diff --git a/CPFTreasury/build.gradle b/CPFTreasury/build.gradle index 54f39052..cbfe0f77 100644 --- a/CPFTreasury/build.gradle +++ b/CPFTreasury/build.gradle @@ -1,4 +1,4 @@ -version = '0.9.1' +version = '1.2.0' dependencies { compileOnly 'foundation.icon:javaee-api:0.9.1' 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 97bc759c..abbbe140 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 @@ -29,6 +29,7 @@ public class CPFTreasury extends SetterGetter implements CPFTreasuryInterface { 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 VarDB treasuryFundbnUSD = Context.newVarDB(TREASURY_FUND_BNUSD, BigInteger.class); private final VarDB swapState = Context.newVarDB(SWAP_STATE, Integer.class); @@ -45,7 +46,6 @@ public CPFTreasury() { swapState.set(SwapReset); swapFlag.set(false); } - oraclePerDiff.set(3); } private boolean proposalExists(String ipfsKey) { @@ -61,21 +61,21 @@ public String name() { @Override @External - public void setMaximumTreasuryFundIcx(BigInteger _value) { + public void setMaximumTreasuryFundIcx(BigInteger value) { validateAdmins(); - treasuryFund.set(_value); + treasuryFund.set(value); } /** * Set the maximum Treasury fund. Default 1M in bnUSD * - * @param _value: value in loop + * @param value: value in loop */ @Override @External - public void setMaximumTreasuryFundBnusd(BigInteger _value) { + public void setMaximumTreasuryFundBnusd(BigInteger value) { validateAdmins(); - treasuryFundbnUSD.set(_value); + treasuryFundbnUSD.set(value); } @External @@ -101,21 +101,37 @@ private void burn(BigInteger amount) { */ @Override @External(readonly = true) - public Map get_total_funds() { + public Map getTotalFunds() { return Map.of(ICX, Context.getBalance(Context.getAddress()), - bnUSD, getTotalFundBNUSD()); + bnUSD, getBNUSDAvailableBalance()); } - private BigInteger getTotalFundBNUSD() { - return (BigInteger) Context.call(balancedDollar.get(), "balanceOf", Context.getAddress()); + @External(readonly = true) + public BigInteger getBNUSDAvailableBalance() { + return getTotalFundBNUSD().get(AVAILABLE_BALANCE); + } + + @External(readonly = true) + public BigInteger getEmergencyFund() { + return getTotalFundBNUSD().get(EMERGENCY_FUND); + } + + + 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); } @Override @External(readonly = true) - public Map get_remaining_swap_amount() { + public Map getRemainingSwapAmount() { BigInteger maxCap = treasuryFundbnUSD.get(); - return Map.of("maxCap", maxCap, - "remainingToSwap", maxCap.subtract(getTotalFundBNUSD())); + return Map.of(MAX_CAP, maxCap, + REMAINING_TO_SWAP, maxCap.subtract(getBNUSDAvailableBalance())); } private void returnFundAmount(Address address, BigInteger value) { @@ -126,70 +142,70 @@ private void returnFundAmount(Address address, BigInteger value) { @Override @External - public void transfer_proposal_fund_to_cps_treasury(String _ipfs_key, int _total_installment_count, - Address _sponsor_address, Address _contributor_address, - String token_flag, BigInteger _total_budget) { + public void transferProposalFundToCpsTreasury(String ipfsKey, int projectDuration, + Address sponsorAddress, Address contributorAddress, + String tokenFlag, BigInteger totalBudget) { validateCpsScore(); - Context.require(!proposalExists(_ipfs_key), TAG + ": Project already exists. Invalid IPFS Hash"); - Context.require(token_flag.equals(bnUSD), TAG + ": " + token_flag + " is not supported. Only " + bnUSD + " token available."); - BigInteger sponsorReward = _total_budget.multiply(BigInteger.TWO).divide(BigInteger.valueOf(100)); - BigInteger totalTransfer = _total_budget.add(sponsorReward); + 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."); + BigInteger sponsorReward = totalBudget.multiply(BigInteger.TWO).divide(BigInteger.valueOf(100)); + BigInteger totalTransfer = totalBudget.add(sponsorReward); Address balancedDollar = CPFTreasury.balancedDollar.get(); BigInteger bnUSDBalance = Context.call(BigInteger.class, balancedDollar, "balanceOf", Context.getAddress()); Context.require(totalTransfer.compareTo(bnUSDBalance) < 0, TAG + ": Not enough fund " + bnUSDBalance + " token available"); - proposalsKeys.add(_ipfs_key); - proposalBudgets.set(_ipfs_key, totalTransfer); + proposalsKeys.add(ipfsKey); + proposalBudgets.set(ipfsKey, totalTransfer); JsonObject depositProposal = new JsonObject(); - depositProposal.add(METHOD, "deposit_proposal_fund"); + depositProposal.add(METHOD, "depositProposalFund"); JsonObject params = new JsonObject(); - params.add("ipfs_hash", _ipfs_key); - params.add("project_duration", _total_installment_count); - params.add("sponsor_address", _sponsor_address.toString()); - params.add("contributor_address", _contributor_address.toString()); - params.add("total_budget", _total_budget.toString(16)); - params.add("sponsor_reward", sponsorReward.toString(16)); - params.add("token", token_flag); + params.add(PROJECT_IPFS_HASH, ipfsKey); + params.add(PROJECT_DURATION, projectDuration); + params.add(SPONSOR_ADDRESS, sponsorAddress.toString()); + params.add(CONTRIBUTOR_ADDRESS, contributorAddress.toString()); + params.add(PROJECT_TOTAL_BUDGET, totalBudget.toString(16)); + params.add(SPONSOR_REWARD, sponsorReward.toString(16)); + params.add(TOKEN, tokenFlag); depositProposal.add(PARAMS, params); Context.call(balancedDollar, TRANSFER, cpsTreasuryScore.get(), totalTransfer, depositProposal.toString().getBytes()); - ProposalFundTransferred(_ipfs_key, "Successfully transferred " + totalTransfer + " " + token_flag + " to CPS Treasury " + cpsTreasuryScore.get()); + ProposalFundTransferred(ipfsKey, "Successfully transferred " + totalTransfer + " " + tokenFlag + " to CPS Treasury " + cpsTreasuryScore.get()); } @Override @External - public void update_proposal_fund(String _ipfs_key, @Optional String _flag, @Optional BigInteger _added_budget, - @Optional int _total_installment_count) { + public void updateProposalFund(String ipfsKey, @Optional String flag, @Optional BigInteger addedBudget, + @Optional int totalInstallmentCount) { validateCpsScore(); - Context.require(proposalExists(_ipfs_key), TAG + ": IPFS hash does not exist."); - Context.require(_flag != null && _flag.equals(bnUSD), TAG + ": Unsupported token. " + _flag); + Context.require(proposalExists(ipfsKey), TAG + ": IPFS hash does not exist."); + Context.require(flag != null && flag.equals(bnUSD), TAG + ": Unsupported token. " + flag); - if (_added_budget == null) { - _added_budget = BigInteger.ZERO; + if (addedBudget == null) { + addedBudget = BigInteger.ZERO; } - BigInteger sponsorReward = _added_budget.multiply(BigInteger.TWO).divide(BigInteger.valueOf(100)); - BigInteger totalTransfer = _added_budget.add(sponsorReward); + BigInteger sponsorReward = addedBudget.multiply(BigInteger.TWO).divide(BigInteger.valueOf(100)); + BigInteger totalTransfer = addedBudget.add(sponsorReward); - BigInteger proposalBudget = proposalBudgets.getOrDefault(_ipfs_key, BigInteger.ZERO); - proposalBudgets.set(_ipfs_key, proposalBudget.add(totalTransfer)); - BigInteger bnUSDFund = get_total_funds().get(bnUSD); + BigInteger proposalBudget = proposalBudgets.getOrDefault(ipfsKey, BigInteger.ZERO); + proposalBudgets.set(ipfsKey, proposalBudget.add(totalTransfer)); + BigInteger bnUSDFund = getTotalFunds().get(bnUSD); Context.require(totalTransfer.compareTo(bnUSDFund) <= 0, TAG + ": Not enough " + totalTransfer + " BNUSD on treasury"); JsonObject budgetAdjustmentData = new JsonObject(); - budgetAdjustmentData.add(METHOD, "budget_adjustment"); + budgetAdjustmentData.add(METHOD, "budgetAdjustment"); JsonObject params = new JsonObject(); - params.add("_ipfs_key", _ipfs_key); - params.add("_added_budget", _added_budget.toString(16)); + params.add("_ipfs_key", ipfsKey); + params.add("_added_budget", addedBudget.toString(16)); params.add("_added_sponsor_reward", sponsorReward.toString(16)); - params.add("_added_installment_count", _total_installment_count); + params.add("_added_installment_count", totalInstallmentCount); budgetAdjustmentData.add(PARAMS, params); Context.call(balancedDollar.get(), TRANSFER, cpsTreasuryScore.get(), totalTransfer, budgetAdjustmentData.toString().getBytes()); - ProposalFundTransferred(_ipfs_key, "Successfully transferred " + totalTransfer + " " + bnUSD + " to CPS Treasury"); + ProposalFundTransferred(ipfsKey, "Successfully transferred " + totalTransfer + " " + bnUSD + " to CPS Treasury"); } private void disqualifyProposalFund(String ipfsKey, BigInteger value) { @@ -205,13 +221,13 @@ private void disqualifyProposalFund(String ipfsKey, BigInteger value) { @Override @External @Payable - public void add_fund() { + public void addFund() { burnExtraFund(); FundReceived(Context.getCaller(), "Treasury fund " + Context.getValue() + " " + ICX + " received."); } private void burnExtraFund() { - Map amounts = get_total_funds(); + Map amounts = getTotalFunds(); BigInteger icxAmount = amounts.get(ICX); BigInteger bnUSDAmount = amounts.get(bnUSD); BigInteger extraAmountIcx = icxAmount.subtract(treasuryFund.get()); @@ -284,10 +300,10 @@ public BigInteger getOraclePrice() { } @External - public void setSwapLimitAmount(BigInteger _value) { + public void setSwapLimitAmount(BigInteger value) { validateAdmins(); - Context.require(_value.compareTo(BigInteger.ZERO) > 0, TAG + ": Swap limit amount should be greater than 0"); - swapLimitAmount.set(_value); + Context.require(value.compareTo(BigInteger.ZERO) > 0, TAG + ": Swap limit amount should be greater than 0"); + swapLimitAmount.set(value); } @@ -297,28 +313,49 @@ public BigInteger getSwapLimitAmount() { } + @External + public void allocateEmergencyFund(BigInteger value) { + validateAdmins(); + Context.require(value.compareTo(BigInteger.ZERO) > 0, TAG + ": Emergency Fund amount should be greater than 0"); + emergencyFund.set(value); + + } + + @External + public void withdrawFromEmergencyFund(BigInteger value, Address address, String purpose) { + validateAdmins(); + Context.require(value.compareTo(BigInteger.ZERO) > 0, TAG + ": Emergency Fund amount should be greater than 0"); + BigInteger emergencyFund = this.emergencyFund.getOrDefault(BigInteger.ZERO); + Context.require(emergencyFund.compareTo(value) >= 0, TAG + ": Request amount is greater than Available Emergency Fund"); + this.emergencyFund.set(emergencyFund.subtract(value)); + Address balancedDollar = CPFTreasury.balancedDollar.get(); + + Context.call(balancedDollar, TRANSFER, address, value, "".getBytes()); + EmergencyFundTransferred(address, value,purpose); + } + @Override @External - public void swap_tokens(int _count) { + public void swapTokens(int count) { validateCpsScore(); BigInteger sicxICXPrice = (BigInteger) Context.call(dexScore.get(), "getPrice", sICXICXPoolID); BigInteger sicxBnusdPrice = (BigInteger) Context.call(dexScore.get(), "getPrice", sICXBNUSDPoolID); BigInteger icxbnUSDPrice = sicxBnusdPrice.multiply(EXA).divide(sicxICXPrice); - BigInteger bnUSDRemainingToSwap = get_remaining_swap_amount().get("remainingToSwap"); - if (bnUSDRemainingToSwap.compareTo(BigInteger.TEN.multiply(EXA)) < 0 || _count == 0) { + BigInteger bnUSDRemainingToSwap = getRemainingSwapAmount().get(REMAINING_TO_SWAP); + if (bnUSDRemainingToSwap.compareTo(BigInteger.TEN.multiply(EXA)) < 0 || count == 0) { swapState.set(SwapCompleted); swapCount.set(SwapReset); } else { int swapState = this.swapState.getOrDefault(0); if (swapState == SwapContinue) { int swapCountValue = swapCount.getOrDefault(0); - int count = _count - swapCountValue; - if (count == 0) { + int _count = count - swapCountValue; + if (_count == 0) { this.swapState.set(SwapCompleted); swapCount.set(SwapReset); } else { - BigInteger remainingICXToSwap = bnUSDRemainingToSwap.multiply(EXA).divide(icxbnUSDPrice.multiply(BigInteger.valueOf(count))); + BigInteger remainingICXToSwap = bnUSDRemainingToSwap.multiply(EXA).divide(icxbnUSDPrice.multiply(BigInteger.valueOf(_count))); BigInteger icxBalance = Context.getBalance(Context.getAddress()); swapCount.set(swapCountValue + 1); if (remainingICXToSwap.compareTo(icxBalance) > 0) { @@ -335,13 +372,13 @@ public void swap_tokens(int _count) { @Override @External(readonly = true) - public Map get_swap_state_status() { - return Map.of("state", swapState.getOrDefault(0), "count", swapCount.getOrDefault(0)); + public Map getSwapStateStatus() { + return Map.of(STATE, swapState.getOrDefault(0), COUNT, swapCount.getOrDefault(0)); } @Override @External - public void reset_swap_state() { + public void resetSwapState() { Address cpsScoreAddress = cpsScore.get(); Address caller = Context.getCaller(); @@ -352,41 +389,41 @@ public void reset_swap_state() { } @External - public void setOraclePercentageDifference(int _value) { + public void setOraclePercentageDifference(int value) { validateAdmins(); - oraclePerDiff.set(_value); + oraclePerDiff.set(value); } @Override @External(readonly = true) - public Map get_proposal_details(@Optional int _start_index, @Optional int _end_index) { - if (_end_index == 0) { - _end_index = 20; + public Map getProposalDetails(@Optional int startIndex, @Optional int endIndex) { + if (endIndex == 0) { + endIndex = 20; } List> proposalsList = new ArrayList<>(); - if ((_end_index - _start_index) > 50) { + if ((endIndex - startIndex) > 50) { Context.revert(TAG + ": Page Length cannot be greater than 50"); } int count = proposalsKeys.size(); - if (_start_index > count) { + if (startIndex > count) { Context.revert(TAG + ": Start index can't be higher than total count."); } - if (_start_index < 0) { - _start_index = 0; + if (startIndex < 0) { + startIndex = 0; } - if (_end_index > count) { - _end_index = count; + if (endIndex > count) { + endIndex = count; } - for (int i = _start_index; i < _end_index; i++) { + for (int i = startIndex; i < endIndex; i++) { String proposalHash = proposalsKeys.get(i); Map proposalDetails = Map.of(TOTAL_BUDGET, proposalBudgets.getOrDefault(proposalHash, BigInteger.ZERO).toString(), IPFS_HASH, proposalHash); proposalsList.add(proposalDetails); } - return Map.of("data", proposalsList, "count", count); + return Map.of(DATA, proposalsList, COUNT, count); } @Override @@ -415,16 +452,16 @@ public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { JsonObject transferData = Json.parse(unpacked_data).asObject(); if (_from.equals(cpsScore.get())) { - if (transferData.get(METHOD).asString().equals("return_fund_amount")) { - Address _sponsor_address = Address.fromString(transferData.get(PARAMS).asObject().get("sponsor_address").asString()); + if (transferData.get(METHOD).asString().equals("returnFundAmount")) { + Address _sponsor_address = Address.fromString(transferData.get(PARAMS).asObject().get(SPONSOR_ADDRESS).asString()); returnFundAmount(_sponsor_address, _value); - } else if (transferData.get(METHOD).asString().equals("burn_amount")) { + } else if (transferData.get(METHOD).asString().equals("burnAmount")) { swapTokens(caller, sICX, _value); } else { Context.revert(TAG + ": Not supported method " + transferData.get(METHOD).asString()); } } else if (_from.equals(cpsTreasuryScore.get())) { - if (transferData.get(METHOD).asString().equals("disqualify_project")) { + if (transferData.get(METHOD).asString().equals("disqualifyProject")) { String ipfs_key = transferData.get(PARAMS).asObject().get("ipfs_key").asString(); disqualifyProposalFund(ipfs_key, _value); } else { @@ -442,8 +479,23 @@ public void fallback() { if (Context.getCaller().equals(dexScore.get())) { burn(Context.getValue()); } else { - Context.revert(TAG + ": Please send fund using add_fund()."); + Context.revert(TAG + ": Please send fund using addFund()."); + } + } + + @External + public void migrateOldHashToNewHash(String oldHash, String newHash){ + validateCpsScore(); + int size = proposalsKeys.size(); + for (int i = 0; i < size; i++) { + if (proposalsKeys.get(i).equals(oldHash)) { + proposalsKeys.set(i, newHash); + } } + + BigInteger totalBudget = proposalBudgets.get(oldHash); + proposalBudgets.set(oldHash,null); + proposalBudgets.set(newHash,totalBudget); } @@ -467,4 +519,8 @@ public void ProposalDisqualified(String _ipfs_key, String note) { @EventLog(indexed = 1) public void FundReceived(Address _sponsor_address, String note) { } + + @EventLog(indexed = 1) + public void EmergencyFundTransferred(Address _address, BigInteger _value, String _purpose) { + } } 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 d9eeee00..a440ebdb 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 @@ -16,6 +16,8 @@ public class Constants { public static final String PROPOSAL_BUDGETS = "_proposals_budgets"; 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 AVAILABLE_BALANCE = "availableBalance"; public static final String TREASURY_FUND_BNUSD = "treasury_fund_bnusd"; public static final String CPS_TREASURY_SCORE = "_cps_treasury_score"; @@ -27,12 +29,24 @@ public class Constants { public static final String SICX_SCORE = "sicx_score"; public static final String ROUTER_SCORE = "router_score"; public static final String ORACLE_ADDRESS = "oracle_address"; - + public static final String BNUSD_BALANCE = "bnusdBalance"; public static final String SWAP_STATE = "swap_state"; public static final String SWAP_COUNT = "swap_count"; public static final String SWAP_LIMIT_AMOUNT = "swap_limit_amount"; public static final String ORACLE_PERCENTAGE_DIFF = "oracle_percentage_diff"; public static final String SWAP_FLAG = "swap_flag"; + public static final String MAX_CAP = "maxCap"; + public static final String REMAINING_TO_SWAP = "remainingToSwap"; + public static final String PROJECT_IPFS_HASH = "ipfs_hash"; + public static final String PROJECT_DURATION = "project_duration"; + public static final String SPONSOR_ADDRESS = "sponsor_address"; + public static final String CONTRIBUTOR_ADDRESS = "contributor_address"; + public static final String PROJECT_TOTAL_BUDGET = "total_budget"; + public static final String SPONSOR_REWARD = "sponsor_reward"; + public static final String TOKEN = "token"; + public static final String COUNT = "count"; + public static final String DATA = "data"; + public static final String STATE = "state"; public static final Address SYSTEM_ADDRESS = Address.fromString("cx0000000000000000000000000000000000000000"); public static final int sICXICXPoolID = 1; 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 4dbe1eca..41808227 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,18 +1,23 @@ package community.icon.cps.score.cpftreasury; import score.Address; +import score.Context; import score.annotation.External; +import java.math.BigInteger; + +import static community.icon.cps.score.cpftreasury.Validations.validateGovernanceContract; + public class SetterGetter { /** * Sets the cps score address. Only owner can set the method * - * @param _score: Score address of cps score + * @param score: Score address of cps score */ @External - public void setCpsScore(Address _score) { - Validations.validateAdminScore(_score); - CPFTreasury.cpsScore.set(_score); + public void setCpsScore(Address score) { + Validations.validateAdminScore(score); + CPFTreasury.cpsScore.set(score); } /** @@ -28,12 +33,12 @@ public Address getCpsScore() { /** * Sets the cps treasury score address. Only cps admins can set the method * - * @param _score: Score address of cps treasury score + * @param score: Score address of cps treasury score */ @External - public void setCpsTreasuryScore(Address _score) { - Validations.validateAdminScore(_score); - CPFTreasury.cpsTreasuryScore.set(_score); + public void setCpsTreasuryScore(Address score) { + Validations.validateAdminScore(score); + CPFTreasury.cpsTreasuryScore.set(score); } /** @@ -49,12 +54,12 @@ public Address getCpsTreasuryScore() { /** * Sets the bnUSD score address. Only cps admins can set the method * - * @param _score: Score address of bnUSD score + * @param score: Score address of bnUSD score */ @External - public void setBnUSDScore(Address _score) { - Validations.validateAdminScore(_score); - CPFTreasury.balancedDollar.set(_score); + public void setBnUSDScore(Address score) { + Validations.validateAdminScore(score); + CPFTreasury.balancedDollar.set(score); } /** @@ -70,12 +75,12 @@ public Address getBnUSDScore() { /** * Sets the sicx score address. Only cps admins can set the method * - * @param _score: Score address of sicx score + * @param score: Score address of sicx score */ @External - public void setSicxScore(Address _score) { - Validations.validateAdminScore(_score); - CPFTreasury.sICXScore.set(_score); + public void setSicxScore(Address score) { + Validations.validateAdminScore(score); + CPFTreasury.sICXScore.set(score); } /** @@ -91,12 +96,12 @@ public Address getSicxScore() { /** * Sets the dex score address. Only owner can set the method * - * @param _score: Score address of dex score + * @param score: Score address of dex score */ @External - public void setDexScore(Address _score) { - Validations.validateAdminScore(_score); - CPFTreasury.dexScore.set(_score); + public void setDexScore(Address score) { + Validations.validateAdminScore(score); + CPFTreasury.dexScore.set(score); } /** @@ -112,12 +117,12 @@ public Address getDexScore() { /** * Sets the router score address. Only owner can set the method * - * @param _score: Score address of router score + * @param score: Score address of router score */ @External - public void setRouterScore(Address _score) { - Validations.validateAdminScore(_score); - CPFTreasury.routerScore.set(_score); + public void setRouterScore(Address score) { + Validations.validateAdminScore(score); + CPFTreasury.routerScore.set(score); } /** @@ -131,9 +136,9 @@ public Address getRouterScore() { } @External - public void setOracleAddress(Address _score) { - Validations.validateAdminScore(_score); - CPFTreasury.oracleAddress.set(_score); + public void setOracleAddress(Address score) { + Validations.validateAdminScore(score); + CPFTreasury.oracleAddress.set(score); } /** @@ -146,4 +151,22 @@ public Address getOracleAddress() { return CPFTreasury.oracleAddress.get(); } + @External + public void setSponsorBondPercentage(BigInteger bondValue) { + validateGovernanceContract(); + Context.call( getCpsScore(), "setSponsorBondPercentage",bondValue); + } + + @External + public void setPeriod(BigInteger applicationPeriod) { + validateGovernanceContract(); + Context.call(getCpsScore(), "setPeriod",applicationPeriod); + } + + @External + public void setOnsetPayment(BigInteger paymentPercentage) { + validateGovernanceContract(); + Context.call(getCpsTreasuryScore(), "setOnsetPayment",paymentPercentage); + } + } 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 77d39709..d3defdab 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,6 +3,7 @@ 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 { @@ -12,6 +13,12 @@ public static void validateAdmins() { } + public static void validateGovernanceContract() { + Context.require(Context.getCaller().equals(SYSTEM_ADDRESS), + TAG + ": Only Admins can call this method"); + + } + public static void validateAdminScore(Address _score) { validateAdmins(); 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 33c537dd..86629044 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 @@ -17,7 +17,6 @@ import score.VarDB; import java.math.BigInteger; -import java.security.SecureRandom; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -27,19 +26,14 @@ import static org.mockito.Mockito.times; public class CPFTTreasuryTest extends TestBase { - private static final Address ZERO_ADDRESS = new Address(new byte[Address.LENGTH]); - private static final Address treasury_score = new Address(new byte[Address.LENGTH]); private static final Address score_address = Address.fromString("cx0000000000000000000000000000000000000000"); private static final Address sicxScore = Address.fromString("cx0000000000000000000000000000000000000001"); private static final Address bnUSDScore = Address.fromString("cx0000000000000000000000000000000000000002"); private static final Address dexScore = Address.fromString("cx0000000000000000000000000000000000000003"); - private static final Address oracleAddress = Address.fromString("cx0000000000000000000000000000000000000005"); private static final Address cpsTreasuryScore = Address.fromString("cx0000000000000000000000000000000000000004"); private static final String name = "CPF_TREASURY"; - private static final String symbol = "CPF_TREASURY"; public static final String TAG = "CPF_TREASURY"; - CPFTreasury cpfTreasury; private static final BigInteger MULTIPLIER = new BigInteger("1000000000000000000"); @@ -49,11 +43,8 @@ public class CPFTTreasuryTest extends TestBase { private static final Account testing_account2 = sm.createAccount(); private Score tokenScore; - private final SecureRandom secureRandom = new SecureRandom(); DictDB proposalBudgets = Mockito.mock(DictDB.class); - VarDB swapState = Mockito.mock(VarDB.class); - VarDB swapCount = Mockito.mock(VarDB.class); VarDB swapFlag = Mockito.mock(VarDB.class); @BeforeEach @@ -193,11 +184,15 @@ void setRouterScoreExceptions(Account address, Address _score) { } } -// @Test -// void setCPSScoreNotAdmin() { -// Executable setCPSScoreNotOwner = () -> setCPSScoreExceptions(testing_account, score_address); -// expectErrorMessage(setCPSScoreNotOwner, TAG + ": Only owner can call this method"); -// } + @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); + theMock.verify(() -> Context.require(false,TAG + ": Only Admins can call this method")); + } + } // // @Test // void setCPSTreasuryScoreNotAdmin() { @@ -230,7 +225,7 @@ void setRouterScoreExceptions(Account address, Address _score) { // } @Test - void transferProposalFundToCPSTreasury() { + void transfer_proposal_fund_to_cps_treasury() { setBNUSDScoreMethod(bnUSDScore); setCPSTreasuryScoreMetod(cpsTreasuryScore); @@ -243,20 +238,21 @@ void transferProposalFundToCPSTreasury() { Mockito.when(proposalBudgets.getOrDefault("Proposal 1", null)).thenReturn(BigInteger.valueOf(10)); theMock.when(() -> Context.getAddress()).thenReturn(tokenScore.getAddress()); theMock.when(() -> Context.call(BigInteger.class, bnUSDScore, "balanceOf", tokenScore.getAddress())).thenReturn(BigInteger.valueOf(1000).multiply(MULTIPLIER)); - tokenScore.invoke(owner, "transfer_proposal_fund_to_cps_treasury", "Proposal 1", 2, testing_account.getAddress(), testing_account2.getAddress(), "bnUSD", BigInteger.valueOf(100).multiply(MULTIPLIER)); + tokenScore.invoke(owner, "transferProposalFundToCpsTreasury", "Proposal 1",3, testing_account.getAddress(), testing_account2.getAddress(), "bnUSD", BigInteger.valueOf(100).multiply(MULTIPLIER)); JsonObject depositProposal = new JsonObject(); - depositProposal.add("method", "deposit_proposal_fund"); + depositProposal.add("method", "depositProposalFund"); JsonObject params = new JsonObject(); params.add("ipfs_hash", "Proposal 1"); - params.add("project_duration", 2); + params.add("project_duration", 3); params.add("sponsor_address", testing_account.getAddress().toString()); params.add("contributor_address", testing_account2.getAddress().toString()); params.add("total_budget", BigInteger.valueOf(100).multiply(MULTIPLIER).toString(16)); params.add("sponsor_reward", BigInteger.valueOf(2).multiply(MULTIPLIER).toString(16)); params.add("token", "bnUSD"); depositProposal.add("params", params); - theMock.verify(() -> Context.call(bnUSDScore, "transfer", cpsTreasuryScore, BigInteger.valueOf(102).multiply(MULTIPLIER), depositProposal.toString().getBytes()), times(1)); + theMock.verify(() -> Context.call(bnUSDScore, "transfer", + cpsTreasuryScore, BigInteger.valueOf(102).multiply(MULTIPLIER), depositProposal.toString().getBytes()), times(1)); } catch (Exception e) { throw e; } @@ -272,8 +268,8 @@ void updateProposalFund() { theMock.when(() -> Context.getCaller()).thenReturn(score_address); theMock.when(() -> Context.getBalance(Context.getAddress())).thenReturn(BigInteger.valueOf(1000).multiply(MULTIPLIER)); theMock.when(() -> Context.call(balancedDollar.get(), "balanceOf", Context.getAddress())).thenReturn(BigInteger.valueOf(1000).multiply(MULTIPLIER)); - tokenScore.invoke(owner, "update_proposal_fund", "Proposal 1", "bnUSD", BigInteger.valueOf(100).multiply(MULTIPLIER), 1); - Map details = (Map) tokenScore.call("get_proposal_details", 0, 5); + tokenScore.invoke(owner, "updateProposalFund", "Proposal 1", "bnUSD", BigInteger.valueOf(100).multiply(MULTIPLIER), 1); + Map details = (Map) tokenScore.call("getProposalDetails", 0, 5); List> proposalsList = new ArrayList<>(); proposalsList.add(Map.of("_ipfs_hash", "Proposal 1", "_budget_transfer", BigInteger.valueOf(204).multiply(MULTIPLIER).toString())); proposalsList.add(Map.of("_ipfs_hash", "Proposal 2", "_budget_transfer", BigInteger.valueOf(1122).multiply(MULTIPLIER).divide(BigInteger.TEN).toString())); @@ -281,7 +277,7 @@ void updateProposalFund() { assertEquals(details, expectedDetails); JsonObject budgetAdjustmentData = new JsonObject(); - budgetAdjustmentData.add("method", "budget_adjustment"); + budgetAdjustmentData.add("method", "budgetAdjustment"); JsonObject params = new JsonObject(); params.add("_ipfs_key", "Proposal 1"); params.add("_added_budget", BigInteger.valueOf(100).multiply(MULTIPLIER).toString(16)); @@ -343,8 +339,8 @@ void swapTokensRemainingToSwapLessThanTen() { theMock.when(() -> Context.call(dexScore.get(), "getPrice", 2)).thenReturn(BigInteger.valueOf(8).multiply(MULTIPLIER).divide(BigInteger.TEN)); theMock.when(() -> Context.call(balancedDollar.get(), "balanceOf", Context.getAddress())).thenReturn(BigInteger.valueOf(1995).multiply(MULTIPLIER)); theMock.when(() -> Context.getBalance(Context.getAddress())).thenReturn(BigInteger.valueOf(10000).multiply(MULTIPLIER)); - tokenScore.invoke(owner, "swap_tokens", 10); - assertEquals(tokenScore.call("get_swap_state_status"), Map.of("count", 0, "state", 1)); + tokenScore.invoke(owner, "swapTokens", 10); + assertEquals(tokenScore.call("getSwapStateStatus"), Map.of("count", 0, "state", 1)); } } @@ -361,8 +357,8 @@ void swapTokensRemainingToSwapMoreThanTen() { theMock.when(() -> Context.call(dexScore.get(), "getPrice", 2)).thenReturn(BigInteger.valueOf(8).multiply(MULTIPLIER).divide(BigInteger.TEN)); theMock.when(() -> Context.call(balancedDollar.get(), "balanceOf", Context.getAddress())).thenReturn(BigInteger.valueOf(1000).multiply(MULTIPLIER)); theMock.when(() -> Context.getBalance(Context.getAddress())).thenReturn(BigInteger.valueOf(2000).multiply(MULTIPLIER)); - tokenScore.invoke(owner, "swap_tokens", 10); - assertEquals(tokenScore.call("get_swap_state_status"), Map.of("count", 1, "state", 0)); + tokenScore.invoke(owner, "swapTokens", 10); + assertEquals(tokenScore.call("getSwapStateStatus"), Map.of("count", 1, "state", 0)); } } @@ -379,8 +375,8 @@ void swapTokensRemainingToSwapMoreThanTenCountIsZeroFromCPSScore() { theMock.when(() -> Context.call(dexScore.get(), "getPrice", 2)).thenReturn(BigInteger.valueOf(8).multiply(MULTIPLIER).divide(BigInteger.TEN)); theMock.when(() -> Context.call(balancedDollar.get(), "balanceOf", Context.getAddress())).thenReturn(BigInteger.valueOf(1000).multiply(MULTIPLIER)); theMock.when(() -> Context.getBalance(Context.getAddress())).thenReturn(BigInteger.valueOf(2000).multiply(MULTIPLIER)); - tokenScore.invoke(owner, "swap_tokens", 0); - assertEquals(tokenScore.call("get_swap_state_status"), Map.of("count", 0, "state", 1)); + tokenScore.invoke(owner, "swapTokens", 0); + assertEquals(tokenScore.call("getSwapStateStatus"), Map.of("count", 0, "state", 1)); } } @@ -393,8 +389,8 @@ void resetSwapState() { try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { theMock.when(() -> Context.getCaller()).thenReturn(testing_account.getAddress()); theMock.when(() -> Context.call(score_address, "isAdmin", Context.getCaller())).thenReturn(true); - tokenScore.invoke(owner, "reset_swap_state"); - assertEquals(tokenScore.call("get_swap_state_status"), Map.of("state", 0, "count", 0)); + tokenScore.invoke(owner, "resetSwapState"); + assertEquals(tokenScore.call("getSwapStateStatus"), Map.of("state", 0, "count", 0)); } } @@ -404,8 +400,8 @@ private void transferProposalFundMethod() { try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { theMock.when(() -> Context.getCaller()).thenReturn(score_address); theMock.when(() -> Context.call(BigInteger.class, balancedDollar.get(), "balanceOf", Context.getAddress())).thenReturn(BigInteger.valueOf(1000).multiply(MULTIPLIER)); - tokenScore.invoke(owner, "transfer_proposal_fund_to_cps_treasury", "Proposal 1", 2, testing_account.getAddress(), testing_account2.getAddress(), "bnUSD", BigInteger.valueOf(100).multiply(MULTIPLIER)); - tokenScore.invoke(owner, "transfer_proposal_fund_to_cps_treasury", "Proposal 2", 2, testing_account.getAddress(), testing_account2.getAddress(), "bnUSD", BigInteger.valueOf(110).multiply(MULTIPLIER)); + tokenScore.invoke(owner, "transferProposalFundToCpsTreasury", "Proposal 1", 3, testing_account.getAddress(), testing_account2.getAddress(), "bnUSD", BigInteger.valueOf(100).multiply(MULTIPLIER)); + tokenScore.invoke(owner, "transferProposalFundToCpsTreasury", "Proposal 2", 3, testing_account.getAddress(), testing_account2.getAddress(), "bnUSD", BigInteger.valueOf(110).multiply(MULTIPLIER)); } @@ -423,7 +419,7 @@ void addFundExtraICX() { try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { theMock.when(() -> Context.getBalance(Context.getAddress())).thenReturn(BigInteger.valueOf(2001).multiply(MULTIPLIER)); theMock.when(() -> Context.call(bnUSDScore, "balanceOf", Context.getAddress())).thenReturn(BigInteger.valueOf(2000).multiply(MULTIPLIER)); - tokenScore.invoke(owner, "add_fund"); + tokenScore.invoke(owner, "addFund"); theMock.verify(() -> Context.call(BigInteger.valueOf(1).multiply(MULTIPLIER), score_address, "burn"), times(1)); } @@ -445,7 +441,7 @@ private void addFundMethod() { try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { theMock.when(() -> Context.getBalance(Context.getAddress())).thenReturn(BigInteger.valueOf(2000).multiply(MULTIPLIER)); theMock.when(() -> Context.call(bnUSDScore, "balanceOf", Context.getAddress())).thenReturn(BigInteger.valueOf(2001).multiply(MULTIPLIER)); - tokenScore.invoke(owner, "add_fund"); + tokenScore.invoke(owner, "addFund"); JsonObject swapData = new JsonObject(); swapData.add("method", "_swap"); JsonObject params = new JsonObject(); @@ -530,7 +526,7 @@ void tokenFallBackFromIsCpsScoreMethodReturnFundAmount() { theMock.when(() -> Context.getBalance(Context.getAddress())).thenReturn(BigInteger.valueOf(2000).multiply(MULTIPLIER)); theMock.when(() -> Context.call(bnUSDScore, "balanceOf", Context.getAddress())).thenReturn(BigInteger.valueOf(2001).multiply(MULTIPLIER)); JsonObject jsonObject = new JsonObject(); - jsonObject.add("method", "return_fund_amount"); + jsonObject.add("method", "returnFundAmount"); JsonObject params = new JsonObject(); params.add("sponsor_address", testing_account.getAddress().toString()); jsonObject.add("params", params); @@ -558,7 +554,7 @@ void tokenFallBackFromIsCpsScoreMethodBurnAmount() { theMock.when(() -> Context.getBalance(Context.getAddress())).thenReturn(BigInteger.valueOf(2000).multiply(MULTIPLIER)); theMock.when(() -> Context.call(bnUSDScore, "balanceOf", Context.getAddress())).thenReturn(BigInteger.valueOf(2001).multiply(MULTIPLIER)); JsonObject jsonObject = new JsonObject(); - jsonObject.add("method", "burn_amount"); + jsonObject.add("method", "burnAmount"); JsonObject params = new JsonObject(); params.add("sponsor_address", testing_account.getAddress().toString()); jsonObject.add("params", params); @@ -584,8 +580,8 @@ void tokenFallBackFromIsCpsTreasuryScore() { try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { theMock.when(() -> Context.getCaller()).thenReturn(score_address); theMock.when(() -> Context.call(BigInteger.class, bnUSDScore, "balanceOf", Context.getAddress())).thenReturn(BigInteger.valueOf(1000).multiply(MULTIPLIER)); - tokenScore.invoke(owner, "transfer_proposal_fund_to_cps_treasury", "Proposal 1", 2, testing_account.getAddress(), testing_account2.getAddress(), "bnUSD", BigInteger.valueOf(100).multiply(MULTIPLIER)); - tokenScore.invoke(owner, "transfer_proposal_fund_to_cps_treasury", "Proposal 2", 2, testing_account.getAddress(), testing_account2.getAddress(), "bnUSD", BigInteger.valueOf(110).multiply(MULTIPLIER)); + tokenScore.invoke(owner, "transferProposalFundToCpsTreasury", "Proposal 1", 3, testing_account.getAddress(), testing_account2.getAddress(), "bnUSD", BigInteger.valueOf(100).multiply(MULTIPLIER)); + tokenScore.invoke(owner, "transferProposalFundToCpsTreasury", "Proposal 2", 3, testing_account.getAddress(), testing_account2.getAddress(), "bnUSD", BigInteger.valueOf(110).multiply(MULTIPLIER)); } try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { @@ -593,7 +589,7 @@ void tokenFallBackFromIsCpsTreasuryScore() { theMock.when(() -> Context.getBalance(Context.getAddress())).thenReturn(BigInteger.valueOf(2000).multiply(MULTIPLIER)); theMock.when(() -> Context.call(bnUSDScore, "balanceOf", Context.getAddress())).thenReturn(BigInteger.valueOf(2001).multiply(MULTIPLIER)); JsonObject jsonObject = new JsonObject(); - jsonObject.add("method", "disqualify_project"); + jsonObject.add("method", "disqualifyProject"); JsonObject params = new JsonObject(); params.add("ipfs_key", "Proposal 1"); jsonObject.add("params", params); @@ -604,7 +600,7 @@ void tokenFallBackFromIsCpsTreasuryScore() { params_.add("toToken", sicxScore.toString()); swapData.add("params", params_); theMock.verify(() -> Context.call(bnUSDScore, "transfer", dexScore, BigInteger.ONE.multiply(MULTIPLIER), swapData.toString().getBytes())); - Map details = (Map) tokenScore.call("get_proposal_details", 0, 5); + Map details = (Map) tokenScore.call("getProposalDetails", 0, 5); List> proposalsList = new ArrayList<>(); proposalsList.add(Map.of("_ipfs_hash", "Proposal 1", "_budget_transfer", BigInteger.valueOf(2).multiply(MULTIPLIER).toString())); proposalsList.add(Map.of("_ipfs_hash", "Proposal 2", "_budget_transfer", BigInteger.valueOf(1122).multiply(MULTIPLIER).divide(BigInteger.TEN).toString())); @@ -649,8 +645,8 @@ void tokenFallBackFromIsCpsTreasuryScoreInvalidMethod() { try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { theMock.when(() -> Context.getCaller()).thenReturn(score_address); theMock.when(() -> Context.call(BigInteger.class, bnUSDScore, "balanceOf", Context.getAddress())).thenReturn(BigInteger.valueOf(1000).multiply(MULTIPLIER)); - tokenScore.invoke(owner, "transfer_proposal_fund_to_cps_treasury", "Proposal 1", 2, testing_account.getAddress(), testing_account2.getAddress(), "bnUSD", BigInteger.valueOf(100).multiply(MULTIPLIER)); - tokenScore.invoke(owner, "transfer_proposal_fund_to_cps_treasury", "Proposal 2", 2, testing_account.getAddress(), testing_account2.getAddress(), "bnUSD", BigInteger.valueOf(110).multiply(MULTIPLIER)); + tokenScore.invoke(owner, "transferProposalFundToCpsTreasury", "Proposal 1", 3, testing_account.getAddress(), testing_account2.getAddress(), "bnUSD", BigInteger.valueOf(100).multiply(MULTIPLIER)); + tokenScore.invoke(owner, "transferProposalFundToCpsTreasury", "Proposal 2", 3, testing_account.getAddress(), testing_account2.getAddress(), "bnUSD", BigInteger.valueOf(110).multiply(MULTIPLIER)); } try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { @@ -685,7 +681,61 @@ void fallbackSenderIsNotDex() { theMock.when(() -> Context.getCaller()).thenReturn(sicxScore); theMock.when(() -> Context.getValue()).thenReturn(BigInteger.valueOf(1000).multiply(MULTIPLIER)); tokenScore.invoke(owner, "fallback"); - theMock.verify(() -> Context.revert(TAG + ": Please send fund using add_fund().")); + theMock.verify(() -> Context.revert(TAG + ": Please send fund using addFund().")); + } + } + + @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"); + assertEquals(true,tokenScore.call("getSwapFlag")); + } + } + + @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)){ + theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true); + tokenScore.invoke(owner,"allocateEmergencyFund",emergencyFund); + + theMock.when(() -> Context.call(balanceDollar.get(), "balanceOf", Context.getAddress())).thenReturn(BigInteger.valueOf(100).multiply(ICX)); + assertEquals(emergencyFund,tokenScore.call("getEmergencyFund")); + } + } + + @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)){ + theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true); + tokenScore.invoke(owner,"withdrawFromEmergencyFund",withdrawAmount,testing_account.getAddress(), "Need fund"); + + theMock.when(() -> Context.call(balanceDollar.get(), "balanceOf", Context.getAddress())).thenReturn(BigInteger.valueOf(100).multiply(ICX)); + assertEquals(BigInteger.valueOf(6).multiply(ICX),tokenScore.call("getEmergencyFund")); + + } + } + + @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); + tokenScore.invoke(owner, "setOraclePercentageDifference",value ); + + assertEquals(value,tokenScore.call("getSlippagePercentage")); + + } } diff --git a/CPSCore/build.gradle b/CPSCore/build.gradle index c8896a42..b5dd43f6 100644 --- a/CPSCore/build.gradle +++ b/CPSCore/build.gradle @@ -1,4 +1,4 @@ -version = '0.9.1' +version = '1.3.3' dependencies { compileOnly 'foundation.icon:javaee-api:0.9.2' @@ -30,7 +30,7 @@ deployJar { lisbon { uri = 'https://lisbon.net.solidwallet.io/api/v3' nid = 0x2 - to = 'cxd82e5f0c1090f55f9b2f727ad35fb3a9e1de95c4' + to = 'cx8e21d3b7a70aeeaca45d4a70c31a6b959f5823bd' } local { uri = 'http://localhost:9082/api/v3' 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 d68c6e56..034c7d36 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 @@ -2,6 +2,7 @@ import com.eclipsesource.json.Json; import com.eclipsesource.json.JsonObject; +import community.icon.cps.score.cpscore.db.MilestoneDb; import community.icon.cps.score.cpscore.db.ProgressReportDataDb; import community.icon.cps.score.cpscore.db.ProposalDataDb; import community.icon.cps.score.cpscore.utils.ArrayDBUtils; @@ -18,6 +19,8 @@ import java.util.List; import java.util.Map; +import static community.icon.cps.score.cpscore.db.MilestoneDb.addDataToMilestoneDb; +import static community.icon.cps.score.cpscore.db.MilestoneDb.getDataFromMilestoneDB; import static community.icon.cps.score.cpscore.db.ProgressReportDataDb.*; import static community.icon.cps.score.cpscore.db.ProposalDataDb.*; import static community.icon.cps.score.cpscore.utils.ArrayDBUtils.*; @@ -38,33 +41,12 @@ public class CPSCore implements CPSCoreInterface { private final ArrayDB
contributors = Context.newArrayDB(CONTRIBUTORS, Address.class); private final ArrayDB
sponsors = Context.newArrayDB(SPONSORS, Address.class); private static final ArrayDB
admins = Context.newArrayDB(ADMINS, Address.class); - private final ArrayDB sponsorPending = Context.newArrayDB(SPONSOR_PENDING, String.class); - private final ArrayDB pending = Context.newArrayDB(PENDING, String.class); - private final ArrayDB active = Context.newArrayDB(ACTIVE, String.class); - private final ArrayDB paused = Context.newArrayDB(PAUSED, String.class); - private final ArrayDB completed = Context.newArrayDB(COMPLETED, String.class); - private final ArrayDB rejected = Context.newArrayDB(REJECTED, String.class); - private final ArrayDB disqualified = Context.newArrayDB(DISQUALIFIED, String.class); - public final Map> proposalStatus = Map.of(SPONSOR_PENDING, sponsorPending, - PENDING, pending, - ACTIVE, active, - PAUSED, paused, - COMPLETED, completed, - REJECTED, rejected, - DISQUALIFIED, disqualified); - - - private final ArrayDB waitingProgressReports = Context.newArrayDB(WAITING, String.class); - private final ArrayDB approvedProgressReports = Context.newArrayDB(APPROVED, String.class); - private final ArrayDB progressRejected = Context.newArrayDB(PROGRESS_REPORT_REJECTED, String.class); - public final Map> progressReportStatus = Map.of(WAITING, waitingProgressReports, - APPROVED, approvedProgressReports, - PROGRESS_REPORT_REJECTED, progressRejected - ); - + public final DictDB period = Context.newDictDB(PERIOD, BigInteger.class); + public final VarDB sponsorBondPercentage = Context.newVarDB(SPONSOR_BOND_PERCENTAGE, BigInteger.class); private final BranchDB> sponsorBondReturn = Context.newBranchDB(SPONSOR_BOND_RETURN, BigInteger.class); private final DictDB delegationSnapshot = Context.newDictDB(DELEGATION_SNAPSHOT, BigInteger.class); private final VarDB maxDelegation = Context.newVarDB(MAX_DELEGATION, BigInteger.class); + private final VarDB totalDelegationSnapshot = Context.newVarDB(TOTAL_DELEGATION_SNAPSHOT, BigInteger.class); private final VarDB proposalFees = Context.newVarDB(PROPOSAL_FEES, BigInteger.class); private final VarDB swapBlockHeight = Context.newVarDB(SWAP_BLOCK_HEIGHT, BigInteger.class); private final VarDB swapCount = Context.newVarDB(SWAP_COUNT, Integer.class); @@ -72,9 +54,14 @@ public class CPSCore implements CPSCoreInterface { private final ArrayDB
priorityVotedPreps = Context.newArrayDB(PRIORITY_VOTED_PREPS, Address.class); private final BranchDB> sponsorProjects = Context.newBranchDB(SPONSOR_PROJECTS, String.class); private final BranchDB> contributorProjects = Context.newBranchDB(CONTRIBUTOR_PROJECTS, String.class); + private static final BigInteger HUNDRED = BigInteger.valueOf(100); - public CPSCore() { - PeriodController periodController = new PeriodController(); + public CPSCore(@Optional BigInteger bondValue, @Optional BigInteger applicationPeriod) { + if (sponsorBondPercentage.get() == null) { + sponsorBondPercentage.set(bondValue); + this.period.set(APPLICATION_PERIOD, applicationPeriod); + this.period.set(VOTING_PERIOD, TOTAL_PERIOD.subtract(applicationPeriod)); + } } @Override @@ -88,22 +75,15 @@ public String proposalPrefix(String proposalKey) { return PROPOSAL_DB_PREFIX + "|" + "|" + proposalKey; } + public String mileStonePrefix(String proposalKey, int id) { + return proposalKey + "|" + "|" + id; + } + @Override public String progressReportPrefix(String progressKey) { return PROGRESS_REPORT_DB_PREFIX + "|" + "|" + progressKey; } - /*** - * Deprecated because JAVA convention will be used in the future versions for method name and parameter name - * i.e. set_cps_treasury_score -> setCpsTreasuryScore and _score -> score - * @param _score: Address of CPS Treasury Score - */ - @Override - @Deprecated(since = "JAVA translation", forRemoval = true) - @External - public void set_cps_treasury_score(Address _score) { - setCpsTreasuryScore(_score); - } @Override @External @@ -113,12 +93,6 @@ public void setCpsTreasuryScore(Address score) { setterGetter.cpsTreasuryScore.set(score); } - @Override - @Deprecated(since = "JAVA translation", forRemoval = true) - @External(readonly = true) - public Address get_cps_treasury_score() { - return getCpsTreasuryScore(); - } @Override @External(readonly = true) @@ -127,12 +101,6 @@ public Address getCpsTreasuryScore() { return setterGetter.cpsTreasuryScore.get(); } - @Override - @Deprecated(since = "JAVA translation", forRemoval = true) - @External - public void set_cpf_treasury_score(Address _score) { - setCpfTreasuryScore(_score); - } @Override @External @@ -142,12 +110,6 @@ public void setCpfTreasuryScore(Address score) { setterGetter.cpfScore.set(score); } - @Override - @Deprecated(since = "JAVA translation", forRemoval = true) - @External(readonly = true) - public Address get_cpf_treasury_score() { - return getCpfTreasuryScore(); - } @Override @External(readonly = true) @@ -173,12 +135,43 @@ public Address getBnusdScore() { return setterGetter.balancedDollar.get(); } - @Deprecated(since = "JAVA translation", forRemoval = true) @External(readonly = true) - public Address get_bnUSD_score() { - return getBnusdScore(); + public BigInteger getSponsorBondPercentage() { + return sponsorBondPercentage.get(); + } + + @External + public void setSponsorBondPercentage(BigInteger bondValue) { + onlyCPFTreasury(); + Context.require(bondValue.compareTo(BigInteger.valueOf(12)) >= 0, TAG + + ": Cannot set bond percentage less than 12%"); + sponsorBondPercentage.set(bondValue); + } + + @External(readonly = true) + public BigInteger getVotingPeriod() { + return period.get(VOTING_PERIOD); } + @External(readonly = true) + public BigInteger getApplicationPeriod() { + return period.get(APPLICATION_PERIOD); + } + + @External + public void setPeriod(BigInteger applicationPeriod) { + onlyCPFTreasury(); + BigInteger votingPeriod = TOTAL_PERIOD.subtract(applicationPeriod); + + Context.require( + (votingPeriod.compareTo(BigInteger.TEN) >= 0), + TAG + ": Voting period must be more than or equal to 10 days"); + + this.period.set(APPLICATION_PERIOD, applicationPeriod); + this.period.set(VOTING_PERIOD, votingPeriod); + } + + private boolean proposalKeyExists(String key) { return proposalsKeyListIndex.get(key) != null; } @@ -192,11 +185,6 @@ public boolean isAdmin(Address address) { return ArrayDBUtils.containsInArrayDb(address, admins); } - @Deprecated - @External - public boolean is_admin(Address _address) { - return isAdmin(_address); - } @Override @External @@ -228,10 +216,6 @@ public boolean getMaintenanceMode() { return setterGetter.maintenance.getOrDefault(false); } - @External(readonly = true) - public boolean get_maintenance_mode() { - return getMaintenanceMode(); - } @Override @Payable @@ -250,8 +234,8 @@ private void burn(BigInteger amount, @Optional Address token) { Address bnUSDScore = setterGetter.balancedDollar.get(); if (token.equals(bnUSDScore)) { JsonObject burnTokens = new JsonObject(); - burnTokens.add("method", "burn_amount"); - callScore(bnUSDScore, "transfer", setterGetter.cpfScore.get(), amount, burnTokens.toString().getBytes()); + burnTokens.add(METHOD, "burnAmount"); + callScore(bnUSDScore, TRANSFER, setterGetter.cpfScore.get(), amount, burnTokens.toString().getBytes()); } else { Context.revert(TAG + ": Not a supported token."); } @@ -285,7 +269,7 @@ public void removeAdmin(Address address) { // change made ArrayDBUtils.removeArrayItem(admins, address); } - + @Override @External public void unregisterPrep() { checkMaintenance(); @@ -305,12 +289,6 @@ public void unregisterPrep() { } @Override - @Deprecated(since = "JAVA translation", forRemoval = true) - @External - public void unregister_prep() { - unregisterPrep(); - } - @External public void registerPrep() { checkMaintenance(); @@ -338,12 +316,6 @@ public void registerPrep() { } - @Override - @Deprecated(since = "JAVA translation", forRemoval = true) - @External - public void register_prep() { - registerPrep(); - } @SuppressWarnings("unchecked") private List> getPrepTerm() { @@ -373,6 +345,10 @@ private BigInteger getStake(Address address) { return (BigInteger) getPRepInfo(address).get("power"); } + private BigInteger getDelegation(Address address) { + return delegationSnapshot.get(address); + } + private void setPreps() { PReps pReps = new PReps(); ArrayDBUtils.clearArrayDb(pReps.validPreps); @@ -380,10 +356,9 @@ private void setPreps() { for (Address prep : prepsList) { if (!ArrayDBUtils.containsInArrayDb(prep, pReps.denylist) && - !ArrayDBUtils.containsInArrayDb(prep, pReps.unregisteredPreps)) { - if (ArrayDBUtils.containsInArrayDb(prep, pReps.registeredPreps)) { - pReps.validPreps.add(prep); - } + !ArrayDBUtils.containsInArrayDb(prep, pReps.unregisteredPreps) && + ArrayDBUtils.containsInArrayDb(prep, pReps.registeredPreps)) { + pReps.validPreps.add(prep); } } @@ -439,17 +414,23 @@ private BigInteger getPenaltyAmount(Address address) { @Override @External(readonly = true) public boolean checkPriorityVoting(Address _prep) { - return ArrayDBUtils.containsInArrayDb(_prep, priorityVotedPreps); + int count = (int) getActiveProposalsList(0).get(COUNT); + if (count > 0) { + return ArrayDBUtils.containsInArrayDb(_prep, priorityVotedPreps); + } + return false; } @Override @External(readonly = true) public List sortPriorityProposals() { - String[] pendingProposals = new String[pending.size()]; - for (int i = 0; i < pending.size(); i++) { - pendingProposals[i] = pending.get(i); + Status status = new Status(); + int size = status.pending.size(); + String[] pendingProposals = new String[size]; + for (int i = 0; i < size; i++) { + pendingProposals[i] = status.pending.get(i); } - mergeSort(pendingProposals, 0, pending.size() - 1, getPriorityVoteResult()); + mergeSort(pendingProposals, 0, size - 1, getPriorityVoteResult()); return arrayToList(pendingProposals); } @@ -457,9 +438,11 @@ public List sortPriorityProposals() { @External(readonly = true) public Map getPriorityVoteResult() { Map priorityVoteResult = new HashMap<>(); + Status status = new Status(); - for (int i = 0; i < pending.size(); i++) { - String prop = pending.get(i); + int size = status.pending.size(); + for (int i = 0; i < size; i++) { + String prop = status.pending.get(i); priorityVoteResult.put(prop, proposalRank.getOrDefault(prop, 0)); } @@ -479,9 +462,10 @@ public void votePriority(String[] _proposals) { priorityVotedPreps.add(caller); int size = _proposals.length; + Status status = new Status(); for (int i = 0; i < size; i++) { String proposal = _proposals[i]; - Context.require(ArrayDBUtils.containsInArrayDb(proposal, pending), + Context.require(ArrayDBUtils.containsInArrayDb(proposal, status.pending), proposal + " not in pending state."); proposalRank.set(proposal, proposalRank.getOrDefault(proposal, 0) + size - i); } @@ -504,13 +488,6 @@ public void setPrepPenaltyAmount(BigInteger[] penalty) { } - @Deprecated(since = "JAVA translation", forRemoval = true) - @External - public void set_prep_penalty_amount(BigInteger[] _penalty) { - setPrepPenaltyAmount(_penalty); - } - - @Override @External public void setInitialBlock() { @@ -521,84 +498,63 @@ public void setInitialBlock() { period.nextBlock.set(BigInteger.valueOf(Context.getBlockHeight()).add(BLOCKS_DAY_COUNT.multiply(DAY_COUNT))); period.periodName.set(APPLICATION_PERIOD); period.previousPeriodName.set("None"); + period.periodCount.set(0); } + @Override @External(readonly = true) public Map loginPrep(Address address) { Map loginData = new HashMap<>(); - List
allPreps = getPrepsAddress(); + PeriodController period = new PeriodController(); + List
allPreps; PReps pReps = new PReps(); + if (period.periodName.get().equals(APPLICATION_PERIOD)) { + allPreps = getPrepsAddress(); + } else { + allPreps = ArrayDBUtils.arrayDBtoList(pReps.validPreps); + } + + loginData.put(IS_PREP, BigInteger.ZERO); + loginData.put(IS_REGISTERED, BigInteger.ZERO); + loginData.put(PAY_PENALTY, BigInteger.ZERO); + loginData.put(VOTING_PREP, BigInteger.ZERO); + if (allPreps.contains(address)) { - loginData.put("isPRep", BigInteger.ONE); - if (ArrayDBUtils.containsInArrayDb(address, pReps.unregisteredPreps)) { - loginData.put("isRegistered", BigInteger.ZERO); - loginData.put("payPenalty", BigInteger.ZERO); - loginData.put("votingPRep", BigInteger.ZERO); - - } else if (ArrayDBUtils.containsInArrayDb(address, pReps.denylist)) { - loginData.put("isRegistered", BigInteger.ZERO); - loginData.put("payPenalty", BigInteger.ONE); - loginData.put("votingPRep", BigInteger.ZERO); - loginData.put("penaltyAmount", getPenaltyAmount(address)); + loginData.put(IS_PREP, BigInteger.ONE); + if (ArrayDBUtils.containsInArrayDb(address, pReps.denylist)) { + loginData.put(PAY_PENALTY, BigInteger.ONE); + loginData.put(PENALTY_AMOUNT1, getPenaltyAmount(address)); } else if (ArrayDBUtils.containsInArrayDb(address, pReps.registeredPreps)) { - loginData.put("isRegistered", BigInteger.ONE); - loginData.put("payPenalty", BigInteger.ZERO); - loginData.put("votingPRep", BigInteger.ZERO); + loginData.put(IS_REGISTERED, BigInteger.ONE); if (ArrayDBUtils.containsInArrayDb(address, pReps.validPreps)) { - loginData.put("votingPRep", BigInteger.ONE); + loginData.put(VOTING_PREP, BigInteger.ONE); } - } else { - loginData.put("isRegistered", BigInteger.ZERO); - loginData.put("payPenalty", BigInteger.ZERO); - loginData.put("votingPRep", BigInteger.ZERO); } - } else { - loginData.put("isPRep", BigInteger.ZERO); - loginData.put("isRegistered", BigInteger.ZERO); - loginData.put("payPenalty", BigInteger.ZERO); - loginData.put("votingPRep", BigInteger.ZERO); - } return loginData; } - @Override - @Deprecated(since = "JAVA translation", forRemoval = true) - @External(readonly = true) - public Map login_prep(Address _address) { - return loginPrep(_address); - } + @Override @External(readonly = true) public List
getAdmins() { return ArrayDBUtils.arrayDBtoList(admins); } - @Override - @Deprecated(since = "JAVA translation", forRemoval = true) - @External(readonly = true) - public List
get_admins() { - return getAdmins(); - } @Override @External(readonly = true) public Map getRemainingFund() { SetterGetter setterGetter = new SetterGetter(); //noinspection unchecked - return callScore(Map.class, setterGetter.cpfScore.get(), "get_total_funds"); + return callScore(Map.class, setterGetter.cpfScore.get(), "getTotalFunds"); } - @Deprecated(since = "JAVA translation", forRemoval = true) - @External(readonly = true) - public Map get_remaining_fund() { - return getRemainingFund(); - } - + @Override @External(readonly = true) public List> getPReps() { List> prepsList = new ArrayList<>(); @@ -615,12 +571,6 @@ public List> getPReps() { } @Override - @Deprecated(since = "JAVA translation", forRemoval = true) - @External(readonly = true) - public List> get_PReps() { - return getPReps(); - } - @External(readonly = true) public List
getDenylist() { List
denyList = new ArrayList<>(); @@ -633,12 +583,6 @@ public List
getDenylist() { } @Override - @Deprecated(since = "JAVA translation", forRemoval = true) - @External(readonly = true) - public List
get_denylist() { - return getDenylist(); - } - @External(readonly = true) public Map getPeriodStatus() { PeriodController period = new PeriodController(); @@ -651,29 +595,17 @@ public List
get_denylist() { REMAINING_TIME, remainingTime, PERIOD_NAME, period.periodName.getOrDefault("None"), PREVIOUS_PERIOD_NAME, period.previousPeriodName.getOrDefault("None"), - PERIOD_SPAN, BLOCKS_DAY_COUNT.multiply(DAY_COUNT).multiply(BigInteger.valueOf(2))); + PERIOD_SPAN, BLOCKS_DAY_COUNT.multiply(TOTAL_PERIOD)); } @Override - @Deprecated(since = "JAVA translation", forRemoval = true) - @External(readonly = true) - public Map get_period_status() { - return getPeriodStatus(); - } - @External(readonly = true) public List
getContributors() { return ArrayDBUtils.arrayDBtoList(this.contributors); } - @Override - @Deprecated(since = "JAVA translation", forRemoval = true) - @External(readonly = true) - public List
get_contributors() { - return getContributors(); - } - + @Override @External(readonly = true) public Map checkClaimableSponsorBond(Address address) { DictDB userAmounts = sponsorBondReturn.at(address.toString()); @@ -682,23 +614,18 @@ public Map checkClaimableSponsorBond(Address address) { } - @Override - @Deprecated(since = "JAVA translation", forRemoval = true) - @External(readonly = true) - public Map check_claimable_sponsor_bond(Address _address) { - return checkClaimableSponsorBond(_address); - } @SuppressWarnings("unchecked") private BigInteger getMaxCapBNUsd() { SetterGetter setterGetter = new SetterGetter(); - Map cpfAmount = callScore(Map.class, setterGetter.cpfScore.get(), "get_remaining_swap_amount"); + Map cpfAmount = callScore(Map.class, setterGetter.cpfScore.get(), "getRemainingSwapAmount"); return cpfAmount.get("maxCap"); } + @Override @Payable @External - public void submitProposal(ProposalAttributes proposals) { + public void submitProposal(ProposalAttributes proposals, MilestonesAttributes[] milestones) { checkMaintenance(); updatePeriod(); PeriodController period = new PeriodController(); @@ -708,6 +635,7 @@ public void submitProposal(ProposalAttributes proposals) { Context.require(!Context.getCaller().isContract(), TAG + ": Contract Address not supported."); Context.require(proposals.project_duration <= MAX_PROJECT_PERIOD, TAG + ": Maximum Project Duration exceeds " + MAX_PROJECT_PERIOD + " months."); + Context.require(proposals.milestoneCount == milestones.length, TAG + ": Milestone count mismatch"); BigInteger projectBudget = proposals.total_budget.multiply(EXA); BigInteger maxCapBNUsd = getMaxCapBNUsd(); Context.require(projectBudget.compareTo(maxCapBNUsd) < 0, @@ -724,9 +652,25 @@ public void submitProposal(ProposalAttributes proposals) { String ipfsHashPrefix = proposalPrefix(ipfsHash); addDataToProposalDB(proposals, ipfsHashPrefix); + BigInteger initialPaymentPercentage = callScore(BigInteger.class, getCpsTreasuryScore(), "getOnsetPayment"); + + BigInteger totalBudget = proposals.total_budget.multiply(EXA); + BigInteger milestoneBudget = totalBudget.subtract(totalBudget.multiply(initialPaymentPercentage).divide(HUNDRED)); + + BigInteger totalMilestoneBudget = BigInteger.ZERO; + for (MilestonesAttributes milestone : milestones) { + totalMilestoneBudget = totalMilestoneBudget.add(milestone.budget); + String milestonePrefix = mileStonePrefix(ipfsHash, milestone.id); + addDataToMilestoneDb(milestone, milestonePrefix); + milestoneIds.at(ipfsHashPrefix).add(milestone.id); + } + Context.require(milestoneBudget.equals(totalMilestoneBudget), TAG + ":: Total milestone budget and " + + "project budget is not equal"); + proposalsKeyList.add(proposals.ipfs_hash); proposalsKeyListIndex.set(ipfsHash, proposalsKeyList.size() - 1); - sponsorPending.add(ipfsHash); + Status status = new Status(); + status.sponsorPending.add(ipfsHash); contributors.add(Context.getCaller()); contributorProjects.at(Context.getCaller()).add(ipfsHash); ProposalSubmitted(Context.getCaller(), "Successfully submitted a Proposal."); @@ -738,14 +682,8 @@ public void submitProposal(ProposalAttributes proposals) { swapBNUsdToken(); } - @Override - @Deprecated(since = "JAVA translation", forRemoval = true) - @Payable - @External - public void submit_proposal(ProposalAttributes _proposals) { - submitProposal(_proposals); - } + @Override @External public void voteProposal(String ipfsKey, String vote, String voteReason, @Optional boolean voteChange) { checkMaintenance(); @@ -766,27 +704,27 @@ public void voteProposal(String ipfsKey, String vote, String voteReason, @Option ArrayDB
voterList = ProposalDataDb.votersList.at(proposalPrefix); - if (!voteChange) { - if (ArrayDBUtils.containsInArrayDb(caller, voterList)) { - Context.revert(TAG + ": Already Voted"); - } + if (!voteChange && (ArrayDBUtils.containsInArrayDb(caller, voterList))) { + Context.revert(TAG + ":: Already Voted"); + } Context.require(status.equals(PENDING), TAG + ": Proposal must be done in Voting state."); - BigInteger voterStake = delegationSnapshot.get(caller); - BigInteger totalVotes = (BigInteger) proposalDetails.get(TOTAL_VOTES); - BigInteger approvedVotes = (BigInteger) proposalDetails.get(APPROVED_VOTES); - BigInteger rejectedVotes = (BigInteger) proposalDetails.get(REJECTED_VOTES); - BigInteger abstainedVotes = (BigInteger) proposalDetails.get(ABSTAINED_VOTES); - Integer totalVoter = (Integer) proposalDetails.get(TOTAL_VOTERS); - if (totalVoter == 0) { + BigInteger voterStake = getDelegation(caller); + Map proposalVoteDetails = getVoteResult(ipfsKey); + BigInteger totalVotes = (BigInteger) proposalVoteDetails.get(TOTAL_VOTES); + BigInteger approvedVotes = (BigInteger) proposalVoteDetails.get(APPROVED_VOTES); + BigInteger rejectedVotes = (BigInteger) proposalVoteDetails.get(REJECTED_VOTES); + BigInteger abstainedVotes = (BigInteger) proposalVoteDetails.get(ABSTAINED_VOTES); + Integer totalVoter = (Integer) proposalVoteDetails.get(TOTAL_VOTERS); + if (totalVoter == 0 || totalVotes.equals(BigInteger.ZERO)) { ProposalDataDb.totalVoters.at(proposalPrefix).set(pReps.validPreps.size()); + ProposalDataDb.totalVotes.at(proposalPrefix).set(totalDelegationSnapshot.getOrDefault(BigInteger.ZERO)); } DictDB votersIndexDb = votersListIndex.at(proposalPrefix).at(caller); if (!voteChange) { - ProposalDataDb.totalVotes.at(proposalPrefix).set(totalVotes.add(voterStake)); ProposalDataDb.votersList.at(proposalPrefix).add(caller); votersIndexDb.set(INDEX, ProposalDataDb.votersList.at(proposalPrefix).size()); ProposalDataDb.votersReasons.at(proposalPrefix).add(voteReason); @@ -798,9 +736,15 @@ public void voteProposal(String ipfsKey, String vote, String voteReason, @Option int voteIndex = votersIndexDb.getOrDefault(VOTE, 0); ProposalDataDb.votersReasons.at(proposalPrefix).set(index - 1, voteReason); if (voteIndex == APPROVE_) { + if (vote.equals(APPROVE)) { + Context.revert(TAG + ":: Cannot cast same vote. Change your vote"); + } ArrayDBUtils.removeArrayItem(ProposalDataDb.approveVoters.at(proposalPrefix), caller); ProposalDataDb.approvedVotes.at(proposalPrefix).set(approvedVotes.subtract(voterStake)); } else if (voteIndex == REJECT_) { + if (vote.equals(REJECT)) { + Context.revert(TAG + ":: Cannot cast same vote. Change your vote"); + } ArrayDBUtils.removeArrayItem(ProposalDataDb.rejectVoters.at(proposalPrefix), caller); ProposalDataDb.rejectedVotes.at(proposalPrefix).set(rejectedVotes.subtract(voterStake)); } else { @@ -830,15 +774,32 @@ public void voteProposal(String ipfsKey, String vote, String voteReason, @Option swapBNUsdToken(); } - @Override - @Deprecated(since = "JAVA translation", forRemoval = true) - @External - public void vote_proposal(String _ipfs_key, String _vote, String _vote_reason, @Optional boolean _vote_change) { - voteProposal(_ipfs_key, _vote, _vote_reason, _vote_change); + + private List getMilestoneDeadline(String ipfsHash) { + String ipfsHAshPRefix = proposalPrefix(ipfsHash); + ArrayDB milestoneIDs = milestoneIds.at(ipfsHAshPRefix); + + List milestoneIdList = new ArrayList<>(); + for (int i = 0; i < milestoneIDs.size(); i++) { + int milestoneId = milestoneIDs.get(i); + String milestonePrefix = mileStonePrefix(ipfsHash, milestoneId); + int proposalTotalPeriod = proposalPeriod.at(ipfsHAshPRefix).getOrDefault(0); + int completionPeriod = MilestoneDb.completionPeriod.at(milestonePrefix).getOrDefault(0); + + int computedCompletionPeriod = proposalTotalPeriod + completionPeriod; + + int currentPeriod = getPeriodCount(); + if (currentPeriod >= computedCompletionPeriod) { + milestoneIdList.add(milestoneId); + } + } + return milestoneIdList; } + + @Override @External - public void submitProgressReport(ProgressReportAttributes progressReport) { + public void submitProgressReport(ProgressReportAttributes progressReport, MilestoneSubmission[] milestoneSubmissions) { checkMaintenance(); updatePeriod(); PeriodController period = new PeriodController(); @@ -869,13 +830,43 @@ public void submitProgressReport(ProgressReportAttributes progressReport) { Context.require(proposalKeyExists(ipfsHash), TAG + ": Invalid proposal key"); addNewProgressReportKey(ipfsHash, reportHash); String reportHashPrefix = progressReportPrefix(reportHash); + addDataToProgressReportDB(progressReport, reportHashPrefix); - int percentageCompleted = progressReport.percentage_completed; + int totalMilestoneCount = ProposalDataDb.getMilestoneCount(ipfsHashPrefix); + int currentPeriod = getPeriodCount(); + int duration = projectDuration.at(ipfsHashPrefix).get(); + int totalPeriod = duration + proposalPeriod.at(ipfsHashPrefix).getOrDefault(0); + + if (totalMilestoneCount != 0) { + boolean lastProgressReport = totalPeriod - currentPeriod == 0; + int approvedReports = ProposalDataDb.approvedReports.at(ipfsHashPrefix).getOrDefault(0); + if ((lastProgressReport) && (milestoneSubmissions.length + approvedReports != totalMilestoneCount)) { + Context.revert(TAG + ":: Submit progress report for all milestones."); + } + + + Context.require(milestoneSubmissions.length + approvedReports <= totalMilestoneCount, + TAG + ":: Submitted milestone is greater than recorded on proposal."); + + for (MilestoneSubmission milestoneAttr : milestoneSubmissions) { + if (getMilestoneDeadline(ipfsHash).size() > 0) { + Context.require(getMilestoneDeadline(ipfsHash).contains(milestoneAttr.id), TAG + + ": Submit milestone report for milestone id " + getMilestoneDeadline(ipfsHash)); + } + int milestoneStatus = getMileststoneStatusOf(ipfsHash, milestoneAttr.id); + if (milestoneStatus == MILESTONE_REPORT_APPROVED || milestoneStatus == MILESTONE_REPORT_COMPLETED) { + Context.revert(TAG + " Milestone already completed/submitted " + milestoneStatus); + } + int stats = MILESTONE_REPORT_NOT_COMPLETED; + if (milestoneAttr.status) { + stats = MILESTONE_REPORT_COMPLETED; + } + String milestonePrefix = mileStonePrefix(ipfsHash, milestoneAttr.id); + MilestoneDb.status.at(milestonePrefix).set(stats); + MilestoneDb.progressReportHash.at(milestonePrefix).set(reportHash); + milestoneSubmitted.at(reportHashPrefix).add(milestoneAttr.id); + } - if (percentageCompleted >= 0 && percentageCompleted <= 100) { - ProposalDataDb.percentageCompleted.at(ipfsHashPrefix).set(percentageCompleted); - } else { - Context.revert(TAG + ": Percentage completed should be between 0 and 100"); } if (progressReport.budget_adjustment) { @@ -898,24 +889,36 @@ public void submitProgressReport(ProgressReportAttributes progressReport) { progressKeyListIndex.set(reportHash, progressKeyList.size() - 1); submitProgressReport.at(ipfsHashPrefix).set(true); - waitingProgressReports.add(reportHash); + Status _status = new Status(); + _status.waitingProgressReports.add(reportHash); swapBNUsdToken(); ProgressReportSubmitted(caller, progressReport.progress_report_title + " --> Progress Report Submitted Successfully."); } - @Override - @Deprecated(since = "JAVA translation", forRemoval = true) - @External - public void submit_progress_report(ProgressReportAttributes _progress_report) { - submitProgressReport(_progress_report); + public boolean isAllElementPresent(MilestoneVoteAttributes[] vote, ArrayDB submitted) { + for (int i = 0; i < submitted.size(); i++) { + boolean found = false; + for (MilestoneVoteAttributes v : vote) { + if (v.id == submitted.get(i)) { + found = true; + break; + } + } + if (!found) { + return false; + } + } + return true; } + + @Override @External - public void voteProgressReport(String ipfsKey, String reportKey, String vote, String voteReason, @Optional String budgetAdjustmentVote, @Optional boolean voteChange) { + public void voteProgressReport(String reportKey, String voteReason, MilestoneVoteAttributes[] votes, + @Optional String budgetAdjustmentVote, @Optional boolean voteChange) { if (budgetAdjustmentVote == null) { budgetAdjustmentVote = ""; - } checkMaintenance(); @@ -927,87 +930,129 @@ public void voteProgressReport(String ipfsKey, String reportKey, String vote, St PReps pReps = new PReps(); Context.require(ArrayDBUtils.containsInArrayDb(caller, pReps.validPreps), TAG + ": Voting can only be done by registered P-Reps."); - Context.require(List.of(APPROVE, REJECT).contains(vote), - TAG + ": Vote should be either _approve or _reject"); + String progressReportPrefix = progressReportPrefix(reportKey); + ArrayDB submittedMilestones = milestoneSubmitted.at(progressReportPrefix);// CAN TAKE FROM READONLY METHOD + for (MilestoneVoteAttributes milestoneVote : votes) { + Context.require(List.of(APPROVE, REJECT).contains(milestoneVote.vote), + TAG + ": Vote should be either _approve or _reject"); + Context.require(ArrayDBUtils.containsInArrayDb(milestoneVote.id, submittedMilestones), + TAG + ": Voting can only be done for milestone submitted in this progress report"); + } + if (!voteChange) { + if (votes.length == submittedMilestones.size()) { + Context.require(isAllElementPresent(votes, submittedMilestones), + "You should submit votes for all milestones of the progress report"); + } else { + Context.revert(TAG + ":: You should submit votes for all milestones of the progress report"); + } + } Map progressReportDetails = getProgressReportDetails(reportKey); - String progressReportPrefix = progressReportPrefix(reportKey); String status = (String) progressReportDetails.get(STATUS); - ArrayDB
voterList = ProgressReportDataDb.votersList.at(progressReportPrefix); + if (!status.equals(WAITING)) { + Context.revert(TAG + ": Voting can be only be done in waiting progress reports."); + } - if (!voteChange) { - if (ArrayDBUtils.containsInArrayDb(caller, voterList)) { - Context.revert(TAG + ": Already Voted"); - } + BigInteger voterStake = getDelegation(caller); + String proposalKey = ProgressReportDataDb.ipfsHash.at(progressReportPrefix).get(); + + BigInteger totalVotes = ProgressReportDataDb.totalVotes.at(progressReportPrefix).getOrDefault(BigInteger.ZERO); + Integer totalVoter = ProgressReportDataDb.totalVoters.at(progressReportPrefix).getOrDefault(0); + + if (totalVoter == 0 || totalVotes.equals(BigInteger.ZERO)) { + ProgressReportDataDb.totalVoters.at(progressReportPrefix).set(pReps.validPreps.size()); + ProgressReportDataDb.totalVotes.at(progressReportPrefix).set(this.totalDelegationSnapshot.getOrDefault(BigInteger.ZERO)); + } + + DictDB voteChanged = ProgressReportDataDb.voteChange.at(progressReportPrefix); + + if (voteChanged.getOrDefault(caller, NOT_VOTED) == 1) { + Context.revert(TAG + ":: Vote change can be done only once."); } + for (MilestoneVoteAttributes milestoneVote : votes) { + String milestonePrefix = mileStonePrefix(proposalKey, milestoneVote.id); + ArrayDB
voterList = MilestoneDb.votersList.at(milestonePrefix); + if (!voteChange && (ArrayDBUtils.containsInArrayDb(caller, voterList))) { + Context.revert(TAG + ":: Already Voted"); - if (status.equals(WAITING)) { - BigInteger voterStake = delegationSnapshot.get(caller); - BigInteger totalVotes = (BigInteger) progressReportDetails.get(TOTAL_VOTES); - BigInteger approvedVotes = (BigInteger) progressReportDetails.get(APPROVED_VOTES); - BigInteger rejectedVotes = (BigInteger) progressReportDetails.get(REJECTED_VOTES); - Integer totalVoter = (Integer) progressReportDetails.get(TOTAL_VOTERS); - if (totalVoter == 0) { - ProgressReportDataDb.totalVoters.at(progressReportPrefix).set(pReps.validPreps.size()); } - DictDB votersIndexDb = votersListIndices.at(progressReportPrefix).at(caller); + Map milestoneDetails = getDataFromMilestoneDB(milestonePrefix); + BigInteger approvedVotes = (BigInteger) milestoneDetails.get(APPROVED_VOTES); + BigInteger rejectedVotes = (BigInteger) milestoneDetails.get(REJECTED_VOTES); + + DictDB votersIndexDb = MilestoneDb.votersListIndices.at(milestonePrefix).at(caller); if (!voteChange) { - ProgressReportDataDb.totalVotes.at(progressReportPrefix).set(totalVotes.add(voterStake)); - ProgressReportDataDb.votersList.at(progressReportPrefix).add(caller); - votersIndexDb.set(INDEX, ProgressReportDataDb.votersList.at(progressReportPrefix).size()); + MilestoneDb.votersList.at(milestonePrefix).add(caller); + votersIndexDb.set(INDEX, MilestoneDb.votersList.at(milestonePrefix).size()); ProgressReportDataDb.votersReasons.at(progressReportPrefix).add(voteReason); } else { - Context.require(votersIndexDb.getOrDefault(CHANGE_VOTE, 0) == 0, - TAG + ": Progress Report Vote change can be done only once."); - votersIndexDb.set(CHANGE_VOTE, VOTED); + voteChanged.set(caller, VOTED); int index = votersIndexDb.getOrDefault(INDEX, 0); int voteIndex = votersIndexDb.getOrDefault(VOTE, 0); ProgressReportDataDb.votersReasons.at(progressReportPrefix).set(index - 1, voteReason); if (voteIndex == APPROVE_) { - ArrayDBUtils.removeArrayItem(ProgressReportDataDb.approveVoters.at(progressReportPrefix), caller); - ProgressReportDataDb.approvedVotes.at(progressReportPrefix).set(approvedVotes.subtract(voterStake)); + if (milestoneVote.vote.equals(APPROVE)) { + Context.revert(TAG + ": Cannot cast same vote. Change your vote"); + } + ArrayDBUtils.removeArrayItem(MilestoneDb.approveVoters.at(milestonePrefix), caller); + MilestoneDb.approvedVotes.at(milestonePrefix).set(approvedVotes.subtract(voterStake)); } else { - ArrayDBUtils.removeArrayItem(ProgressReportDataDb.rejectVoters.at(progressReportPrefix), caller); - ProgressReportDataDb.rejectedVotes.at(progressReportPrefix).set(rejectedVotes.subtract(voterStake)); - } - - if (ArrayDBUtils.containsInArrayDb(reportKey, budgetApprovalsList)) { - BigInteger budgetApprovedVotes = (BigInteger) progressReportDetails.get(BUDGET_APPROVED_VOTES); - BigInteger budgetRejectedVotes = (BigInteger) progressReportDetails.get(BUDGET_REJECTED_VOTES); - int budgetVoteIndex = budgetVotersListIndices.at(progressReportPrefix).at(caller).getOrDefault(VOTE, 0); - if (budgetVoteIndex == APPROVE_) { - ArrayDBUtils.removeArrayItem(budgetApproveVoters.at(progressReportPrefix), caller); - ProgressReportDataDb.budgetApprovedVotes.at(progressReportPrefix).set(budgetApprovedVotes.subtract(voterStake)); - } else if (budgetVoteIndex == REJECT_) { - ArrayDBUtils.removeArrayItem(budgetRejectVoters.at(progressReportPrefix), caller); - ProgressReportDataDb.budgetRejectedVotes.at(progressReportPrefix).set(budgetRejectedVotes.subtract(voterStake)); - } else { - Context.revert(TAG + ": Choose option " + APPROVE + " or " + REJECT + " for budget adjustment"); + if (milestoneVote.vote.equals(REJECT)) { + Context.revert(TAG + ": Cannot cast same vote. Change your vote"); } - + ArrayDBUtils.removeArrayItem(MilestoneDb.rejectVoters.at(milestonePrefix), caller); + MilestoneDb.rejectedVotes.at(milestonePrefix).set(rejectedVotes.subtract(voterStake)); } - approvedVotes = ProgressReportDataDb.approvedVotes.at(progressReportPrefix).getOrDefault(BigInteger.ZERO); - rejectedVotes = ProgressReportDataDb.rejectedVotes.at(progressReportPrefix).getOrDefault(BigInteger.ZERO); + } + boolean budgetAdjustment = (boolean) progressReportDetails.get(BUDGET_ADJUSTMENT); + if (budgetAdjustment && getBudgetAdjustmentFeature()) { // + budgetAdjustment(reportKey, budgetAdjustmentVote, voteChange); } - if (vote.equals(APPROVE)) { - ProgressReportDataDb.approveVoters.at(progressReportPrefix).add(caller); + approvedVotes = MilestoneDb.approvedVotes.at(milestonePrefix).getOrDefault(BigInteger.ZERO); + rejectedVotes = MilestoneDb.rejectedVotes.at(milestonePrefix).getOrDefault(BigInteger.ZERO); + if (milestoneVote.vote.equals(APPROVE)) { + MilestoneDb.approveVoters.at(milestonePrefix).add(caller); votersIndexDb.set(VOTE, APPROVE_); - ProgressReportDataDb.approvedVotes.at(progressReportPrefix).set(approvedVotes.add(voterStake)); - } else if (vote.equals(REJECT)) { - ProgressReportDataDb.rejectVoters.at(progressReportPrefix).add(caller); - votersIndexDb.set(VOTE, REJECT_); - ProgressReportDataDb.rejectedVotes.at(progressReportPrefix).set(rejectedVotes.add(voterStake)); + MilestoneDb.approvedVotes.at(milestonePrefix).set(approvedVotes.add(voterStake)); } else { - Context.revert(TAG + ": Choose option " + APPROVE + " or " + REJECT + " for budget adjustment"); + MilestoneDb.rejectVoters.at(milestonePrefix).add(caller); + votersIndexDb.set(VOTE, REJECT_); + MilestoneDb.rejectedVotes.at(milestonePrefix).set(rejectedVotes.add(voterStake)); + } + if (budgetAdjustment && getBudgetAdjustmentFeature()) { + budgetAdjustment(reportKey, budgetAdjustmentVote, voteChange); - if (ArrayDBUtils.containsInArrayDb(reportKey, budgetApprovalsList)) { - BigInteger budgetApprovedVotes = ProgressReportDataDb.budgetApprovedVotes.at(progressReportPrefix).getOrDefault(BigInteger.ZERO); - BigInteger budgetRejectedVotes = ProgressReportDataDb.budgetRejectedVotes.at(progressReportPrefix).getOrDefault(BigInteger.ZERO); + } + VotedSuccessfully(caller, "Progress Report Vote for " + progressReportDetails.get(PROGRESS_REPORT_TITLE) + " Successful."); + swapBNUsdToken(); + } + } + + private void budgetAdjustment(String reportKey, String budgetAdjustmentVote, boolean voteChange) { + String progressReportPrefix = progressReportPrefix(reportKey); + Address caller = Context.getCaller(); + BigInteger voterStake = getDelegation(caller); + if (ArrayDBUtils.containsInArrayDb(reportKey, budgetApprovalsList)) { + BigInteger budgetApprovedVotes = ProgressReportDataDb.budgetApprovedVotes.at(progressReportPrefix).getOrDefault(BigInteger.ZERO); + BigInteger budgetRejectedVotes = ProgressReportDataDb.budgetRejectedVotes.at(progressReportPrefix).getOrDefault(BigInteger.ZERO); + + if (voteChange) { + int budgetVoteIndex = budgetVotersListIndices.at(progressReportPrefix).at(caller).getOrDefault(VOTE, 0); + if (budgetVoteIndex == APPROVE_) { + ArrayDBUtils.removeArrayItem(budgetApproveVoters.at(progressReportPrefix), caller); + ProgressReportDataDb.budgetApprovedVotes.at(progressReportPrefix).set(budgetApprovedVotes.subtract(voterStake)); + } else if (budgetVoteIndex == REJECT_) { + ArrayDBUtils.removeArrayItem(budgetRejectVoters.at(progressReportPrefix), caller); + ProgressReportDataDb.budgetRejectedVotes.at(progressReportPrefix).set(budgetRejectedVotes.subtract(voterStake)); + } else { + Context.revert(TAG + ": Choose option " + APPROVE + " or " + REJECT + " for budget adjustment"); + } + } else { DictDB budgetVoteIndex = budgetVotersListIndices.at(progressReportPrefix).at(caller); if (budgetAdjustmentVote.equals(APPROVE)) { ProgressReportDataDb.budgetApproveVoters.at(progressReportPrefix).add(caller); @@ -1021,34 +1066,19 @@ public void voteProgressReport(String ipfsKey, String reportKey, String vote, St Context.revert(TAG + ": Choose option " + APPROVE + " or " + REJECT + " for budget adjustment"); } } - VotedSuccessfully(caller, "Proposal Vote for " + progressReportDetails.get(PROGRESS_REPORT_TITLE) + " Successful."); - - - swapBNUsdToken(); } } @Override - @Deprecated(since = "JAVA translation", forRemoval = true) - @External - public void vote_progress_report(String _ipfs_key, String _report_key, String _vote, String _vote_reason, @Optional String _budget_adjustment_vote, @Optional boolean _vote_change) { - voteProgressReport(_ipfs_key, _report_key, _vote, _vote_reason, _budget_adjustment_vote, _vote_change); - } - @External(readonly = true) public List getProposalsKeysByStatus(String status) { + Status _status = new Status(); Context.require(STATUS_TYPE.contains(status), TAG + ": Not a valid status"); - ArrayDB proposalStatus = this.proposalStatus.get(status); + ArrayDB proposalStatus = _status.proposalStatus.get(status); return ArrayDBUtils.arrayDBtoList(proposalStatus); } @Override - @Deprecated(since = "JAVA translation", forRemoval = true) - @External(readonly = true) - public List get_proposals_keys_by_status(String _status) { - return getProposalsKeysByStatus(_status); - } - @External(readonly = true) public int checkChangeVote(Address address, String ipfsHash, String proposalType) { if (proposalType.equals(PROPOSAL)) { @@ -1056,7 +1086,7 @@ public int checkChangeVote(Address address, String ipfsHash, String proposalType return ProposalDataDb.votersListIndex.at(proposalPrefix).at(address).getOrDefault(CHANGE_VOTE, NOT_VOTED); } else if (proposalType.equals(PROGRESS_REPORTS)) { String progressReportPrefix = progressReportPrefix(ipfsHash); - return votersListIndices.at(progressReportPrefix).at(address).getOrDefault(CHANGE_VOTE, NOT_VOTED); + return ProgressReportDataDb.voteChange.at(progressReportPrefix).getOrDefault(address, NOT_VOTED); } else { return 0; } @@ -1092,6 +1122,7 @@ public int check_change_vote(Address _address, String _ipfs_hash, String _propos return checkChangeVote(_address, _ipfs_hash, _proposal_type); } + @External(readonly = true) public Map getProjectAmounts() { List statusList = List.of(PENDING, ACTIVE, PAUSED, COMPLETED, DISQUALIFIED); @@ -1141,22 +1172,17 @@ public Map getProjectAmounts() { } - return Map.of(statusList.get(0), Map.of(AMOUNT, Map.of(ICX, pendingAmountIcx, bnUSD, pendingAmountBnusd), "_count", proposalStatus.get(statusList.get(0)).size()), - statusList.get(1), Map.of(AMOUNT, Map.of(ICX, activeAmountIcx, bnUSD, activeAmountBnusd), "_count", proposalStatus.get(statusList.get(1)).size()), - statusList.get(2), Map.of(AMOUNT, Map.of(ICX, pausedAmountIcx, bnUSD, pausedAmountBnusd), "_count", proposalStatus.get(statusList.get(2)).size()), - statusList.get(3), Map.of(AMOUNT, Map.of(ICX, completedAmountIcx, bnUSD, completedAmountBnusd), "_count", proposalStatus.get(statusList.get(3)).size()), - statusList.get(4), Map.of(AMOUNT, Map.of(ICX, disqualifiedAmountIcx, bnUSD, disqualifiedAmountBnusd), "_count", proposalStatus.get(statusList.get(4)).size())); + Status status = new Status(); + return Map.of(statusList.get(0), Map.of(AMOUNT, Map.of(ICX, pendingAmountIcx, bnUSD, pendingAmountBnusd), COUNT, status.proposalStatus.get(statusList.get(0)).size()), + statusList.get(1), Map.of(AMOUNT, Map.of(ICX, activeAmountIcx, bnUSD, activeAmountBnusd), COUNT, status.proposalStatus.get(statusList.get(1)).size()), + statusList.get(2), Map.of(AMOUNT, Map.of(ICX, pausedAmountIcx, bnUSD, pausedAmountBnusd), COUNT, status.proposalStatus.get(statusList.get(2)).size()), + statusList.get(3), Map.of(AMOUNT, Map.of(ICX, completedAmountIcx, bnUSD, completedAmountBnusd), COUNT, status.proposalStatus.get(statusList.get(3)).size()), + statusList.get(4), Map.of(AMOUNT, Map.of(ICX, disqualifiedAmountIcx, bnUSD, disqualifiedAmountBnusd), COUNT, status.proposalStatus.get(statusList.get(4)).size())); } @Override - @Deprecated(since = "JAVA translation", forRemoval = true) - @External(readonly = true) - public Map get_project_amounts() { - return getProjectAmounts(); - } - @External(readonly = true) public Map getSponsorsRecord() { Map sponsorsDict = new HashMap<>(); @@ -1168,13 +1194,8 @@ public Map getSponsorsRecord() { return sponsorsDict; } - @Override - @Deprecated(since = "JAVA translation", forRemoval = true) - @External(readonly = true) - public Map get_sponsors_record() { - return getSponsorsRecord(); - } + @Override @External public void updatePeriod() { checkMaintenance(); @@ -1182,19 +1203,19 @@ public void updatePeriod() { PeriodController period = new PeriodController(); BigInteger nextBlock = period.nextBlock.get(); PReps pReps = new PReps(); + Status status = new Status(); if (currentBlock.compareTo(nextBlock) >= 0) { if (period.periodName.get().equals(APPLICATION_PERIOD)) { period.periodName.set(VOTING_PERIOD); - period.periodCount.set(period.periodCount.get() + 1); period.previousPeriodName.set(APPLICATION_PERIOD); - period.nextBlock.set(nextBlock.add(BLOCKS_DAY_COUNT.multiply(DAY_COUNT))); + period.nextBlock.set(nextBlock.add(BLOCKS_DAY_COUNT.multiply(getVotingPeriod()))); updateApplicationResult(); period.updatePeriodIndex.set(0); setPreps(); snapshotDelegation(); - int activeProposalCount = pending.size() + waitingProgressReports.size(); + int activeProposalCount = status.pending.size() + status.waitingProgressReports.size(); swapCount.set(activeProposalCount + pReps.validPreps.size()); } else { @@ -1219,20 +1240,20 @@ public void updatePeriod() { } else { SetterGetter setterGetter = new SetterGetter(); updateDenylistPreps(); - period.nextBlock.set(nextBlock.add(BLOCKS_DAY_COUNT.multiply(DAY_COUNT))); + period.nextBlock.set(nextBlock.add(BLOCKS_DAY_COUNT.multiply(getApplicationPeriod()))); period.periodName.set(APPLICATION_PERIOD); period.previousPeriodName.set(VOTING_PERIOD); PeriodUpdate("Period Update State 4/4. Period Successfully Updated to Application Period."); setPreps(); - int activeProposalCount = active.size() + paused.size(); + int activeProposalCount = status.active.size() + status.paused.size(); swapCount.set(activeProposalCount + activeProposalCount * pReps.validPreps.size()); - callScore(setterGetter.cpfScore.get(), "reset_swap_state"); + callScore(setterGetter.cpfScore.get(), "resetSwapState"); ArrayDBUtils.clearArrayDb(budgetApprovalsList); - ArrayDBUtils.clearArrayDb(activeProposals); ArrayDBUtils.clearArrayDb(priorityVotedPreps); + period.periodCount.set(period.periodCount.getOrDefault(0) + 1); burn(proposalFees.get(), null); proposalFees.set(BigInteger.ZERO); } @@ -1241,12 +1262,6 @@ public void updatePeriod() { } } - @Override - @Deprecated(since = "JAVA translation", forRemoval = true) - @External - public void update_period() { - updatePeriod(); - } private void updateDenylistPreps() { PReps pReps = new PReps(); @@ -1262,6 +1277,24 @@ private void updateDenylistPreps() { ArrayDBUtils.clearArrayDb(pReps.inactivePreps); } + + private void updateMilestoneDB(String milestonePrefix) { + MilestoneDb.approvedVotes.at(milestonePrefix).set(BigInteger.ZERO); + clearArrayDb(MilestoneDb.approveVoters.at(milestonePrefix)); + + MilestoneDb.rejectedVotes.at(milestonePrefix).set(BigInteger.ZERO); + clearArrayDb(MilestoneDb.rejectVoters.at(milestonePrefix)); + + ArrayDB
voters = MilestoneDb.votersList.at(milestonePrefix); + for (int i = 0; i < voters.size(); i++) { + Address prep = voters.get(i); + DictDB prepVote = MilestoneDb.votersListIndices.at(milestonePrefix).at(prep); + prepVote.set(INDEX, 0); + prepVote.set(VOTE, 0); + } + clearArrayDb(MilestoneDb.votersList.at(milestonePrefix)); + } + /*** Calculate votes for the progress reports and update the status and get the Installment and Sponsor Reward is the progress report is accepted. @@ -1269,9 +1302,9 @@ private void updateDenylistPreps() { ***/ private void updateProgressReportResult() { - List waiting_progress_reports = arrayDBtoList(this.waitingProgressReports); + Status status = new Status(); + List waiting_progress_reports = arrayDBtoList(status.waitingProgressReports); PReps pReps = new PReps(); - List
_main_preps_list = arrayDBtoList(pReps.validPreps); for (String _reports : waiting_progress_reports) { Map _report_result = getProgressReportDetails(_reports); @@ -1279,81 +1312,160 @@ private void updateProgressReportResult() { String _ipfs_hash = (String) _report_result.get(IPFS_HASH); String proposal_prefix = proposalPrefix(_ipfs_hash); String progressPrefix = progressReportPrefix(_reports); - Map _proposal_details = getProposalDetails(_ipfs_hash); submitProgressReport.at(proposal_prefix).set(Boolean.FALSE); + boolean _budget_adjustment = (boolean) _report_result.get(BUDGET_ADJUSTMENT); + + +// If a progress report have any budget_adjustment, then it checks the budget adjustment first + if (_budget_adjustment && getBudgetAdjustmentFeature()) { + updateBudgetAdjustments(_reports); + } + Map _proposal_details = getProposalDetails(_ipfs_hash); + + int milestoneCount = (int) _proposal_details.get(MILESTONE_COUNT); String _proposal_status = (String) _proposal_details.get(STATUS); int _approved_reports_count = (int) _proposal_details.get(APPROVED_REPORTS); Address _sponsor_address = (Address) _proposal_details.get(SPONSOR_ADDRESS); - Address _contributor_address = (Address) _proposal_details.get(CONTRIBUTOR_ADDRESS); - boolean _budget_adjustment = (boolean) _report_result.get(BUDGET_ADJUSTMENT); BigInteger _sponsor_deposit_amount = (BigInteger) _proposal_details.get(SPONSOR_DEPOSIT_AMOUNT); - String flag = (String) _proposal_details.get("token"); + String flag = (String) _proposal_details.get(TOKEN); - int _approve_voters = (int) _report_result.get(APPROVE_VOTERS); - BigInteger _approved_votes = (BigInteger) _report_result.get(APPROVED_VOTES); - BigInteger _total_votes = (BigInteger) _report_result.get(TOTAL_VOTES); - int _total_voters = (int) _report_result.get(TOTAL_VOTERS); + List
_main_preps_list = arrayDBtoList(pReps.validPreps); -// checking which prep(s) did not vote the progress report - checkInactivePreps(ProgressReportDataDb.votersList.at(progressPrefix)); + ArrayDB milestoneSubmitted = ProgressReportDataDb.milestoneSubmitted.at(progressPrefix); -// If a progress report have any budget_adjustment, then it checks the budget adjustment first - if (_budget_adjustment) { - updateBudgetAdjustments(_reports); - } + int milestonePassed = 0; + BigInteger milestoneBudget = BigInteger.ZERO; + int milestoneSubmittedSize = milestoneSubmitted.size(); - int _project_duration = projectDuration.at(proposal_prefix).getOrDefault(0); - String updated_status; - double votersRatio = (double) _approve_voters / _total_voters; - if (_total_voters == 0 || _total_votes.equals(BigInteger.ZERO) || _main_preps_list.size() < MINIMUM_PREPS) { - updateProgressReportStatus(_reports, PROGRESS_REPORT_REJECTED); - updated_status = PROGRESS_REPORT_REJECTED; - } else if (votersRatio >= MAJORITY && (_approved_votes.doubleValue() / _total_votes.doubleValue()) >= MAJORITY) { + for (int i = 0; i < milestoneSubmittedSize; i++) { + String milestonePrefix = mileStonePrefix(_ipfs_hash, milestoneSubmitted.get(i)); - updateProgressReportStatus(_reports, APPROVED); - updated_status = APPROVED; - _approved_reports_count += 1; - - if (_approved_reports_count == _project_duration) { - updateProposalStatus(_ipfs_hash, COMPLETED); -// Transfer the Sponsor - Bond back to the Sponsor P - Rep after the project is completed. - this.sponsorBondReturn.at(_sponsor_address.toString()).set(flag, this.sponsorBondReturn.at(_sponsor_address.toString()).getOrDefault(flag, BigInteger.ZERO).add(_sponsor_deposit_amount)); - sponsorDepositStatus.at(proposal_prefix).set(BOND_RETURNED); - SponsorBondReturned(_sponsor_address, - _sponsor_deposit_amount + " " + flag + " returned to sponsor address."); - } else if (_proposal_status.equals(PAUSED)) { - updateProposalStatus(_ipfs_hash, ACTIVE); + // checking which prep(s) did not vote the progress report + checkInactivePreps(MilestoneDb.votersList.at(milestonePrefix)); + + Map _milestone_details = getDataFromMilestoneDB(milestonePrefix); + + int milestoneStatus = (int) _milestone_details.get(STATUS); + int _approve_voters = (int) _milestone_details.get(APPROVE_VOTERS); + BigInteger _approved_votes = (BigInteger) _milestone_details.get(APPROVED_VOTES); + BigInteger _total_votes = ProgressReportDataDb.totalVotes.at(progressPrefix).get(); + int _total_voters = ProgressReportDataDb.totalVoters.at(progressPrefix).getOrDefault(0); + + if (_total_voters == 0 || _total_votes.equals(BigInteger.ZERO) || _main_preps_list.size() < MINIMUM_PREPS) { + MilestoneDb.status.at(milestonePrefix).set(MILESTONE_REPORT_REJECTED); + updateMilestoneDB(milestonePrefix); + } else { + double votersRatio = (double) _approve_voters / _total_voters; + double votesRatio = _approved_votes.doubleValue() / _total_votes.doubleValue(); + if (votersRatio >= MAJORITY && votesRatio >= MAJORITY) { + _approved_reports_count += 1; + + if (milestoneStatus == MILESTONE_REPORT_COMPLETED) { + milestonePassed += 1; + milestoneBudget = milestoneBudget.add(MilestoneDb.budget.at(milestonePrefix).getOrDefault(BigInteger.ZERO)); + MilestoneDb.status.at(milestonePrefix).set(MILESTONE_REPORT_APPROVED); + int percentageCompleted = (_approved_reports_count * 100) / milestoneCount; + ProposalDataDb.updatePercentageCompleted(proposal_prefix, percentageCompleted); + + ProposalDataDb.approvedReports.at(proposal_prefix).set(_approved_reports_count); + + if (_approved_reports_count == milestoneCount) { + updateProposalStatus(_ipfs_hash, COMPLETED); + ProposalDataDb.updatePercentageCompleted(proposal_prefix, 100); + + // Transfer the Sponsor - Bond back to the Sponsor P - Rep after the project is completed. + this.sponsorBondReturn.at(_sponsor_address.toString()).set(flag, + this.sponsorBondReturn.at(_sponsor_address.toString()).getOrDefault(flag, BigInteger.ZERO). + add(_sponsor_deposit_amount)); + sponsorDepositStatus.at(proposal_prefix).set(BOND_RETURNED); + SponsorBondReturned(_sponsor_address, + _sponsor_deposit_amount + " " + flag + " returned to sponsor address."); + + + } else if (_proposal_status.equals(PAUSED)) { + updateProposalStatus(_ipfs_hash, ACTIVE); + } + + } else if (milestoneStatus == MILESTONE_REPORT_NOT_COMPLETED) { + int completionPeriod = MilestoneDb.completionPeriod.at(milestonePrefix).getOrDefault(0); + int proposalPeriod = ProposalDataDb.proposalPeriod.at(proposal_prefix).getOrDefault(0); + boolean extended = MilestoneDb.extensionFlag.at(milestonePrefix).getOrDefault(false); + + if (getPeriodCount() == (proposalPeriod + completionPeriod)) { + if (extended) { + updateProposalStatus(_ipfs_hash, _proposal_details); + } else { + 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 { + MilestoneDb.status.at(milestonePrefix).set(MILESTONE_REPORT_REJECTED); + updateMilestoneDB(milestonePrefix); + } } - ProposalDataDb.approvedReports.at(proposal_prefix).set(_approved_reports_count); -// Request CPS Treasury to add some installments amount to the contributor address - callScore(getCpsTreasuryScore(), "send_installment_to_contributor", _ipfs_hash); -// Request CPS Treasury to add some sponsor reward amount to the sponsor address - callScore(getCpsTreasuryScore(), "send_reward_to_sponsor", _ipfs_hash); + } + if (milestonePassed > 0) { + updateProgressReportStatus(_reports, APPROVED); } else { updateProgressReportStatus(_reports, PROGRESS_REPORT_REJECTED); - updated_status = PROGRESS_REPORT_REJECTED; + updateProposalStatus(_ipfs_hash, _proposal_details); } - if (updated_status.equals(PROGRESS_REPORT_REJECTED)) { - if (_proposal_status.equals(ACTIVE)) { - updateProposalStatus(_ipfs_hash, PAUSED); - } else if (_proposal_status.equals(PAUSED)) { - updateProposalStatus(_ipfs_hash, DISQUALIFIED); - callScore(getCpsTreasuryScore(), "disqualify_project", _ipfs_hash); - - removeContributor(_contributor_address, _ipfs_hash); - removeSponsor(_sponsor_address, _ipfs_hash); - - sponsorDepositStatus.at(proposal_prefix).set(BOND_CANCELLED); -// Transferring the sponsor bond deposit to CPF after the project being disqualified - disqualifyProject(_sponsor_address, _sponsor_deposit_amount, flag); + int projectDuration = ProposalDataDb.projectDuration.at(proposal_prefix).getOrDefault(0); + int proposalPeriod = ProposalDataDb.proposalPeriod.at(proposal_prefix).getOrDefault(0); + boolean lastProgressReport = proposalPeriod + projectDuration - getPeriodCount() == 0; + if (milestoneBudget.compareTo(BigInteger.ZERO) > 0) { + // Request CPS Treasury to add some installments amount to the contributor address + Address cpsTreasuryScore = getCpsTreasuryScore(); + callScore(cpsTreasuryScore, "sendInstallmentToContributor", _ipfs_hash, milestoneBudget); + //Request CPS Treasury to add some sponsor reward amount to the sponsor address + callScore(cpsTreasuryScore, "sendRewardToSponsor", _ipfs_hash, milestonePassed); + if (lastProgressReport && milestonePassed != milestoneSubmittedSize) { + updateProposalStatus(_ipfs_hash, _proposal_details); } } } + + } + + + private void updateProposalStatus(String _ipfs_hash, Map _proposal_details) { + String _proposal_status = (String) _proposal_details.get(STATUS); + Address _sponsor_address = (Address) _proposal_details.get(SPONSOR_ADDRESS); + Address _contributor_address = (Address) _proposal_details.get(CONTRIBUTOR_ADDRESS); + BigInteger _sponsor_deposit_amount = (BigInteger) _proposal_details.get(SPONSOR_DEPOSIT_AMOUNT); + String flag = (String) _proposal_details.get(TOKEN); + + String proposalPrefix = proposalPrefix(_ipfs_hash); + if (_proposal_status.equals(ACTIVE)) { + int project_duration = (int) _proposal_details.get(PROJECT_DURATION); + projectDuration.at(proposalPrefix).set(project_duration + 1); + updateProposalStatus(_ipfs_hash, PAUSED); + } else if (_proposal_status.equals(PAUSED)) { + updateProposalStatus(_ipfs_hash, DISQUALIFIED); + callScore(getCpsTreasuryScore(), "disqualifyProject", _ipfs_hash); + + removeContributor(_contributor_address, _ipfs_hash); + removeSponsor(_sponsor_address, _ipfs_hash); + + sponsorDepositStatus.at(proposalPrefix).set(BOND_CANCELLED); + +// Transferring the sponsor bond deposit to CPF after the project being disqualified + disqualifyProject(_sponsor_address, _sponsor_deposit_amount, flag); + } } /*** @@ -1369,14 +1481,14 @@ private void checkProgressReportSubmission() { String _proposal_status = (String) _proposal_details.get(STATUS); Address _sponsor_address = (Address) _proposal_details.get(SPONSOR_ADDRESS); Address _contributor_address = (Address) _proposal_details.get(CONTRIBUTOR_ADDRESS); - String flag = (String) _proposal_details.get("token"); + String flag = (String) _proposal_details.get(TOKEN); if (!ProposalDataDb.submitProgressReport.at(proposalPrefix).getOrDefault(Boolean.FALSE)) { if (_proposal_status.equals(ACTIVE)) { updateProposalStatus(_ipfs_hash, PAUSED); } else if (_proposal_status.equals(PAUSED)) { updateProposalStatus(_ipfs_hash, DISQUALIFIED); - callScore(getCpsTreasuryScore(), "disqualify_project", _ipfs_hash); + callScore(getCpsTreasuryScore(), "disqualifyProject", _ipfs_hash); removeContributor(_contributor_address, _ipfs_hash); @@ -1427,7 +1539,7 @@ private void updateBudgetAdjustments(String _budget_key) { // After the budget adjustment is approved, Request new added fund to CPF - callScore(getCpfTreasuryScore(), "update_proposal_fund", _ipfs_hash, token_flag, _additional_budget, _additional_duration); + callScore(getCpfTreasuryScore(), "updateProposalFund", _ipfs_hash, token_flag, _additional_budget, _additional_duration); } else { budgetAdjustmentStatus.at(_prefix).set(REJECTED); } @@ -1435,20 +1547,21 @@ private void updateBudgetAdjustments(String _budget_key) { private void updateProposalsResult() { BigInteger distributionAmount = getRemainingFund().get(bnUSD); - List proposals = sortPriorityProposals(); + List proposals = sortPriorityProposals(); // priority proposal mean? PReps pReps = new PReps(); for (String proposal : proposals) { Map proposalDetails = getProposalDetails(proposal); + Map proposalVoteDetails = getVoteResult(proposal); Address sponsorAddress = (Address) proposalDetails.get(SPONSOR_ADDRESS); Address contributorAddress = (Address) proposalDetails.get(CONTRIBUTOR_ADDRESS); BigInteger totalBudget = (BigInteger) proposalDetails.get(TOTAL_BUDGET); - int projectDuration = (int) proposalDetails.get(PROJECT_DURATION); + int projectDuration = (int) proposalDetails.get(MILESTONE_COUNT); BigInteger sponsorDepositAmount = (BigInteger) proposalDetails.get(SPONSOR_DEPOSIT_AMOUNT); - int approvedVoters = (int) proposalDetails.get(APPROVE_VOTERS); - BigInteger approvedVotes = (BigInteger) proposalDetails.get(APPROVED_VOTES); - BigInteger totalVotes = (BigInteger) proposalDetails.get(TOTAL_VOTES); - int totalVoters = (int) proposalDetails.get(TOTAL_VOTERS); + int approvedVoters = (int) proposalVoteDetails.get(APPROVE_VOTERS); + BigInteger approvedVotes = (BigInteger) proposalVoteDetails.get(APPROVED_VOTES); + BigInteger totalVotes = (BigInteger) proposalVoteDetails.get(TOTAL_VOTES); + int totalVoters = (int) proposalVoteDetails.get(TOTAL_VOTERS); String flag = (String) proposalDetails.get(TOKEN); String updatedStatus; String proposalPrefix = proposalPrefix(proposal); @@ -1464,14 +1577,14 @@ private void updateProposalsResult() { updatedStatus = REJECTED; } else if ((voters_ratio) >= MAJORITY && (approvedVotes.doubleValue() / totalVotes.doubleValue()) >= MAJORITY) { - if (totalBudget.multiply(BigInteger.valueOf(102)).divide(BigInteger.valueOf(100)). + if (totalBudget.multiply(BigInteger.valueOf(102)).divide(BigInteger.valueOf(100)). // total budget + 2% of sponsor compareTo(distributionAmount) < 0) { updateProposalStatus(proposal, ACTIVE); updatedStatus = ACTIVE; sponsors.add(sponsorAddress); sponsorProjects.at(sponsorAddress).add(proposal); ProposalDataDb.sponsorDepositStatus.at(proposalPrefix).set(BOND_APPROVED); - callScore(getCpfTreasuryScore(), "transfer_proposal_fund_to_cps_treasury", + callScore(getCpfTreasuryScore(), "transferProposalFundToCpsTreasury", proposal, projectDuration, sponsorAddress, contributorAddress, flag, totalBudget); distributionAmount = distributionAmount.subtract(totalBudget); @@ -1521,14 +1634,15 @@ private void updateProposalsResult() { } private void updateProposalStatus(String proposalHash, String propStatus) { + Status status = new Status(); String proposalPrefix = proposalPrefix(proposalHash); String currentStatus = ProposalDataDb.status.at(proposalPrefix).get(); ProposalDataDb.timestamp.at(proposalPrefix).set(BigInteger.valueOf(Context.getBlockTimestamp())); ProposalDataDb.status.at(proposalPrefix).set(propStatus); - ArrayDB proposalStatus = this.proposalStatus.get(currentStatus); + ArrayDB proposalStatus = status.proposalStatus.get(currentStatus); ArrayDBUtils.removeArrayItem(proposalStatus, proposalHash); - this.proposalStatus.get(propStatus).add(proposalHash); + status.proposalStatus.get(propStatus).add(proposalHash); } private void updateProgressReportStatus(String progressHash, String progressStatus) { @@ -1537,11 +1651,13 @@ private void updateProgressReportStatus(String progressHash, String progressStat ProgressReportDataDb.timestamp.at(progressPrefix).set(BigInteger.valueOf(Context.getBlockTimestamp())); ProgressReportDataDb.status.at(progressPrefix).set(progressStatus); - ArrayDB progressReportStatus = this.progressReportStatus.get(currentStatus); + Status status = new Status(); + ArrayDB progressReportStatus = status.progressReportStatus.get(currentStatus); ArrayDBUtils.removeArrayItem(progressReportStatus, progressHash); - this.progressReportStatus.get(progressStatus).add(progressHash); + status.progressReportStatus.get(progressStatus).add(progressHash); } + private void checkInactivePreps(ArrayDB
prepList) { PReps pReps = new PReps(); for (int i = 0; i < pReps.validPreps.size(); i++) { @@ -1588,29 +1704,45 @@ private void addNewProgressReportKey(String ipfsHash, String reportHash) { for (int i = startIndex; i < endIndex; i++) { String proposalKey = proposalKeys.get(i); - Map proposalDetails = getProposalDetails(proposalKey); - String propStatus = (String) proposalDetails.get(STATUS); - - if (status.equals(SPONSOR_PENDING)) { - Address wallet = (Address) proposalDetails.get(CONTRIBUTOR_ADDRESS); - if (wallet.equals(walletAddress)) { + Map proposalDetails = new HashMap<>(); + if (proposalKeyExists(proposalKey)) { + String proposalPrefix = proposalPrefix(proposalKey); + proposalDetails.put(IPFS_HASH, ProposalDataDb.ipfsHash.at(proposalPrefix).getOrDefault("")); + proposalDetails.put(PROJECT_TITLE, ProposalDataDb.projectTitle.at(proposalPrefix).getOrDefault("")); + proposalDetails.put(TOTAL_BUDGET, totalBudget.at(proposalPrefix).getOrDefault(BigInteger.ZERO)); + proposalDetails.put(TOKEN, token.at(proposalPrefix).getOrDefault("")); + proposalDetails.put(PERCENTAGE_COMPLETED, percentageCompleted.at(proposalPrefix).getOrDefault(0)); + + proposalDetails.put(TOTAL_VOTES, ProposalDataDb.totalVotes.at(proposalPrefix).getOrDefault(BigInteger.ZERO)); + proposalDetails.put(APPROVED_VOTES, ProposalDataDb.approvedVotes.at(proposalPrefix).getOrDefault(BigInteger.ZERO)); + proposalDetails.put(REJECTED_VOTES, ProposalDataDb.rejectedVotes.at(proposalPrefix).getOrDefault(BigInteger.ZERO)); + proposalDetails.put(ABSTAINED_VOTES, ProposalDataDb.abstainedVotes.at(proposalPrefix).getOrDefault(BigInteger.ZERO)); + + proposalDetails.put(APPROVE_VOTERS, ProposalDataDb.approveVoters.at(proposalPrefix).size()); + proposalDetails.put(REJECT_VOTERS, ProposalDataDb.rejectVoters.at(proposalPrefix).size()); + proposalDetails.put(ABSTAIN_VOTERS, abstainVoters.at(proposalPrefix).size()); + proposalDetails.put(TOTAL_VOTERS, ProposalDataDb.totalVoters.at(proposalPrefix).getOrDefault(0)); + + String propStatus = ProposalDataDb.status.at(proposalPrefix).getOrDefault(""); + proposalDetails.put(STATUS, propStatus); + + if (status.equals(SPONSOR_PENDING)) { + Address wallet = contributorAddress.at(proposalPrefix).get(); + if (wallet.equals(walletAddress)) { + proposalsList.add(proposalDetails); + } + } else if (propStatus.equals(status)) { proposalsList.add(proposalDetails); } - } else if (propStatus.equals(status)) { - proposalsList.add(proposalDetails); - } + } } return Map.of(DATA, proposalsList, COUNT, count); } - @Deprecated(since = "JAVA translation", forRemoval = true) - @External(readonly = true) - public Map get_proposal_details(String _status, @Optional Address _wallet_address, @Optional int _start_index) { - return getProposalDetails(_status, _wallet_address, _start_index); - } + @Override @External(readonly = true) public Map getProposalDetailsByHash(String ipfsKey) { Map proposalDetails = new HashMap<>(); @@ -1620,17 +1752,26 @@ public Map getProposalDetailsByHash(String ipfsKey) { return proposalDetails; } - @Override - @Deprecated(since = "JAVA translation", forRemoval = true) - @External(readonly = true) - public Map get_proposal_details_by_hash(String _ipfs_key) { - return getProposalDetailsByHash(_ipfs_key); - } private Map getProgressReportDetails(String progressKey) { return getDataFromProgressReportDB(progressReportPrefix(progressKey)); } + @External(readonly = true) + public List getMilestoneCountOfProgressReport(String progressKey) { + return getMilestoneSubmittedFromProgressReportDB(progressReportPrefix(progressKey)); + } + + @External(readonly = true) + public Map getProgressReportVoteDetails(String progressKey) { + return getVoteResultsFromProgressReportDB(progressReportPrefix(progressKey)); + } + + @External(readonly = true) + public Map getBudgetAdjustmentDetails(String progressKey) { + return getBudgetAdjustmentDetailsFromDB(progressReportPrefix(progressKey)); + } + @Override @External(readonly = true) public Map getProgressReports(String status, @Optional int startIndex) { @@ -1639,7 +1780,8 @@ private Map getProgressReportDetails(String progressKey) { } List progressReportList = new ArrayList<>(); - ArrayDB progressReportKeys = this.progressReportStatus.get(status); + Status _status = new Status(); + ArrayDB progressReportKeys = _status.progressReportStatus.get(status); if (startIndex < 0) { startIndex = 0; @@ -1663,12 +1805,6 @@ private Map getProgressReportDetails(String progressKey) { return Map.of(DATA, progressReportList, COUNT, progressReportList.size()); } - @Deprecated(since = "JAVA translation", forRemoval = true) - @External(readonly = true) - public Map get_progress_reports(String _status, @Optional int _start_index) { - return getProgressReports(_status, _start_index); - } - /*** Returns all the progress reports for a specific project :param _report_key : project key i.e. progress report ipfs hash @@ -1676,23 +1812,43 @@ private Map getProgressReportDetails(String progressKey) { :return : List of all progress report with status :rtype : dict ***/ + @Override @External(readonly = true) public Map getProgressReportsByHash(String reportKey) { if (progressKeyExists(reportKey)) { - return getProgressReportDetails(reportKey); + Map finalDetail = new HashMap<>(); + Map progressReportDetails = getProgressReportDetails(reportKey); + finalDetail.putAll(progressReportDetails); + boolean hasMilestone = false; + int milestoneSubmittedSize = (int) progressReportDetails.get(MILESTONE_SUBMITTED_COUNT); + if (milestoneSubmittedSize > 0) { + hasMilestone = true; + } + finalDetail.put("isMilestone", hasMilestone); + if (hasMilestone) { + List milestoneSubmittedList = getMilestoneCountOfProgressReport(reportKey); + finalDetail.put("milestoneId", milestoneSubmittedList); + } else { + finalDetail.putAll(getProgressReportVoteDetails(reportKey)); + } + + return finalDetail; } return Map.of(); - - } - @Override - @Deprecated(since = "JAVA translation", forRemoval = true) - @External(readonly = true) - public Map get_progress_reports_by_hash(String _report_key) { - return getProgressReportsByHash(_report_key); + private Map getMilestoneReport(String reportKey, String ipfsHash) { + Map milestoneReport = new HashMap<>(); + ArrayDB mileSubmitted = milestoneSubmitted.at(progressReportPrefix(reportKey)); + for (int i = 0; i < mileSubmitted.size(); i++) { + int count = mileSubmitted.get(i); + milestoneReport.put("milestone_" + count, getMilestonesReport(ipfsHash, count)); + } + return milestoneReport; } + + @Override @External(readonly = true) public Map getProgressReportsByProposal(String ipfsKey) { String proposalPrefix = proposalPrefix(ipfsKey); @@ -1700,19 +1856,14 @@ public Map getProgressReportsByProposal(String ipfsKey) { List> progressReportList = new ArrayList<>(); - for (int i = 0; i < reportKeys.size(); i++) { - Map progressReportDetails = this.getProgressReportDetails(reportKeys.get(i)); + int reportCount = reportKeys.size(); + for (int i = 0; i < reportCount; i++) { + Map progressReportDetails = this.getProgressReportsByHash(reportKeys.get(i)); progressReportList.add(progressReportDetails); } - return Map.of(DATA, progressReportList, COUNT, progressReportList.size()); + return Map.of(DATA, progressReportList, COUNT, reportCount); } - @Override - @Deprecated(since = "JAVA translation", forRemoval = true) - @External(readonly = true) - public Map get_progress_reports_by_proposal(String _ipfs_key) { - return getProgressReportsByProposal(_ipfs_key); - } @Override @External(readonly = true) @@ -1751,7 +1902,8 @@ public Map getSponsorsRequests(String status, Address sponsorAdd endIndex = count; } - BigInteger sponsorAmountICX = BigInteger.ZERO, sponsorAmountBnusd = BigInteger.ZERO; + BigInteger sponsorAmountICX = BigInteger.ZERO; + BigInteger sponsorAmountBnusd = BigInteger.ZERO; for (int i = startIndex; i < endIndex; i++) { String proposalKey = proposalKeys.get(i); @@ -1774,30 +1926,25 @@ public Map getSponsorsRequests(String status, Address sponsorAdd SPONSOR_DEPOSIT_AMOUNT, Map.of(ICX, sponsorAmountICX, bnUSD, sponsorAmountBnusd)); } - @Deprecated(since = "JAVA translation", forRemoval = true) - @External(readonly = true) - public Map get_sponsors_requests(String _status, Address _sponsor_address, @Optional int _start_index) { - return getSponsorsRequests(_status, _sponsor_address, _start_index); - } /*** Returns remaining projects and progress reports to vote on the current voting period - :param _project_type: "proposal" or "progress_report" which type, remaining votes need to be checked - :type _project_type: str - :param _wallet_address: Wallet Address of the P-Rep - :type _wallet_address: str + :param projectType: "proposal" or "progress_report" which type, remaining votes need to be checked + :type projectType: str + :param walletAddress: Wallet Address of the P-Rep + :type walletAddress: str :return: list of details of proposal or progress report what they need to vote on the same voting period ***/ @External(readonly = true) - public List> get_remaining_project(String _project_type, Address _wallet_address) { + public List> getRemainingProject(String projectType, Address walletAddress) { List> _remaining_proposals = new ArrayList<>(); List> _remaining_progress_report = new ArrayList<>(); - if (_project_type.equals(PROPOSAL)) { + if (projectType.equals(PROPOSAL)) { List _proposal_keys = getProposalsKeysByStatus(PENDING); for (String _ipfs_key : _proposal_keys) { String prefix = proposalPrefix(_ipfs_key); - if (!containsInArrayDb(_wallet_address, ProposalDataDb.votersList.at(prefix))) { + if (!containsInArrayDb(walletAddress, ProposalDataDb.votersList.at(prefix))) { Map _proposal_details = getProposalDetails(_ipfs_key); _remaining_proposals.add(_proposal_details); } @@ -1805,14 +1952,39 @@ public List> get_remaining_project(String _project_type, Add return _remaining_proposals; } - if (_project_type.equals(PROGRESS_REPORTS)) { - for (int i = 0; i < waitingProgressReports.size(); i++) { - String reportHash = waitingProgressReports.get(i); + Status status = new Status(); + if (projectType.equals(PROGRESS_REPORTS)) { + for (int i = 0; i < status.waitingProgressReports.size(); i++) { + String reportHash = status.waitingProgressReports.get(i); String prefix = progressReportPrefix(reportHash); - if (!containsInArrayDb(_wallet_address, ProgressReportDataDb.votersList.at(prefix))) { - Map progressReportDetails = getProgressReportDetails(reportHash); - _remaining_progress_report.add(progressReportDetails); + String ipfsHash = ProgressReportDataDb.ipfsHash.at(prefix).get(); + int milestoneCount = getMilestoneCount(ipfsHash); + + if (milestoneCount > 0) { + + ArrayDB milestoneSubmittedOf = milestoneSubmitted.at(prefix); + + for (int j = 0; j < milestoneSubmittedOf.size(); j++) { + int milestoneID = milestoneSubmittedOf.get(j); + String milestonePrefix = mileStonePrefix(ipfsHash, milestoneID); + + ArrayDB
voterList = MilestoneDb.votersList.at(milestonePrefix); + if (!containsInArrayDb(walletAddress, voterList)) { + Map progressReportDetails = new HashMap<>(); + progressReportDetails.putAll(getProgressReportDetails(reportHash)); + progressReportDetails.putAll(getMilestoneReport(reportHash, ipfsHash)); + _remaining_progress_report.add(progressReportDetails); + } + } + + } else { + if (!containsInArrayDb(walletAddress, ProgressReportDataDb.votersList.at(prefix))) { + Map progressReportDetails = new HashMap<>(); + progressReportDetails.putAll(getProgressReportDetails(reportHash)); + progressReportDetails.putAll(getVoteResultsFromProgressReportDB(prefix)); + _remaining_progress_report.add(progressReportDetails); + } } } return _remaining_progress_report; @@ -1828,6 +2000,7 @@ public List> get_remaining_project(String _project_type, Add :return: Vote status of given _ipfs_key :rtype : dict ***/ + @Override @External(readonly = true) public Map getVoteResult(String ipfsKey) { String prefix = proposalPrefix(ipfsKey); @@ -1835,6 +2008,7 @@ public Map getVoteResult(String ipfsKey) { ArrayDB
_voters_list = ProposalDataDb.votersList.at(prefix); ArrayDB
approve_voters = ProposalDataDb.approveVoters.at(prefix); ArrayDB
reject_voters = ProposalDataDb.rejectVoters.at(prefix); + ArrayDB
abstain_voters = ProposalDataDb.abstainVoters.at(prefix); List> _vote_status = new ArrayList<>(); String vote; for (int i = 0; i < _voters_list.size(); i++) { @@ -1862,19 +2036,130 @@ PREP_NAME, getPrepName(voter), return Map.of(DATA, _vote_status, APPROVE_VOTERS, approve_voters.size(), REJECT_VOTERS, reject_voters.size(), + ABSTAIN_VOTERS, abstain_voters.size(), TOTAL_VOTERS, ProposalDataDb.totalVoters.at(prefix).getOrDefault(0), APPROVED_VOTES, ProposalDataDb.approvedVotes.at(prefix).getOrDefault(BigInteger.ZERO), REJECTED_VOTES, ProposalDataDb.rejectedVotes.at(prefix).getOrDefault(BigInteger.ZERO), + ABSTAINED_VOTES, ProposalDataDb.abstainedVotes.at(prefix).getOrDefault(BigInteger.ZERO), TOTAL_VOTES, ProposalDataDb.totalVotes.at(prefix).getOrDefault(BigInteger.ZERO)); } - @Override + // a different method for get milestone report @External(readonly = true) - @Deprecated(since = "JAVA translation", forRemoval = true) - public Map get_vote_result(String _ipfs_key) { - return getVoteResult(_ipfs_key); + public Map getMilestoneVoteResult(String reportKey, int milestoneId) { + String prefix = progressReportPrefix(reportKey); + String ipfshHash = ProgressReportDataDb.ipfsHash.at(prefix).get(); + List milestoneSubmitted = getMilestoneCountOfProgressReport(reportKey); + if (milestoneSubmitted.contains(milestoneId)) { + + String milestonePrefix = mileStonePrefix(ipfshHash, milestoneId); + ArrayDB
_voters_list = MilestoneDb.votersList.at(milestonePrefix); + ArrayDB
_approved_voters_list = MilestoneDb.approveVoters.at(milestonePrefix); + ArrayDB
_rejected_voters_list = MilestoneDb.rejectVoters.at(milestonePrefix); + + List> _vote_status = new ArrayList<>(); + String vote; +// Differentiating the P-Rep(s) votes according to their votes + for (int i = 0; i < _voters_list.size(); i++) { + Address voter = _voters_list.get(i); + if (containsInArrayDb(voter, _approved_voters_list)) { + vote = APPROVE; + } else if (containsInArrayDb(voter, _rejected_voters_list)) { + vote = REJECT; + } else { + vote = "not voted"; + } + String reason = ProgressReportDataDb.votersReasons.at(prefix).get(i); + if (reason == null) { + reason = ""; + } + Map _voters = Map.of(ADDRESS, voter, + PREP_NAME, getPrepName(voter), + VOTE_REASON, reason, + VOTE, vote); + _vote_status.add(_voters); + } + + return Map.of(DATA, _vote_status, APPROVE_VOTERS, _approved_voters_list.size(), + REJECT_VOTERS, _rejected_voters_list.size(), + TOTAL_VOTERS, ProgressReportDataDb.totalVoters.at(prefix).getOrDefault(0), + APPROVED_VOTES, MilestoneDb.approvedVotes.at(milestonePrefix).getOrDefault(BigInteger.ZERO), + REJECTED_VOTES, MilestoneDb.rejectedVotes.at(milestonePrefix).getOrDefault(BigInteger.ZERO), + TOTAL_VOTES, ProgressReportDataDb.totalVotes.at(prefix).getOrDefault(BigInteger.ZERO)); + } + return Map.of(); + } + + + @External(readonly = true) + public Map getProgressReportVoters(String reportKey) { + String prefix = progressReportPrefix(reportKey); + String ipfsHash = ProgressReportDataDb.ipfsHash.at(prefix).get(); + int milestoneCount = getMilestoneCount(ipfsHash); + List> voteStatus = new ArrayList<>(); + String vote; + if (milestoneCount > 0) { + + ArrayDB milestoneSubmittedOf = milestoneSubmitted.at(prefix); + + for (int i = 0; i < milestoneSubmittedOf.size(); i++) { + int milestoneID = milestoneSubmittedOf.get(i); + String milestonePrefix = mileStonePrefix(ipfsHash, milestoneID); + + ArrayDB
voterList = MilestoneDb.votersList.at(milestonePrefix); + ArrayDB
approvedVoterList = MilestoneDb.approveVoters.at(milestonePrefix); + ArrayDB
rejectedVoterList = MilestoneDb.rejectVoters.at(milestonePrefix); + + for (int j = 0; j < voterList.size(); j++) { + Address voter = voterList.get(j); + + if (containsInArrayDb(voter, approvedVoterList)) { + vote = APPROVE; + } else if (containsInArrayDb(voter, rejectedVoterList)) { + vote = REJECT; + } else { + vote = "not voted"; + } + String reason = ProgressReportDataDb.votersReasons.at(prefix).get(j); + if (reason == null) { + reason = ""; + } + Map voters = Map.of(ADDRESS, voter, + PREP_NAME, getPrepName(voter), + VOTE_REASON, reason, + VOTE, vote, + MILESTONE_ID, milestoneID); + voteStatus.add(voters); + } + } + } else { + ArrayDB
voterList = ProgressReportDataDb.votersList.at(prefix); + ArrayDB
approvedVoterList = ProgressReportDataDb.approveVoters.at(prefix); + ArrayDB
rejectedVoterList = ProgressReportDataDb.rejectVoters.at(prefix); + for (int i = 0; i < voterList.size(); i++) { + Address voter = voterList.get(i); + if (containsInArrayDb(voter, approvedVoterList)) { + vote = APPROVE; + } else if (containsInArrayDb(voter, rejectedVoterList)) { + vote = REJECT; + } else { + vote = "not voted"; + } + String reason = ProgressReportDataDb.votersReasons.at(prefix).get(i); + if (reason == null) { + reason = ""; + } + Map voters = Map.of(ADDRESS, voter, + PREP_NAME, getPrepName(voter), + VOTE_REASON, reason, + VOTE, vote); + voteStatus.add(voters); + } + } + return Map.of(DATA, voteStatus); } + /*** Get vote results by progress report :param reportKey : progress report ipfs key @@ -1882,52 +2167,53 @@ public Map get_vote_result(String _ipfs_key) { :return: Vote status of given reportKey :rtype : dict ***/ + @Override @External(readonly = true) public Map getProgressReportResult(String reportKey) { + String prefix = progressReportPrefix(reportKey); + String ipfsHash = ProgressReportDataDb.ipfsHash.at(prefix).get(); + boolean hasMilestone = isMilestone.at(proposalPrefix(ipfsHash)).getOrDefault(false); + if (hasMilestone) { + List milestoneSubmittedList = getMilestoneCountOfProgressReport(reportKey); - ArrayDB
_voters_list = ProgressReportDataDb.votersList.at(prefix); - ArrayDB
_approved_voters_list = ProgressReportDataDb.approveVoters.at(prefix); - ArrayDB
_rejected_voters_list = ProgressReportDataDb.rejectVoters.at(prefix); - List> _vote_status = new ArrayList<>(); - String vote; -// Differentiating the P-Rep(s) votes according to their votes - for (int i = 0; i < _voters_list.size(); i++) { - Address voter = _voters_list.get(i); - if (containsInArrayDb(voter, _approved_voters_list)) { - vote = APPROVE; - } else if (containsInArrayDb(voter, _rejected_voters_list)) { - vote = REJECT; - } else { - vote = "not voted"; - } - String reason = ProgressReportDataDb.votersReasons.at(prefix).get(i); - if (reason == null) { - reason = ""; - } - Map _voters = Map.of(ADDRESS, voter, - PREP_NAME, getPrepName(voter), - VOTE_REASON, reason, - VOTE, vote); - _vote_status.add(_voters); + return Map.of( + TOTAL_VOTERS, ProgressReportDataDb.totalVoters.at(prefix).getOrDefault(0), + TOTAL_VOTES, ProgressReportDataDb.totalVotes.at(prefix).getOrDefault(BigInteger.ZERO), + MILESTONE_ID, milestoneSubmittedList, + IS_MILESTONE, hasMilestone); } - - return Map.of(DATA, _vote_status, APPROVE_VOTERS, _approved_voters_list.size(), - REJECT_VOTERS, _rejected_voters_list.size(), + return Map.of(APPROVE_VOTERS, ProgressReportDataDb.approveVoters.at(prefix).size(), + REJECT_VOTERS, ProgressReportDataDb.rejectVoters.at(prefix).size(), TOTAL_VOTERS, ProgressReportDataDb.totalVoters.at(prefix).getOrDefault(0), APPROVED_VOTES, ProgressReportDataDb.approvedVotes.at(prefix).getOrDefault(BigInteger.ZERO), REJECTED_VOTES, ProgressReportDataDb.rejectedVotes.at(prefix).getOrDefault(BigInteger.ZERO), - TOTAL_VOTES, ProgressReportDataDb.totalVotes.at(prefix).getOrDefault(BigInteger.ZERO)); + TOTAL_VOTES, ProgressReportDataDb.totalVotes.at(prefix).getOrDefault(BigInteger.ZERO), + IS_MILESTONE, hasMilestone); } - @Override @External(readonly = true) - @Deprecated(since = "JAVA translation", forRemoval = true) - public Map get_progress_report_result(String _report_key) { - return getProgressReportResult(_report_key); + public Map getMilestonesReport(String ipfsKey, int milestoneId) { + String milestonePrefix = mileStonePrefix(ipfsKey, milestoneId); + return getDataFromMilestoneDB(milestonePrefix); + } + + @External(readonly = true) + public int getMilestoneCount(String ipfsHash) { + if (proposalKeyExists(ipfsHash)) { + return ProposalDataDb.getMilestoneCount(proposalPrefix(ipfsHash)); + } + return 0; + } + + @External(readonly = true) + public int getMileststoneStatusOf(String proposalKey, int milestoneId) { + String milestonePrefix = mileStonePrefix(proposalKey, milestoneId); + return MilestoneDb.status.at(milestonePrefix).getOrDefault(0); } + /*** Get budget adjustment vote results :param _report_key : progress report ipfs key @@ -1936,6 +2222,7 @@ public Map get_progress_report_result(String _report_key) { :rtype : dict ***/ + @Override @External(readonly = true) public Map getBudgetAdjustmentVoteResult(String reportKey) { String prefix = progressReportPrefix(reportKey); @@ -1969,48 +2256,40 @@ PREP_NAME, getPrepName(voter), TOTAL_VOTES, ProgressReportDataDb.totalVotes.at(prefix).getOrDefault(BigInteger.ZERO)); } - @Override - @External(readonly = true) - @Deprecated(since = "JAVA translation", forRemoval = true) - public Map get_budget_adjustment_vote_result(String _report_key) { - return getBudgetAdjustmentVoteResult(_report_key); - } - private void snapshotDelegation() { BigInteger maxDelegation = BigInteger.ZERO; PReps pReps = new PReps(); + BigInteger totalStake = BigInteger.ZERO; for (int i = 0; i < pReps.validPreps.size(); i++) { Address prep = pReps.validPreps.get(i); BigInteger stake = getStake(prep); delegationSnapshot.set(prep, stake); + totalStake = totalStake.add(stake); if (stake.compareTo(maxDelegation) > 0) { maxDelegation = stake; } } this.maxDelegation.set(maxDelegation); + this.totalDelegationSnapshot.set(totalStake); } private void updateApplicationResult() { PReps pReps = new PReps(); + Status status = new Status(); PeriodController period = new PeriodController(); if (pReps.validPreps.size() < MINIMUM_PREPS) { period.periodName.set(APPLICATION_PERIOD); PeriodUpdate("Period Updated back to Application Period due to less Registered P-Reps Count"); - } else if (getProposalsKeysByStatus(PENDING).size() == 0 && this.progressReportStatus.get(WAITING).size() == 0 && activeProposals.size() + paused.size() == 0) { - createActiveProposalDb(); - checkProgressReportSubmission(); - period.periodName.set(APPLICATION_PERIOD); - PeriodUpdate("Period Updated back to Application Period due not enough " + - "Voting Proposals or Progress Reports."); - } else if (pending.size() == 0 && waitingProgressReports.size() == 0 && activeProposals.size() + paused.size() > 0) { + } else if (getProposalsKeysByStatus(PENDING).size() == 0 && + status.progressReportStatus.get(WAITING).size() == 0 && + activeProposals.size() + status.paused.size() >= 0) { createActiveProposalDb(); checkProgressReportSubmission(); period.periodName.set(APPLICATION_PERIOD); PeriodUpdate("Period Updated back to Application Period due not enough " + "Voting Proposals or Progress Reports."); - } else { createActiveProposalDb(); PeriodUpdate("Period Updated to Voting Period"); @@ -2018,14 +2297,16 @@ private void updateApplicationResult() { } private void createActiveProposalDb() { - for (int i = 0; i < active.size(); i++) { - String proposal = active.get(i); + clearArrayDb(activeProposals); + Status status = new Status(); + for (int i = 0; i < status.active.size(); i++) { + String proposal = status.active.get(i); if (!ArrayDBUtils.containsInArrayDb(proposal, activeProposals)) { activeProposals.add(proposal); } } - for (int i = 0; i < paused.size(); i++) { - String proposal = paused.get(i); + for (int i = 0; i < status.paused.size(); i++) { + String proposal = status.paused.get(i); if (!ArrayDBUtils.containsInArrayDb(proposal, activeProposals)) { activeProposals.add(proposal); } @@ -2056,21 +2337,21 @@ private void payPrepPenalty(Address from, BigInteger _value) { @Override @External - public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { + public void tokenFallback(Address from, BigInteger value, byte[] data) { Context.require(Context.getCaller().equals(getBnusdScore()), TAG + " Only bnUSD token accepted."); - String unpacked_data = new String(_data); + String unpacked_data = new String(data); JsonObject transferData = Json.parse(unpacked_data).asObject(); - String methodName = transferData.get("method").asString(); + String methodName = transferData.get(METHOD).asString(); JsonObject paramsName = transferData.get("params").asObject(); - if (methodName.equals("sponsor_vote")) { + if (methodName.equals("sponsorVote")) { String ipfsKey = paramsName.get(IPFS_HASH).asString(); String vote = paramsName.get(VOTE).asString(); String voteReason = paramsName.get(VOTE_REASON).asString(); - sponsorVote(ipfsKey, vote, voteReason, _from, _value); - } else if (methodName.equals("pay_prep_penalty")) { - payPrepPenalty(_from, _value); + sponsorVote(ipfsKey, vote, voteReason, from, value); + } else if (methodName.equals("payPrepPenalty")) { + payPrepPenalty(from, value); } else { Context.revert(TAG + " Not supported method. Token transfer fails."); @@ -2105,8 +2386,8 @@ private void sponsorVote(String ipfsKey, String vote, String voteReason, Address BigInteger projectBudget = (BigInteger) proposalDetails.get(TOTAL_BUDGET); - Context.require(value.equals(projectBudget.divide(BigInteger.TEN)), - TAG + ": Deposit 10% of the total budget of the project."); + Context.require(value.equals(projectBudget.multiply(getSponsorBondPercentage()).divide(HUNDRED)), + TAG + ": Deposit " + getSponsorBondPercentage() + "% of the total budget of the project."); updateProposalStatus(ipfsKey, PENDING); String proposalPrefix = proposalPrefix(ipfsKey); @@ -2114,6 +2395,7 @@ private void sponsorVote(String ipfsKey, String vote, String voteReason, Address sponsoredTimestamp.at(proposalPrefix).set(BigInteger.valueOf(Context.getBlockTimestamp())); sponsorDepositStatus.at(proposalPrefix).set(BOND_RECEIVED); sponsorVoteReason.at(proposalPrefix).set(voteReason); + proposalPeriod.at(proposalPrefix).set(getPeriodCount()); SponsorBondReceived(from, "Sponsor Bond " + value + " " + token + " Received."); } else { @@ -2128,23 +2410,20 @@ private void sponsorVote(String ipfsKey, String vote, String voteReason, Address } } + @Override @External public void removeDenylistPreps() { validateAdmins(); PReps pReps = new PReps(); - for (int i = 0; i < pReps.denylist.size(); i++) { + int size = pReps.denylist.size(); + for (int i = 0; i < size; i++) { Address prep = pReps.denylist.pop(); pReps.prepsDenylistStatus.set(prep.toString(), 0); } } - @Override - @External - @Deprecated(since = "JAVA translation", forRemoval = true) - public void remove_denylist_preps() { - removeDenylistPreps(); - } + @Override @External public void claimSponsorBond() { Address caller = Context.getCaller(); @@ -2159,29 +2438,24 @@ public void claimSponsorBond() { } else if (amountBNUsd.compareTo(BigInteger.ZERO) > 0) { userAmounts.set(bnUSD, BigInteger.ZERO); - callScore(getBnusdScore(), "transfer", caller, amountBNUsd); + callScore(getBnusdScore(), TRANSFER, caller, amountBNUsd); SponsorBondClaimed(caller, amountIcx, amountBNUsd + " " + bnUSD + " withdrawn to " + caller); } else { Context.revert(TAG + " Claim Reward Fails. Available Amounts are " + amountIcx + " " + ICX + " and" + amountBNUsd + " " + bnUSD); } } - @Override - @External - @Deprecated(since = "JAVA translation", forRemoval = true) - public void claim_sponsor_bond() { - claimSponsorBond(); - } private void swapBNUsdToken() { BigInteger sbh = swapBlockHeight.getOrDefault(BigInteger.ZERO); BigInteger currentBlock = BigInteger.valueOf(Context.getBlockHeight()); if (sbh.compareTo(currentBlock) < 0) { swapBlockHeight.set(currentBlock.add(SWAP_BLOCK_DIFF)); - callScore(getCpfTreasuryScore(), "swap_tokens", swapCount.getOrDefault(0)); + callScore(getCpfTreasuryScore(), "swapTokens", swapCount.getOrDefault(0)); } } + @Override @External public void setSwapCount(int value) { validateAdmins(); @@ -2192,12 +2466,6 @@ public void setSwapCount(int value) { } } - @Override - @External - @Deprecated(since = "JAVA translation", forRemoval = true) - public void set_swap_count(int value) { - setSwapCount(value); - } @External(readonly = true) public int getSwapCount() { @@ -2215,12 +2483,12 @@ public void updateNextBlock(int blockCount) { private void disqualifyProject(Address sponsorAddress, BigInteger sponsorDepositAmount, String flag) { Context.require(flag.equals(bnUSD), TAG + " Not supported Token"); JsonObject disqualifyProject = new JsonObject(); - disqualifyProject.add("method", "burn_amount"); + disqualifyProject.add(METHOD, "returnFundAmount"); JsonObject params = new JsonObject(); params.add(SPONSOR_ADDRESS, sponsorAddress.toString()); disqualifyProject.add("params", params); Address cpfScore = getCpfTreasuryScore(); - callScore(getBnusdScore(), "transfer", cpfScore, + callScore(getBnusdScore(), TRANSFER, cpfScore, sponsorDepositAmount, disqualifyProject.toString().getBytes()); SponsorBondReturned(cpfScore, "Project Disqualified. " + sponsorDepositAmount + " " + flag + " returned to CPF Treasury Address."); @@ -2243,14 +2511,19 @@ public Map getActiveProposalsList(@Optional int startIndex) { } for (int i = startIndex; i < endIndex; i++) { - Map proposalDetails = getProposalDetails(proposalKeys.get(i)); + String proposalHash = proposalKeys.get(i); + String proposalPrefix = proposalPrefix(proposalHash); + Address contributorAddr = contributorAddress.at(proposalPrefix).get(); + Map proposalDetails = Map.of(PROJECT_TITLE, projectTitle.at(proposalPrefix).getOrDefault(""), + IPFS_HASH, proposalHash, + CONTRIBUTOR_ADDRESS, contributorAddr); activeProposalsList.add(proposalDetails); } return Map.of(DATA, activeProposalsList, COUNT, size); } /*** - Returns the list of all all active or paused proposal from that address + Returns the list of all active or paused proposal from that address :param walletAddress : wallet address of the contributor :type walletAddress: Address :return: list of active proposals of a contributor @@ -2265,13 +2538,14 @@ public List> getActiveProposals(Address walletAddress) { String prefix = proposalPrefix(proposals); String status = ProposalDataDb.status.at(prefix).getOrDefault(""); if (ArrayDBUtils.containsInList(status, List.of(ACTIVE, PAUSED))) { - int _project_duration = projectDuration.at(prefix).getOrDefault(0); - int _approved_reports_count = approvedReports.at(prefix).getOrDefault(0); - boolean _last_progress_report = _project_duration - _approved_reports_count == 1; + int projectDuration = ProposalDataDb.projectDuration.at(prefix).getOrDefault(0); + int proposalPeriod = ProposalDataDb.proposalPeriod.at(prefix).getOrDefault(0); + boolean lastProgressReport = proposalPeriod + projectDuration - getPeriodCount() == 0; Map _proposals_details = Map.of(PROJECT_TITLE, projectTitle.at(prefix).getOrDefault(""), IPFS_HASH, proposals, NEW_PROGRESS_REPORT, submitProgressReport.at(prefix).getOrDefault(false), - "last_progress_report", _last_progress_report); + "last_progress_report", lastProgressReport, + "milestoneDeadlines", getMilestoneDeadline(proposals)); _proposal_titles.add(_proposals_details); } } @@ -2279,12 +2553,6 @@ public List> getActiveProposals(Address walletAddress) { return _proposal_titles; } - @Deprecated(since = "JAVA translation", forRemoval = true) - @External(readonly = true) - public List> get_active_proposals(Address _wallet_address) { - return getActiveProposals(_wallet_address); - } - /*** Returns a dict of proposals of provided status @@ -2309,10 +2577,6 @@ public Map getProposalDetailByWallet(Address walletAddress, @Opt return Map.of(DATA, _proposals_list, COUNT, size); } - @External(readonly = true) - public Map get_proposal_detail_by_wallet(Address _wallet_address, @Optional int startIndex) { - return getProposalDetailByWallet(_wallet_address, startIndex); - } @Override @External(readonly = true) @@ -2340,8 +2604,46 @@ public Map getProposalsHistory(@Optional int startIndex) { return Map.of(DATA, proposalHistory, COUNT, size); } + // =====================================TEMPORARY MIGRATIONS METHODS=============================================== + + @External + public void updateProposalPeriodCount(String newHash, int count) { + validateAdmins(); + String newIpfsHashPrefix = proposalPrefix(newHash); + proposalPeriod.at(newIpfsHashPrefix).set(count); + } + + @External + public void updateMilestoneDb(String progressHash, int MilestoneId) { + validateAdmins(); + ArrayDB milestoneSize = milestoneSubmitted.at(progressReportPrefix(progressHash)); + ArrayDBUtils.removeArrayItem(milestoneSize, MilestoneId); + } + + + @External + public void milestoneDbMigration(String ipfsHash) { + validateAdmins(); + String proposalPrefix = proposalPrefix(ipfsHash); + ArrayDB milestoneId = milestoneIds.at(proposalPrefix); + int size = milestoneId.size(); + for (int i = 0; i < size; i++) { + String migration_milestonePrefix = mileStonePrefix(proposalPrefix, milestoneId.get(i)); + String actual_milestonePrefix = mileStonePrefix(ipfsHash, milestoneId.get(i)); - // EventLogs + MilestonesAttributes milestonesAttributes = new MilestonesAttributes(); + milestonesAttributes.id = MilestoneDb.id.at(migration_milestonePrefix).get(); + milestonesAttributes.budget = MilestoneDb.budget.at(migration_milestonePrefix).get(); + milestonesAttributes.completionPeriod = MilestoneDb.completionPeriod.at(migration_milestonePrefix).get(); + addDataToMilestoneDb(milestonesAttributes, actual_milestonePrefix); + + } + } + + + // =====================================TEMPORARY MIGRATIONS METHODS=============================================== + + // =====================================EventLogs=============================================== @Override @EventLog(indexed = 1) public void ProposalSubmitted(Address _sender_address, String note) { @@ -2402,11 +2704,16 @@ public void SponsorBondClaimed(Address _receiver_address, BigInteger _fund, Stri public void PriorityVote(Address _address, String note) { } + @Override @EventLog(indexed = 1) public void UpdateContributor(Address _old, Address _new) { } + // =====================================EventLogs=============================================== + + // =====================================CallScore Methods=============================================== + public T callScore(Class t, Address address, String method, Object... params) { return Context.call(t, address, method, params); } @@ -2419,6 +2726,10 @@ public void callScore(BigInteger amount, Address address, String method, Object. Context.call(amount, address, method, params); } + // =====================================CallScore Methods=============================================== + + + // =====================================Checkers=============================================== public void validateAdmins() { Context.require(isAdmin(Context.getCaller()), @@ -2431,4 +2742,10 @@ public void validateAdminScore(Address scoreAddress) { Context.require(scoreAddress.isContract(), scoreAddress + " is not a SCORE Address"); } + + public void onlyCPFTreasury() { + Context.require(Context.getCaller().equals(getCpfTreasuryScore()), TAG + ": Only CPF treasury can call this method"); + } + + // =====================================Checkers=============================================== } \ No newline at end of file diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/Status.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/Status.java new file mode 100644 index 00000000..3b9e393b --- /dev/null +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/Status.java @@ -0,0 +1,46 @@ +package community.icon.cps.score.cpscore; + +import score.ArrayDB; +import score.Context; + +import java.util.Map; + +import static community.icon.cps.score.cpscore.utils.Constants.ACTIVE; +import static community.icon.cps.score.cpscore.utils.Constants.APPROVED; +import static community.icon.cps.score.cpscore.utils.Constants.COMPLETED; +import static community.icon.cps.score.cpscore.utils.Constants.DISQUALIFIED; +import static community.icon.cps.score.cpscore.utils.Constants.PAUSED; +import static community.icon.cps.score.cpscore.utils.Constants.PENDING; +import static community.icon.cps.score.cpscore.utils.Constants.PROGRESS_REPORT_REJECTED; +import static community.icon.cps.score.cpscore.utils.Constants.REJECTED; +import static community.icon.cps.score.cpscore.utils.Constants.SPONSOR_PENDING; +import static community.icon.cps.score.cpscore.utils.Constants.WAITING; + +public class Status { + + public final ArrayDB sponsorPending = Context.newArrayDB(SPONSOR_PENDING, String.class); + public final ArrayDB pending = Context.newArrayDB(PENDING, String.class); + public final ArrayDB active = Context.newArrayDB(ACTIVE, String.class); + public final ArrayDB paused = Context.newArrayDB(PAUSED, String.class); + public final ArrayDB completed = Context.newArrayDB(COMPLETED, String.class); + // TODO : find use case for this + public final ArrayDB rejected = Context.newArrayDB(REJECTED, String.class); + public final ArrayDB disqualified = Context.newArrayDB(DISQUALIFIED, String.class); + public final Map> proposalStatus = Map.of(SPONSOR_PENDING, sponsorPending, + PENDING, pending, + ACTIVE, active, + PAUSED, paused, + COMPLETED, completed, + REJECTED, rejected, + DISQUALIFIED, disqualified); + + + public final ArrayDB waitingProgressReports = Context.newArrayDB(WAITING, String.class); + public final ArrayDB approvedProgressReports = Context.newArrayDB(APPROVED, String.class); + public final ArrayDB progressRejected = Context.newArrayDB(PROGRESS_REPORT_REJECTED, String.class); + public final Map> progressReportStatus = Map.of(WAITING, waitingProgressReports, + APPROVED, approvedProgressReports, + PROGRESS_REPORT_REJECTED, progressRejected + ); + +} diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/db/MilestoneDb.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/db/MilestoneDb.java new file mode 100644 index 00000000..4fe94274 --- /dev/null +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/db/MilestoneDb.java @@ -0,0 +1,55 @@ +package community.icon.cps.score.cpscore.db; + +import community.icon.cps.score.lib.interfaces.CPSCoreInterface; +import score.*; + +import java.math.BigInteger; +import java.util.Map; + +import static community.icon.cps.score.cpscore.utils.Constants.*; + +public class MilestoneDb { + public static final BranchDB> id = Context.newBranchDB(MILESTONE_ID, Integer.class); + public static final BranchDB> progressReportHash = Context.newBranchDB(REPORT_HASH, String.class); + public static final BranchDB> status = Context.newBranchDB(STATUS, Integer.class); + public static final BranchDB> approvedVotes = Context.newBranchDB(APPROVED_VOTES, BigInteger.class); + public static final BranchDB> rejectedVotes = Context.newBranchDB(REJECTED_VOTES, BigInteger.class); + public static final BranchDB> votersList = Context.newBranchDB(VOTERS_LIST, Address.class); + public static final BranchDB> approveVoters = Context.newBranchDB(APPROVE_VOTERS, Address.class); + public static final BranchDB> rejectVoters = Context.newBranchDB(REJECT_VOTERS, Address.class); + public static final BranchDB> completionPeriod = Context.newBranchDB(COMPLETION_PERIOD, Integer.class); + public static final BranchDB> budget = Context.newBranchDB(BUDGET, BigInteger.class); + public static final BranchDB> extensionFlag = Context.newBranchDB(EXTENSION_FLAG, Boolean.class); + + public static final BranchDB>> votersListIndices = Context.newBranchDB(VOTERS_LIST_INDEXES, Integer.class); + + public static void addDataToMilestoneDb(CPSCoreInterface.MilestonesAttributes milestoneData, String prefix) { + id.at(prefix).set(milestoneData.id); + approvedVotes.at(prefix).set(BigInteger.ZERO); + rejectedVotes.at(prefix).set(BigInteger.ZERO); + completionPeriod.at(prefix).set(milestoneData.completionPeriod); + budget.at(prefix).set(milestoneData.budget); + + } + + public static Map getDataFromMilestoneDB(String prefix) { + String reportHash = progressReportHash.at(prefix).getOrDefault(""); + return Map.ofEntries( + Map.entry(MILESTONE_ID, id.at(prefix).get()), + Map.entry(STATUS, status.at(prefix).getOrDefault(0)), + Map.entry(COMPLETION_PERIOD, completionPeriod.at(prefix).getOrDefault(0)), + Map.entry(BUDGET, budget.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(REPORT_HASH, progressReportHash.at(prefix).getOrDefault("")), + Map.entry(TOTAL_VOTES, ProgressReportDataDb.totalVotes.at(progressReportPrefix(reportHash)).getOrDefault(BigInteger.ZERO)), + Map.entry(APPROVED_VOTES, approvedVotes.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(REJECTED_VOTES, rejectedVotes.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(TOTAL_VOTERS, ProgressReportDataDb.totalVoters.at(progressReportPrefix(reportHash)).getOrDefault(0)), + Map.entry(APPROVE_VOTERS, approveVoters.at(prefix).size()), + Map.entry(REJECT_VOTERS, rejectVoters.at(prefix).size()), + Map.entry(EXTENSION_FLAG, extensionFlag.at(prefix).getOrDefault(false))); + } + + public static String progressReportPrefix(String progressHash) { + return PROGRESS_REPORT_DB_PREFIX + "|" + "|" + progressHash; + } +} diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/db/ProgressReportDataDb.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/db/ProgressReportDataDb.java index 0640ccd1..78222b06 100644 --- a/CPSCore/src/main/java/community/icon/cps/score/cpscore/db/ProgressReportDataDb.java +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/db/ProgressReportDataDb.java @@ -1,8 +1,11 @@ package community.icon.cps.score.cpscore.db; import score.*; +import scorex.util.ArrayList; import java.math.BigInteger; + +import java.util.List; import java.util.Map; import static community.icon.cps.score.cpscore.utils.ArrayDBUtils.recordTxHash; @@ -10,13 +13,14 @@ import static community.icon.cps.score.lib.interfaces.CPSCoreInterface.ProgressReportAttributes; public class ProgressReportDataDb { - private static final BranchDB> ipfsHash = Context.newBranchDB(IPFS_HASH, String.class); + public static final BranchDB> ipfsHash = Context.newBranchDB(IPFS_HASH, String.class); private static final BranchDB> reportHash = Context.newBranchDB(REPORT_HASH, String.class); private static final BranchDB> progressReportTitle = Context.newBranchDB(PROGRESS_REPORT_TITLE, String.class); public static final BranchDB> timestamp = Context.newBranchDB(TIMESTAMP, BigInteger.class); public static final BranchDB> status = Context.newBranchDB(STATUS, String.class); private static final BranchDB> txHash = Context.newBranchDB(TX_HASH, String.class); private static final BranchDB> budgetAdjustment = Context.newBranchDB(BUDGET_ADJUSTMENT, Boolean.class); + private static final BranchDB> additionalBudget = Context.newBranchDB(ADDITIONAL_BUDGET, BigInteger.class); private static final BranchDB> additionalMonth = Context.newBranchDB(ADDITIONAL_DURATION, Integer.class); @@ -37,6 +41,8 @@ public class ProgressReportDataDb { public static final BranchDB> budgetAdjustmentStatus = Context.newBranchDB(BUDGET_ADJUSTMENT_STATUS, String.class); public static final BranchDB> ipfsLink = Context.newBranchDB(IPFS_LINK, String.class); public static final BranchDB>> budgetVotersListIndices = Context.newBranchDB(BUDGET_VOTERS_LIST_INDICES, Integer.class); + public static final BranchDB> milestoneSubmitted = Context.newBranchDB(MILESTONE_SUBMITTED_COUNT,Integer.class); + public static final BranchDB> voteChange = Context.newBranchDB(VOTE_CHANGE,Integer.class); public static void addDataToProgressReportDB(ProgressReportAttributes progressData, String prefix) { ipfsHash.at(prefix).set(progressData.ipfs_hash); @@ -60,32 +66,46 @@ public static void addDataToProgressReportDB(ProgressReportAttributes progressDa public static Map getDataFromProgressReportDB(String prefix) { String proposalHash = ipfsHash.at(prefix).getOrDefault(""); - Map entryMap = - Map.ofEntries(Map.entry(IPFS_HASH, proposalHash), - Map.entry(REPORT_HASH, reportHash.at(prefix).getOrDefault("")), - Map.entry(PROGRESS_REPORT_TITLE, progressReportTitle.at(prefix).getOrDefault("")), - Map.entry(TIMESTAMP, timestamp.at(prefix).getOrDefault(BigInteger.ZERO)), - Map.entry(ADDITIONAL_BUDGET, additionalBudget.at(prefix).getOrDefault(BigInteger.ZERO)), - Map.entry(ADDITIONAL_DURATION, additionalMonth.at(prefix).getOrDefault(0)), - Map.entry(STATUS, status.at(prefix).getOrDefault("")), - Map.entry(TX_HASH, txHash.at(prefix).getOrDefault("")), - Map.entry(TOTAL_VOTES, totalVotes.at(prefix).getOrDefault(BigInteger.ZERO)), - Map.entry(APPROVED_VOTES, approvedVotes.at(prefix).getOrDefault(BigInteger.ZERO)), - Map.entry(REJECTED_VOTES, rejectedVotes.at(prefix).getOrDefault(BigInteger.ZERO)), - Map.entry(TOTAL_VOTERS, totalVoters.at(prefix).getOrDefault(0)), - Map.entry(APPROVE_VOTERS, approveVoters.at(prefix).size()), - Map.entry(REJECT_VOTERS, rejectVoters.at(prefix).size()), - Map.entry(BUDGET_APPROVED_VOTES, budgetApprovedVotes.at(prefix).getOrDefault(BigInteger.ZERO)), - Map.entry(BUDGET_REJECTED_VOTES, budgetRejectedVotes.at(prefix).getOrDefault(BigInteger.ZERO)), - Map.entry(BUDGET_APPROVE_VOTERS, budgetApproveVoters.at(prefix).size()), - Map.entry(BUDGET_REJECT_VOTERS, budgetRejectVoters.at(prefix).size()), - Map.entry(BUDGET_ADJUSTMENT_STATUS, budgetAdjustmentStatus.at(prefix).getOrDefault("")), - Map.entry(IPFS_LINK, ipfsLink.at(prefix).getOrDefault("")), - Map.entry(BUDGET_ADJUSTMENT, budgetAdjustment.at(prefix).getOrDefault(false)), - Map.entry(PROJECT_TITLE, ProposalDataDb.projectTitle.at(proposalPrefix(proposalHash)).getOrDefault("")), - Map.entry(CONTRIBUTOR_ADDRESS, ProposalDataDb.contributorAddress.at(proposalPrefix(proposalHash)).get())); + return Map.ofEntries(Map.entry(IPFS_HASH, proposalHash), + Map.entry(REPORT_HASH, reportHash.at(prefix).getOrDefault("")), + Map.entry(PROGRESS_REPORT_TITLE, progressReportTitle.at(prefix).getOrDefault("")), + Map.entry(TIMESTAMP, timestamp.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(ADDITIONAL_BUDGET, additionalBudget.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(ADDITIONAL_DURATION, additionalMonth.at(prefix).getOrDefault(0)), + Map.entry(STATUS, status.at(prefix).getOrDefault("")), + Map.entry(TX_HASH, txHash.at(prefix).getOrDefault("")), + Map.entry(IPFS_LINK, ipfsLink.at(prefix).getOrDefault("")), + Map.entry(BUDGET_ADJUSTMENT, budgetAdjustment.at(prefix).getOrDefault(false)), + Map.entry(PROJECT_TITLE, ProposalDataDb.projectTitle.at(proposalPrefix(proposalHash)).getOrDefault("")), + Map.entry(MILESTONE_SUBMITTED_COUNT, milestoneSubmitted.at(prefix).size()), + Map.entry(CONTRIBUTOR_ADDRESS, ProposalDataDb.contributorAddress.at(proposalPrefix(proposalHash)).get())); + } + public static List getMilestoneSubmittedFromProgressReportDB(String prefix){ + ArrayDB milestoneSize = milestoneSubmitted.at(prefix); + List m = new ArrayList<>(); + for (int i = 0; i < milestoneSize.size(); i++) { + m.add(milestoneSize.get(i)); + } + return m; + } + + public static Map getVoteResultsFromProgressReportDB(String prefix) { + return Map.ofEntries(Map.entry(TOTAL_VOTES, totalVotes.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(APPROVED_VOTES, approvedVotes.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(REJECTED_VOTES, rejectedVotes.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(TOTAL_VOTERS, totalVoters.at(prefix).getOrDefault(0)), + Map.entry(APPROVE_VOTERS, approveVoters.at(prefix).size()), + Map.entry(REJECT_VOTERS, rejectVoters.at(prefix).size())); + + } + + public static Map getBudgetAdjustmentDetailsFromDB(String prefix) { + return Map.ofEntries(Map.entry(BUDGET_APPROVED_VOTES, budgetApprovedVotes.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(BUDGET_REJECTED_VOTES, budgetRejectedVotes.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(BUDGET_APPROVE_VOTERS, budgetApproveVoters.at(prefix).size()), + Map.entry(BUDGET_REJECT_VOTERS, budgetRejectVoters.at(prefix).size()), + Map.entry(BUDGET_ADJUSTMENT_STATUS, budgetAdjustmentStatus.at(prefix).getOrDefault(""))); - return entryMap; } public static String proposalPrefix(String proposalKey) { diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/db/ProposalDataDb.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/db/ProposalDataDb.java index 9425118b..c0fa6cbe 100644 --- a/CPSCore/src/main/java/community/icon/cps/score/cpscore/db/ProposalDataDb.java +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/db/ProposalDataDb.java @@ -15,6 +15,7 @@ public class ProposalDataDb { public static final BranchDB> timestamp = Context.newBranchDB(TIMESTAMP, BigInteger.class); public static final BranchDB> totalBudget = Context.newBranchDB(TOTAL_BUDGET, BigInteger.class); public static final BranchDB> projectDuration = Context.newBranchDB(PROJECT_DURATION, Integer.class); + public static final BranchDB> milestoneCount = Context.newBranchDB(MILESTONE_COUNT, Integer.class); public static final BranchDB> approvedReports = Context.newBranchDB(APPROVED_REPORTS, Integer.class); public static final BranchDB> sponsorAddress = Context.newBranchDB(SPONSOR_ADDRESS, Address.class); public static final BranchDB> contributorAddress = Context.newBranchDB(CONTRIBUTOR_ADDRESS, Address.class); @@ -41,6 +42,9 @@ public class ProposalDataDb { public static final BranchDB> progressReports = Context.newBranchDB(PROGRESS_REPORTS, String.class); public static final BranchDB> budgetAdjustment = Context.newBranchDB(BUDGET_ADJUSTMENT, Boolean.class); public static final BranchDB> submitProgressReport = Context.newBranchDB(SUBMIT_PROGRESS_REPORT, Boolean.class); + public static final BranchDB> isMilestone = Context.newBranchDB(IS_MILESTONE, Boolean.class); + public static final BranchDB> proposalPeriod = Context.newBranchDB(PROPOSAL_PERIOD, Integer.class); + public static final BranchDB> milestoneIds = Context.newBranchDB("milestoneIds", Integer.class); public static void addDataToProposalDB(ProposalAttributes proposalData, String prefix) { ipfsHash.at(prefix).set(proposalData.ipfs_hash); @@ -62,43 +66,41 @@ public static void addDataToProposalDB(ProposalAttributes proposalData, String p budgetAdjustment.at(prefix).set(false); submitProgressReport.at(prefix).set(false); token.at(prefix).set(proposalData.token); + milestoneCount.at(prefix).set(proposalData.milestoneCount); + isMilestone.at(prefix).set(true); + + } + + public static void updatePercentageCompleted(String prefix, int percentage) { + percentageCompleted.at(prefix).set(percentage); } public static Map getDataFromProposalDB(String prefix) { - String reason = sponsorVoteReason.at(prefix).getOrDefault(""); - if (reason.equalsIgnoreCase("none")) { - reason = ""; - } else { - reason = reason.toString(); - } + return Map.ofEntries( + Map.entry(IPFS_HASH, ipfsHash.at(prefix).getOrDefault("")), + Map.entry(PROJECT_TITLE, projectTitle.at(prefix).getOrDefault("")), + Map.entry(TIMESTAMP, timestamp.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(TOTAL_BUDGET, totalBudget.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(PROJECT_DURATION, projectDuration.at(prefix).getOrDefault(0)), + Map.entry(APPROVED_REPORTS, approvedReports.at(prefix).getOrDefault(0)), + Map.entry(SPONSOR_ADDRESS, sponsorAddress.at(prefix).get()), + Map.entry(CONTRIBUTOR_ADDRESS, contributorAddress.at(prefix).get()), + Map.entry(STATUS, status.at(prefix).getOrDefault("")), + Map.entry(TX_HASH, txHash.at(prefix).getOrDefault("")), + Map.entry(TOKEN, token.at(prefix).getOrDefault("")), + Map.entry(SPONSOR_DEPOSIT_AMOUNT, sponsorDepositAmount.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(SPONSORED_TIMESTAMP, sponsoredTimestamp.at(prefix).getOrDefault(BigInteger.ZERO)), + Map.entry(SPONSOR_DEPOSIT_STATUS, sponsorDepositStatus.at(prefix).getOrDefault("")), + Map.entry(BUDGET_ADJUSTMENT, budgetAdjustment.at(prefix).getOrDefault(false)), + Map.entry(MILESTONE_COUNT,milestoneCount.at(prefix).getOrDefault(0)), + Map.entry(IS_MILESTONE,isMilestone.at(prefix).getOrDefault(false)), + Map.entry(PERCENTAGE_COMPLETED,percentageCompleted.at(prefix).getOrDefault(0)), + Map.entry(SUBMIT_PROGRESS_REPORT, submitProgressReport.at(prefix).getOrDefault(false)), + Map.entry(PROPOSAL_PERIOD,proposalPeriod.at(prefix).getOrDefault(0))); + } - Map entryMap = Map.ofEntries( - Map.entry(IPFS_HASH, ipfsHash.at(prefix).getOrDefault("")), - Map.entry(PROJECT_TITLE, projectTitle.at(prefix).getOrDefault("")), - Map.entry(TIMESTAMP, timestamp.at(prefix).getOrDefault(BigInteger.ZERO)), - Map.entry(TOTAL_BUDGET, totalBudget.at(prefix).getOrDefault(BigInteger.ZERO)), - Map.entry(PROJECT_DURATION, projectDuration.at(prefix).getOrDefault(0)), - Map.entry(APPROVED_REPORTS, approvedReports.at(prefix).getOrDefault(0)), - Map.entry(SPONSOR_ADDRESS, sponsorAddress.at(prefix).get()), - Map.entry(CONTRIBUTOR_ADDRESS, contributorAddress.at(prefix).get()), - Map.entry(STATUS, status.at(prefix).getOrDefault("")), - Map.entry(TX_HASH, txHash.at(prefix).getOrDefault("")), - Map.entry(PERCENTAGE_COMPLETED, percentageCompleted.at(prefix).getOrDefault(0)), - Map.entry(TOKEN, token.at(prefix).getOrDefault("")), - Map.entry(TOTAL_VOTES, totalVotes.at(prefix).getOrDefault(BigInteger.ZERO)), - Map.entry(TOTAL_VOTERS, totalVoters.at(prefix).getOrDefault(0)), - Map.entry(APPROVED_VOTES, approvedVotes.at(prefix).getOrDefault(BigInteger.ZERO)), - Map.entry(REJECTED_VOTES, rejectedVotes.at(prefix).getOrDefault(BigInteger.ZERO)), - Map.entry(ABSTAINED_VOTES, abstainedVotes.at(prefix).getOrDefault(BigInteger.ZERO)), - Map.entry(SPONSOR_DEPOSIT_AMOUNT, sponsorDepositAmount.at(prefix).getOrDefault(BigInteger.ZERO)), - Map.entry(SPONSORED_TIMESTAMP, sponsoredTimestamp.at(prefix).getOrDefault(BigInteger.ZERO)), - Map.entry(SPONSOR_DEPOSIT_STATUS, sponsorDepositStatus.at(prefix).getOrDefault("")), - Map.entry(APPROVE_VOTERS, approveVoters.at(prefix).size()), - Map.entry(REJECT_VOTERS, rejectVoters.at(prefix).size()), - Map.entry(ABSTAIN_VOTERS, abstainVoters.at(prefix).size()), - Map.entry(BUDGET_ADJUSTMENT, budgetAdjustment.at(prefix).getOrDefault(false)), - Map.entry(SUBMIT_PROGRESS_REPORT, submitProgressReport.at(prefix).getOrDefault(false))); - return entryMap; + public static int getMilestoneCount(String prefix) { + return milestoneCount.at(prefix).getOrDefault(0); } diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/ArrayDBUtils.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/ArrayDBUtils.java index af556c7c..e14152de 100644 --- a/CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/ArrayDBUtils.java +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/ArrayDBUtils.java @@ -98,6 +98,17 @@ public static List arrayToList(T[] array){ return list; } + public static void replaceArrayItem(ArrayDB array_db, Object target, Object newTarget) { + int size = array_db.size(); + + for (int i = 0; i < size; i++) { + if (array_db.get(i).equals(target)) { + array_db.set(i, (T) newTarget); + return; + } + } + } + public static void mergeSort(String[] array, int left, int right, Map priorityVoteResult) { if (left < right) { diff --git a/CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/Constants.java b/CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/Constants.java index 45c4e364..39f8f504 100644 --- a/CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/Constants.java +++ b/CPSCore/src/main/java/community/icon/cps/score/cpscore/utils/Constants.java @@ -9,7 +9,7 @@ public class Constants { public static final String TAG = "CPS Score"; - public static final BigInteger EXA = new BigInteger("1000000000000000000"); + public static final BigInteger EXA = BigInteger.valueOf(1000000000000000000L); public static final Integer MINIMUM_PREPS = 7; public static final Integer MAX_PROJECT_PERIOD = 12; @@ -58,7 +58,6 @@ public class Constants { public static final String ICX = "ICX"; public static final String bnUSD = "bnUSD"; - public static final List SUPPORTED_TOKENS = List.of(ICX, bnUSD); public static final String MAINTENANCE = "maintenance"; public static final String MESSAGE = "message"; @@ -74,8 +73,6 @@ public class Constants { public static final String SPONSOR_ADDRESS = "sponsor_address"; public static final String TOTAL_BUDGET = "total_budget"; public static final String ACTIVE_PROPOSALS = "active_proposals"; - public static final String VOTING_PROPOSALS = "voting_proposals"; - public static final String VOTING_PROGRESS_REPORTS = "voting_progress_reports"; public static final String AMOUNT = "_total_amount"; public static final String ADDRESS = "address"; @@ -101,6 +98,11 @@ public class Constants { public static final String VOTERS_LIST = "voters_list"; public static final String VOTERS_LIST_INDEXES = "voters_list_indexes"; public static final String BUDGET_VOTERS_LIST_INDICES = "budget_voters_list_indexes"; + public static final String MILESTONE_SUBMITTED_COUNT = "milestone_submitted_count"; + public static final String VOTE_CHANGE = "vote_change"; + public static final String COMPLETION_PERIOD = "completionPeriod"; + public static final String BUDGET = "budget"; + public static final String EXTENSION_FLAG = "extensionFlag"; public static final String TIMESTAMP = "timestamp"; @@ -108,15 +110,18 @@ public class Constants { public static final String CONTRIBUTOR_ADDRESS = "contributor_address"; public static final String TX_HASH = "tx_hash"; public static final String IPFS_HASH = "ipfs_hash"; - public static final String REPORT_KEY = "report_key"; public static final String REPORT_HASH = "report_hash"; + public static final String MILESTONE_ID= "milestoneID"; public static final String PROJECT_DURATION = "project_duration"; + public static final String MILESTONE_COUNT = "milestoneCount"; public static final String APPROVED_REPORTS = "approved_reports"; public static final String IPFS_LINK = "ipfs_link"; public static final String PERCENTAGE_COMPLETED = "percentage_completed"; public static final String ADDITIONAL_BUDGET = "additional_budget"; public static final String ADDITIONAL_DURATION = "additional_month"; public static final String BUDGET_ADJUSTMENT = "budget_adjustment"; + public static final String IS_MILESTONE = "isMilestone"; + public static final String PROPOSAL_PERIOD = "proposalPeriod"; public static final String BUDGETADJUSTMENT = "budgetAdjustment"; public static final String BUDGET_ADJUSTMENT_STATUS = "budget_adjustment_status"; public static final String BUDGET_APPROVED_VOTES = "budget_approved_votes"; @@ -131,10 +136,17 @@ public class Constants { public static final String STATUS = "status"; public static final String DATA = "data"; public static final String COUNT = "count"; + public static final String VOTING_PREP = "votingPRep"; + public static final String PAY_PENALTY = "payPenalty"; + public static final String IS_REGISTERED = "isRegistered"; + public static final String IS_PREP = "isPRep"; + public static final String PENALTY_AMOUNT1 = "penaltyAmount"; + public static final String TRANSFER = "transfer"; + public static final String METHOD = "method"; public static final String DELEGATION_SNAPSHOT = "delegation_snapshot"; public static final String MAX_DELEGATION = "max_delegation"; - public static final String PROPOSAL_FUND = "proposal_fund"; + public static final String TOTAL_DELEGATION_SNAPSHOT = "totalDelegationSnapshot"; public static final String PROPOSAL_FEES = "proposal_fees"; public static final String SWAP_BLOCK_HEIGHT = "swap_block_height"; public static final String SWAP_COUNT = "swap_count"; @@ -144,6 +156,8 @@ public class Constants { public static final String PRIORITY_VOTED_PREPS = "priority_voted_preps"; public static final String SPONSOR_PROJECTS = "sponsor_projects"; public static final String CONTRIBUTOR_PROJECTS = "contributor_projects"; + public static final String SPONSOR_BOND_PERCENTAGE = "sponsor_bond_percentage"; + public static final String PERIOD = "period"; // VOTE KEYS @@ -189,7 +203,11 @@ public class Constants { public static final Integer PENALTY_LEVELS = 3; // migration - public static final int MIGRATION_BATCH = 10; + public static final Integer MILESTONE_REPORT_COMPLETED = 1; + public static final Integer MILESTONE_REPORT_REJECTED = 2; + public static final Integer MILESTONE_REPORT_APPROVED = 3; + public static final Integer MILESTONE_REPORT_NOT_COMPLETED = 4; - public static final String BATCH_SIZE = "batch_size"; + + public static final BigInteger TOTAL_PERIOD = BigInteger.valueOf(30); } \ No newline at end of file diff --git a/CPSCore/src/test/java/community/icon/cps/score/cpscore/CPSScoreTest.java b/CPSCore/src/test/java/community/icon/cps/score/cpscore/CPSScoreTest.java index 90daab31..ee04772f 100644 --- a/CPSCore/src/test/java/community/icon/cps/score/cpscore/CPSScoreTest.java +++ b/CPSCore/src/test/java/community/icon/cps/score/cpscore/CPSScoreTest.java @@ -6,6 +6,7 @@ import com.iconloop.score.test.ServiceManager; import com.iconloop.score.test.TestBase; import community.icon.cps.score.cpscore.utils.Constants; +import community.icon.cps.score.lib.interfaces.CPSCoreInterface; import org.junit.jupiter.api.*; import org.junit.jupiter.api.function.Executable; import org.mockito.MockedStatic; @@ -29,29 +30,30 @@ public class CPSScoreTest extends TestBase{ public static final Address SYSTEM_ADDRESS = Address.fromString("cx0000000000000000000000000000000000000000"); - private static final Address cpsTreasury = Address.fromString("cx0000000000000000000000000000000000000002"); - private static final Address cpfTreasury = Address.fromString("cx0000000000000000000000000000000000000003"); - private static final Address bnUSDScore = Address.fromString("cx0000000000000000000000000000000000000004"); + public static final Address cpsTreasury = Address.fromString("cx0000000000000000000000000000000000000002"); + public static final Address cpfTreasury = Address.fromString("cx0000000000000000000000000000000000000003"); + public static final Address bnUSDScore = Address.fromString("cx0000000000000000000000000000000000000004"); public static final String TAG = "CPS Score"; public static final BigInteger MULTIPLIER = new BigInteger("1000000000000000000"); - private static final ServiceManager sm = getServiceManager(); - private static final Account owner = sm.createAccount(); - private static final Account testingAccount = sm.createAccount(); - private static final Account testingAccount1 = sm.createAccount(); - private static final Account testingAccount2 = sm.createAccount(); - private static final Account testingAccount3 = sm.createAccount(); - private static final Account testingAccount4 = sm.createAccount(); - private static final Account testingAccount5 = sm.createAccount(); - private static final Account testingAccount6 = sm.createAccount(); - private Score cpsScore; - private static MockedStatic contextMock; + public static final ServiceManager sm = getServiceManager(); + public static final Account owner = sm.createAccount(); + public static final Account testingAccount = sm.createAccount(); + public static final Account testingAccount1 = sm.createAccount(); + public static final Account testingAccount2 = sm.createAccount(); + public static final Account testingAccount3 = sm.createAccount(); + public static final Account testingAccount4 = sm.createAccount(); + public static final Account testingAccount5 = sm.createAccount(); + public static final Account testingAccount6 = sm.createAccount(); + public static final Account cpfTreasuryScore = Account.newScoreAccount(1); + public Score cpsScore; + public static MockedStatic contextMock; CPSCore scoreSpy; @BeforeEach public void setup() throws Exception { - cpsScore = sm.deploy(owner, CPSCore.class); + cpsScore = sm.deploy(owner, CPSCore.class,BigInteger.valueOf(12),BigInteger.valueOf(20)); CPSCore instance = (CPSCore) cpsScore.getInstance(); scoreSpy = spy(instance); cpsScore.setInstance(scoreSpy); @@ -78,7 +80,7 @@ void name(){ @Test void addAdmin(){ cpsScore.invoke(owner, "addAdmin", testingAccount.getAddress()); - assertEquals(List.of(testingAccount.getAddress()), cpsScore.call("get_admins")); + assertEquals(List.of(testingAccount.getAddress()), cpsScore.call("getAdmins")); } @Test @@ -118,7 +120,7 @@ void addAdminMethod(){ @Test void registerPRep(){ registerPrepsMethod(); - assertEquals(7, ((List)(cpsScore.call("get_PReps"))).size()); + assertEquals(7, ((List)(cpsScore.call("getPReps"))).size()); } @Test @@ -139,8 +141,8 @@ void registerPrepAlreadyRegistered(){ doReturn(prepDict.get(0)).when(scoreSpy).callScore(eq(Map.class), eq(SYSTEM_ADDRESS), eq("getPRep"), any()); cpsScore.invoke(owner, "toggleMaintenance"); cpsScore.invoke(owner, "setInitialBlock"); - cpsScore.invoke(owner, "register_prep"); - Executable register = () -> cpsScore.invoke(owner, "register_prep"); + cpsScore.invoke(owner, "registerPrep"); + Executable register = () -> cpsScore.invoke(owner, "registerPrep"); expectErrorMessage(register, "Reverted(0): CPS Score: P-Rep is already registered."); } @@ -162,7 +164,7 @@ void registerPrepNotAPrep(){ doReturn(prepDict.get(0)).when(scoreSpy).callScore(eq(Map.class), eq(SYSTEM_ADDRESS), eq("getPRep"), any()); cpsScore.invoke(owner, "toggleMaintenance"); cpsScore.invoke(owner, "setInitialBlock"); - Executable register = () -> cpsScore.invoke(testingAccount6, "register_prep"); + Executable register = () -> cpsScore.invoke(testingAccount6, "registerPrep"); expectErrorMessage(register, "Reverted(0): CPS Score: Not a P-Rep."); } @@ -187,7 +189,7 @@ void registerPrepPrepInDenyList(){ cpsScore.invoke(owner, "toggleMaintenance"); cpsScore.invoke(owner, "setInitialBlock"); // contextMock.when() - cpsScore.invoke(owner, "register_prep"); + cpsScore.invoke(owner, "registerPrep"); // todo check when voiting logic is achecked } @@ -210,14 +212,14 @@ void unregisterPrep(){ cpsScore.invoke(owner, "toggleMaintenance"); cpsScore.invoke(owner, "setInitialBlock"); - cpsScore.invoke(owner, "register_prep"); + cpsScore.invoke(owner, "registerPrep"); assertEquals(1, ((List)(cpsScore.call("getPReps"))).size()); - Map loginPrep = (Map) cpsScore.call("login_prep", owner.getAddress()); + Map loginPrep = (Map) cpsScore.call("loginPrep", owner.getAddress()); System.out.println(loginPrep); assertEquals(BigInteger.ONE, loginPrep.get("isRegistered")); - cpsScore.invoke(owner, "unregister_prep"); + cpsScore.invoke(owner, "unregisterPrep"); assertEquals(0, ((List)(cpsScore.call("getPReps"))).size()); loginPrep = (Map) cpsScore.call("loginPrep", owner.getAddress()); @@ -243,9 +245,9 @@ void unregisterPrepNotInValidPrep(){ doReturn(prepDict.get(0)).when(scoreSpy).callScore(eq(Map.class), eq(SYSTEM_ADDRESS), eq("getPRep"), any()); cpsScore.invoke(owner, "toggleMaintenance"); cpsScore.invoke(owner, "setInitialBlock"); - cpsScore.invoke(owner, "register_prep"); + cpsScore.invoke(owner, "registerPrep"); - Executable unregister = () -> cpsScore.invoke(testingAccount1, "unregister_prep"); + Executable unregister = () -> cpsScore.invoke(testingAccount1, "unregisterPrep"); expectErrorMessage(unregister, "Reverted(0): P-Rep is not registered yet."); } @@ -267,7 +269,7 @@ void loginPrep(){ doReturn(prepDict.get(0)).when(scoreSpy).callScore(eq(Map.class), eq(SYSTEM_ADDRESS), eq("getPRep"), any()); cpsScore.invoke(owner, "toggleMaintenance"); cpsScore.invoke(owner, "setInitialBlock"); - cpsScore.invoke(owner, "register_prep"); + cpsScore.invoke(owner, "registerPrep"); Map loginPrep = (Map) cpsScore.call("loginPrep", owner.getAddress()); assertEquals(BigInteger.ONE, loginPrep.get("isPRep")); @@ -330,7 +332,7 @@ void setScoresMethod(){ cpsScore.invoke(owner, "setBnusdScore", bnUSDScore); } - private void registerPrepsMethod(){ + public void registerPrepsMethod(){ setScoresMethod(); List> prepDict = List.of(Map.of("name", "owner", "address", owner.getAddress(), "power", BigInteger.valueOf(1000)), @@ -348,13 +350,13 @@ private void registerPrepsMethod(){ doReturn(prepDict.get(0)).when(scoreSpy).callScore(eq(Map.class), eq(SYSTEM_ADDRESS), eq("getPRep"), any()); cpsScore.invoke(owner, "toggleMaintenance"); cpsScore.invoke(owner, "setInitialBlock"); - cpsScore.invoke(owner, "register_prep"); - cpsScore.invoke(testingAccount, "register_prep"); - cpsScore.invoke(testingAccount1, "register_prep"); - cpsScore.invoke(testingAccount2, "register_prep"); - cpsScore.invoke(testingAccount3, "register_prep"); - cpsScore.invoke(testingAccount4, "register_prep"); - cpsScore.invoke(testingAccount5, "register_prep"); + cpsScore.invoke(owner, "registerPrep"); + cpsScore.invoke(testingAccount, "registerPrep"); + cpsScore.invoke(testingAccount1, "registerPrep"); + cpsScore.invoke(testingAccount2, "registerPrep"); + cpsScore.invoke(testingAccount3, "registerPrep"); + cpsScore.invoke(testingAccount4, "registerPrep"); + cpsScore.invoke(testingAccount5, "registerPrep"); } @@ -363,6 +365,8 @@ void submitProposal(){ submitProposalMethod(); Map proposalDetails = (Map) cpsScore.call("getProposalDetailsByHash", "Proposal 1"); System.out.println(proposalDetails); + proposalDetails.remove("sponsor_vote_reason"); + System.out.println(proposalDetails); assertEquals("Proposal 1", proposalDetails.get("ipfs_hash")); assertEquals("Title", proposalDetails.get("project_title")); assertEquals(2, proposalDetails.get("project_duration")); @@ -372,10 +376,39 @@ void submitProposal(){ assertEquals(BigInteger.valueOf(100).multiply(MULTIPLIER), proposalDetails.get("total_budget")); Map proposalDetailsOfStatus = (Map) cpsScore.call("getProposalDetails", SPONSOR_PENDING, owner.getAddress(), 0, 10); assertEquals(1, proposalDetailsOfStatus.get(COUNT)); - assertEquals(proposalDetails, ((List>)proposalDetailsOfStatus.get(DATA)).get(0)); - - Map proposalDetailsOfWallet = (Map) cpsScore.call("get_proposal_detail_by_wallet", owner.getAddress()); - assertEquals(proposalDetails, ((List>)proposalDetailsOfWallet.get(DATA)).get(0)); + assertEquals(proposalDetails.size(), ((List>)proposalDetailsOfStatus.get(DATA)).get(0).size()); + + + Map proposalDetailsOf = ((List>)proposalDetailsOfStatus.get(DATA)).get(0); + assertEquals(proposalDetails.get("approve_voters"),proposalDetailsOf.get("approve_voters")); + assertEquals(proposalDetails.get("sponsor_vote_reason"),proposalDetailsOf.get("sponsor_vote_reason")); + assertEquals(proposalDetails.get("sponsor_deposit_amount"),proposalDetailsOf.get("sponsor_deposit_amount")); + assertEquals(proposalDetails.get("sponsor_address"),proposalDetailsOf.get("sponsor_address")); + assertEquals(proposalDetails.get("timestamp"),proposalDetailsOf.get("timestamp")); + assertEquals(proposalDetails.get("contributor_address"),proposalDetailsOf.get("contributor_address")); + assertEquals(proposalDetails.get("reject_voters"),proposalDetailsOf.get("reject_voters")); + assertEquals(proposalDetails.get("project_title"),proposalDetailsOf.get("project_title")); + assertEquals(proposalDetails.get("token"),proposalDetailsOf.get("token")); + assertEquals(proposalDetails.get("tx_hash"),proposalDetailsOf.get("tx_hash")); + assertEquals(proposalDetails.get("abstained_votes"),proposalDetailsOf.get("abstained_votes")); + assertEquals(proposalDetails.get("abstain_voters"),proposalDetailsOf.get("abstain_voters")); + assertEquals(proposalDetails.get("submit_progress_report"),proposalDetailsOf.get("submit_progress_report")); + assertEquals(proposalDetails.get("sponsor_deposit_status"),proposalDetailsOf.get("sponsor_deposit_status")); + assertEquals(proposalDetails.get("budget_adjustment"),proposalDetailsOf.get("budget_adjustment")); + assertEquals(proposalDetails.get("status"),proposalDetailsOf.get("status")); + assertEquals(proposalDetails.get("approved_votes"),proposalDetailsOf.get("approved_votes")); + assertEquals(proposalDetails.get("total_votes"),proposalDetailsOf.get("total_votes")); + assertEquals(proposalDetails.get("project_duration"),proposalDetailsOf.get("project_duration")); + assertEquals(proposalDetails.get("total_voters"),proposalDetailsOf.get("total_voters")); + assertEquals(proposalDetails.get("approved_reports"),proposalDetailsOf.get("approved_reports")); + assertEquals(proposalDetails.get("rejected_votes"),proposalDetailsOf.get("rejected_votes")); + assertEquals(proposalDetails.get("sponsored_timestamp"),proposalDetailsOf.get("sponsored_timestamp")); + assertEquals(proposalDetails.get("percentage_completed"),proposalDetailsOf.get("percentage_completed")); + assertEquals(proposalDetails.get("ipfs_hash"),proposalDetailsOf.get("ipfs_hash")); + assertEquals(proposalDetails.get("total_budget"),proposalDetailsOf.get("total_budget")); + + Map proposalDetailsOfWallet = (Map) cpsScore.call("getProposalDetailByWallet", owner.getAddress(),0); + assertEquals(proposalDetails.size(), ((List>)proposalDetailsOfWallet.get(DATA)).get(0).size()); assertEquals(1, proposalDetailsOfWallet.get(COUNT)); List proposalKeys = (List) cpsScore.call("getProposalKeys"); @@ -392,16 +425,17 @@ void submitProposalMethod(){ proposalAttributes.token = bnUSD; proposalAttributes.sponsor_address = testingAccount.getAddress(); proposalAttributes.ipfs_link = "link"; + proposalAttributes.milestoneCount = 2; Map remainingSwapAmount = Map.of( "remaining_swap_amount", BigInteger.valueOf(1000).multiply(MULTIPLIER), "maxCap", BigInteger.valueOf(1000).multiply(MULTIPLIER)); - doReturn(remainingSwapAmount).when(scoreSpy).callScore(eq(Map.class), eq(cpfTreasury), eq("get_remaining_swap_amount")); + doReturn(remainingSwapAmount).when(scoreSpy).callScore(eq(Map.class), eq(cpfTreasury), eq("getRemainingSwapAmount")); contextMock.when(() -> Context.getValue()).thenReturn(BigInteger.valueOf(50).multiply(MULTIPLIER)); byte [] tx_hash = "transaction".getBytes(); contextMock.when(() -> Context.getTransactionHash()).thenReturn(tx_hash); doNothing().when(scoreSpy).callScore(eq(BigInteger.valueOf(25).multiply(MULTIPLIER)), eq(SYSTEM_ADDRESS), eq("burn")); - doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swap_tokens"), eq(0)); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swapTokens"), eq(0)); cpsScore.invoke(owner, "submitProposal", proposalAttributes); } @@ -413,13 +447,10 @@ void sponsorVote(){ System.out.println(proposalDetails); assertEquals(PENDING, proposalDetails.get("status")); assertEquals(BOND_RECEIVED, proposalDetails.get("sponsor_deposit_status")); - Map>> projectAmounts = (Map>>) cpsScore.call("get_project_amounts"); - Map> amount = Map.of( - AMOUNT, Map.of( - Constants.ICX, BigInteger.ZERO, - bnUSD, BigInteger.valueOf(100).multiply(MULTIPLIER) - ) - ); + Map>> projectAmounts = (Map>>) cpsScore.call("getProjectAmounts"); + Map amount = Map.of(AMOUNT, Map.of(Constants.ICX, BigInteger.ZERO, + bnUSD, BigInteger.valueOf(100).multiply(MULTIPLIER)), + "_count", 1); assertEquals(amount, (projectAmounts.get(PENDING))); Map sponosrsRequest = (Map) cpsScore.call("getSponsorsRequests", APPROVED, testingAccount.getAddress(), 0, 10); @@ -430,14 +461,14 @@ void submitAndSponsorVote(){ submitProposalMethod(); contextMock.when(caller()).thenReturn(bnUSDScore); JsonObject sponsorVoteParams = new JsonObject(); - sponsorVoteParams.add("method", "sponsor_vote"); + sponsorVoteParams.add("method", "sponsorVote"); JsonObject params = new JsonObject(); params.add(IPFS_HASH, "Proposal 1"); params.add(VOTE, ACCEPT); params.add(VOTE_REASON, "reason"); sponsorVoteParams.add("params", params); - cpsScore.invoke(testingAccount, "tokenFallback", testingAccount.getAddress(), BigInteger.valueOf(10).multiply(MULTIPLIER), sponsorVoteParams.toString().getBytes()); + cpsScore.invoke(testingAccount, "tokenFallback", testingAccount.getAddress(), BigInteger.valueOf(12).multiply(MULTIPLIER), sponsorVoteParams.toString().getBytes()); } void updateNextBlock(){ @@ -450,9 +481,10 @@ void voteProposal(){ submitAndSponsorVote(); contextMock.when(caller()).thenReturn(owner.getAddress()); updateNextBlock(); - cpsScore.invoke(owner, "update_period"); + doReturn(BigInteger.valueOf(15)).when(scoreSpy).getApplicationPeriod(); + cpsScore.invoke(owner, "updatePeriod"); getPeriodStatusMethod(); - doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swap_tokens"), eq(8)); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swapTokens"), eq(8)); cpsScore.invoke(owner, "voteProposal", "Proposal 1", APPROVE, "reason", false); Map proposalDetails = getProposalDetailsByHash("Proposal 1"); @@ -462,6 +494,11 @@ void voteProposal(){ assertEquals(0, proposalDetails.get("reject_voters")); assertEquals(BigInteger.valueOf(1000), proposalDetails.get("total_votes")); + // changing vote with same vote +// Executable alreadyVoted = () -> cpsScore.invoke(owner, "voteProposal", "Proposal 1", APPROVE, "reason", true); +// expectErrorMessage(alreadyVoted,"Reverted(0): CPS Score:: Cannot cast same vote. Change your vote"); + + cpsScore.invoke(owner, "voteProposal", "Proposal 1", REJECT, "reason", true); proposalDetails = getProposalDetailsByHash("Proposal 1"); @@ -478,15 +515,25 @@ void voteProposal(){ System.out.println(voteResult); } + @Test + @DisplayName("trying to vote on already vote proposal") + void voteOnProposalException(){ + voteProposal(); + contextMock.when(caller()).thenReturn(owner.getAddress()); + Executable alreadyVoted = () -> cpsScore.invoke(owner, "voteProposal", "Proposal 1", REJECT, "reason", false); + expectErrorMessage(alreadyVoted,"Reverted(0): CPS Score:: Already Voted"); + } + @Test @DisplayName("vote reject then change it to approve") void voteProposal2(){ submitAndSponsorVote(); contextMock.when(caller()).thenReturn(owner.getAddress()); updateNextBlock(); - cpsScore.invoke(owner, "update_period"); + doReturn(BigInteger.valueOf(15)).when(scoreSpy).getApplicationPeriod(); + cpsScore.invoke(owner, "updatePeriod"); getPeriodStatusMethod(); - doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swap_tokens"), eq(8)); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swapTokens"), eq(8)); cpsScore.invoke(owner, "voteProposal", "Proposal 1", REJECT, "reason", false); Map proposalDetails = getProposalDetailsByHash("Proposal 1"); @@ -497,11 +544,11 @@ void voteProposal2(){ assertEquals(BigInteger.valueOf(1000), proposalDetails.get("total_votes")); - cpsScore.invoke(owner, "voteProposal", "Proposal 1", APPROVE, "reason", true); + cpsScore.invoke(owner, "voteProposal", "Proposal 1", ABSTAIN, "reason", true); proposalDetails = getProposalDetailsByHash("Proposal 1"); - assertEquals(BigInteger.valueOf(1000), proposalDetails.get("approved_votes")); - assertEquals(1, proposalDetails.get("approve_voters")); + assertEquals(BigInteger.valueOf(1000), proposalDetails.get("abstained_votes")); + assertEquals(1, proposalDetails.get("abstain_voters")); assertEquals(BigInteger.ZERO, proposalDetails.get("rejected_votes")); assertEquals(0, proposalDetails.get("reject_voters")); assertEquals(BigInteger.valueOf(1000), proposalDetails.get("total_votes")); @@ -513,9 +560,10 @@ void voteProposalMethod(){ submitAndSponsorVote(); contextMock.when(caller()).thenReturn(owner.getAddress()); updateNextBlock(); - cpsScore.invoke(owner, "update_period"); + doReturn(BigInteger.valueOf(15)).when(scoreSpy).getApplicationPeriod(); + cpsScore.invoke(owner, "updatePeriod"); getPeriodStatusMethod(); - doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swap_tokens"), eq(8)); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swapTokens"), eq(8)); String[] proposal = new String[1]; proposal[0] = "Proposal 1"; cpsScore.invoke(owner, "voteProposal", "Proposal 1", APPROVE, "reason", false); @@ -552,12 +600,12 @@ void submitMultipleProposals(){ Map remainingSwapAmount = Map.of( "remaining_swap_amount", BigInteger.valueOf(1000).multiply(MULTIPLIER), "maxCap", BigInteger.valueOf(1000).multiply(MULTIPLIER)); - doReturn(remainingSwapAmount).when(scoreSpy).callScore(eq(Map.class), eq(cpfTreasury), eq("get_remaining_swap_amount")); + doReturn(remainingSwapAmount).when(scoreSpy).callScore(eq(Map.class), eq(cpfTreasury), eq("getRemainingSwapAmount")); contextMock.when(() -> Context.getValue()).thenReturn(BigInteger.valueOf(50).multiply(MULTIPLIER)); byte [] tx_hash = "transaction".getBytes(); contextMock.when(() -> Context.getTransactionHash()).thenReturn(tx_hash); doNothing().when(scoreSpy).callScore(eq(BigInteger.valueOf(25).multiply(MULTIPLIER)), eq(SYSTEM_ADDRESS), eq("burn")); - doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swap_tokens"), eq(0)); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swapTokens"), eq(0)); for (int i = 0; i < 10; i++) { ProposalAttributes proposalAttributes = new ProposalAttributes(); proposalAttributes.ipfs_hash = "Proposal " + i; @@ -571,7 +619,7 @@ void submitMultipleProposals(){ } contextMock.when(caller()).thenReturn(bnUSDScore); JsonObject sponsorVoteParams = new JsonObject(); - sponsorVoteParams.add("method", "sponsor_vote"); + sponsorVoteParams.add("method", "sponsorVote"); JsonObject params = new JsonObject(); for (int i = 0; i < 10; i++) { params.add(IPFS_HASH, "Proposal " + i); @@ -579,7 +627,7 @@ void submitMultipleProposals(){ params.add(VOTE_REASON, "reason"); sponsorVoteParams.add("params", params); - cpsScore.invoke(testingAccount, "tokenFallback", testingAccount.getAddress(), BigInteger.valueOf(10).multiply(MULTIPLIER), sponsorVoteParams.toString().getBytes()); + cpsScore.invoke(testingAccount, "tokenFallback", testingAccount.getAddress(), BigInteger.valueOf(12).multiply(MULTIPLIER), sponsorVoteParams.toString().getBytes()); } } @@ -588,9 +636,10 @@ void voteMultipleProposals(){ submitMultipleProposals(); contextMock.when(caller()).thenReturn(owner.getAddress()); updateNextBlock(); - cpsScore.invoke(owner, "update_period"); + doReturn(BigInteger.valueOf(15)).when(scoreSpy).getApplicationPeriod(); + cpsScore.invoke(owner, "updatePeriod"); getPeriodStatusMethod(); - doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swap_tokens"), any()); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swapTokens"), any()); String[] proposal = new String[]{"Proposal 0","Proposal 1","Proposal 2","Proposal 3","Proposal 4","Proposal 5", "Proposal 6","Proposal 7","Proposal 8","Proposal 9"}; @@ -644,9 +693,11 @@ void voteProposalMethodReject(){ submitAndSponsorVote(); contextMock.when(caller()).thenReturn(owner.getAddress()); updateNextBlock(); - cpsScore.invoke(owner, "update_period"); + doReturn(BigInteger.valueOf(15)).when(scoreSpy).getApplicationPeriod(); + doReturn(BigInteger.valueOf(15)).when(scoreSpy).getVotingPeriod(); + cpsScore.invoke(owner, "updatePeriod"); getPeriodStatusMethod(); - doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swap_tokens"), eq(8)); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swapTokens"), eq(8)); String[] proposal = new String[1]; proposal[0] = "Proposal 1"; cpsScore.invoke(owner, "voteProposal", "Proposal 1", REJECT, "reason", false); @@ -679,13 +730,13 @@ void voteProposalMethodReject(){ void updatePeriods(){ // 1/4 - cpsScore.invoke(owner, "update_period"); + cpsScore.invoke(owner, "updatePeriod"); // 2/4 - cpsScore.invoke(owner, "update_period"); + cpsScore.invoke(owner, "updatePeriod"); // 3/4 - cpsScore.invoke(owner, "update_period"); + cpsScore.invoke(owner, "updatePeriod"); // 4/4 - cpsScore.invoke(owner, "update_period"); + cpsScore.invoke(owner, "updatePeriod"); } @Test @@ -699,18 +750,20 @@ void updatePeriodAfterProposalVoting(){ bnUSD, BigInteger.valueOf(1000).multiply(MULTIPLIER) ); - doReturn(totalFunds).when(scoreSpy).callScore(eq(Map.class), eq(cpfTreasury), eq("get_total_funds")); - doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("transfer_proposal_fund_to_cps_treasury"), + doReturn(totalFunds).when(scoreSpy).callScore(eq(Map.class), eq(cpfTreasury), eq("getTotalFunds")); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("transferProposalFundToCpsTreasury"), eq("Proposal 1"), eq(2), eq(testingAccount.getAddress()), eq(owner.getAddress()), eq(bnUSD), eq(BigInteger.valueOf(100).multiply(MULTIPLIER))); - doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("reset_swap_state")); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("resetSwapState")); + doReturn(BigInteger.valueOf(15)).when(scoreSpy).getVotingPeriod(); updatePeriods(); Map proposalDetails = getProposalDetailsByHash("Proposal 1"); - Map activeProposals = (Map) cpsScore.call("getActiveProposals", 0); + Map activeProposals = (Map) cpsScore.call("getActiveProposalsList", 0); assertEquals(ACTIVE, proposalDetails.get("status")); - assertEquals(List.of(proposalDetails), activeProposals.get(DATA)); + List> activeProposalList =(List>) activeProposals.get(DATA); + assertEquals(List.of(proposalDetails).size(), activeProposalList.size()); Map sponosrsRequest = (Map) cpsScore.call("getSponsorsRequests", APPROVED, testingAccount.getAddress(), 0, 10); System.out.println("Sponsors request" + sponosrsRequest); @@ -718,13 +771,10 @@ void updatePeriodAfterProposalVoting(){ Map sponsorsRecord = (Map) cpsScore.call("getSponsorsRecord"); assertEquals(1, sponsorsRecord.get(testingAccount.getAddress().toString())); - Map>> projectAmounts = (Map>>) cpsScore.call("get_project_amounts"); - Map> amount = Map.of( - AMOUNT, Map.of( - Constants.ICX, BigInteger.ZERO, - bnUSD, BigInteger.valueOf(100).multiply(MULTIPLIER) - ) - ); + Map>> projectAmounts = (Map>>) cpsScore.call("getProjectAmounts"); + Map amount = Map.of(AMOUNT, Map.of(Constants.ICX, BigInteger.ZERO, + bnUSD, BigInteger.valueOf(100).multiply(MULTIPLIER)), + "_count", 1); assertEquals(amount, (projectAmounts.get(ACTIVE))); Map voteResult = (Map) cpsScore.call("getVoteResult", "Proposal 1"); @@ -742,26 +792,27 @@ void rejectProposal(){ bnUSD, BigInteger.valueOf(1000).multiply(MULTIPLIER) ); contextMock.when(() -> Context.transfer(any(), any())).thenAnswer((Answer) invocation -> null); - doReturn(totalFunds).when(scoreSpy).callScore(eq(Map.class), eq(cpfTreasury), eq("get_total_funds")); - doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("transfer_proposal_fund_to_cps_treasury"), - eq("Proposal 1"), eq(2), eq(testingAccount.getAddress()), eq(owner.getAddress()), - eq(bnUSD), eq(BigInteger.valueOf(100).multiply(MULTIPLIER))); + doReturn(totalFunds).when(scoreSpy).callScore(eq(Map.class), eq(cpfTreasury), eq("getTotalFunds")); - doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("reset_swap_state")); + + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("resetSwapState")); doNothing().when(scoreSpy).callScore(eq(BigInteger.ZERO), eq(SYSTEM_ADDRESS), eq("burn")); updatePeriods(); Map proposalDetails = getProposalDetailsByHash("Proposal 1"); + proposalDetails.remove("sponsor_vote_reason"); assertEquals(REJECTED, proposalDetails.get("status")); Map claimableSponsorBond = (Map) cpsScore.call("checkClaimableSponsorBond", testingAccount.getAddress()); - assertEquals(BigInteger.valueOf(10).multiply(MULTIPLIER), claimableSponsorBond.get(bnUSD)); + assertEquals(BigInteger.valueOf(12).multiply(MULTIPLIER), claimableSponsorBond.get(bnUSD)); Map voteResult = (Map) cpsScore.call("getVoteResult", "Proposal 1"); System.out.println("voteResult: " + voteResult); Map proposalsHistory = (Map) cpsScore.call("getProposalsHistory", 0); - assertEquals(List.of(proposalDetails), proposalsHistory.get(DATA)); + List> proposalHistory = (List>) proposalsHistory.get(DATA); + + assertEquals(proposalDetails.size(), proposalHistory.get(0).size()); } @Test @@ -774,10 +825,12 @@ void submitProgressReport(){ progressReport.budget_adjustment = true; progressReport.additional_budget = BigInteger.valueOf(10); progressReport.additional_month = 1; - progressReport.percentage_completed = 50; +// progressReport.isMilestone = true; + progressReport.milestoneCompleted = new int[]{1,2}; +// progressReport.percentage_completed = 50; updatePeriodAfterProposalVoting(); - doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swap_tokens"), any()); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swapTokens"), any()); cpsScore.invoke(owner, "toggleBudgetAdjustmentFeature"); cpsScore.invoke(owner, "submitProgressReport", progressReport); @@ -791,86 +844,218 @@ void submitProgressReport(){ assertEquals(progressReport.budget_adjustment, progressReportDetails.get("budget_adjustment")); assertEquals(progressReport.additional_budget.multiply(MULTIPLIER), progressReportDetails.get("additional_budget")); assertEquals(progressReport.additional_month, progressReportDetails.get("additional_month")); - assertEquals(progressReport.percentage_completed, progressReportDetails.get("percentage_completed")); +// assertEquals(progressReport.percentage_completed, progressReportDetails.get("percentage_completed")); List progressKeys = (List) cpsScore.call("getProgressKeys"); assertEquals(List.of("Report 1"), progressKeys); Map progressReports = (Map) cpsScore.call("getProgressReports", WAITING, 0, 10); System.out.println("Progerss reports: " + progressReports); - assertEquals(List.of(progressReportDetails), progressReports.get(DATA)); +// assertEquals(List.of(progressReportDetails), progressReports.get(DATA)); assertEquals(1, progressReports.get(COUNT)); Map progressReportsByProposal = (Map) cpsScore.call("getProgressReportsByProposal", "Proposal 1"); - assertEquals(List.of(progressReportDetails), progressReportsByProposal.get(DATA)); +// assertEquals(List.of(progressReportDetails), progressReportsByProposal.get(DATA)); assertEquals(1, progressReportsByProposal.get(COUNT)); } + @Test + void voteProgressReportExceptions(){ + submitProgressReport(); + updateNextBlock(); + cpsScore.invoke(owner, "updatePeriod"); + getPeriodStatusMethod(); + CPSCoreInterface.MilestoneVoteAttributes milestoneVoteAttributes= new CPSCoreInterface.MilestoneVoteAttributes(); + milestoneVoteAttributes.vote = APPROVE; + milestoneVoteAttributes.id = 1; + + CPSCoreInterface.MilestoneVoteAttributes milestoneVoteAttributes2= new CPSCoreInterface.MilestoneVoteAttributes(); + milestoneVoteAttributes2.vote = APPROVE; + milestoneVoteAttributes2.id = 3; + + CPSCoreInterface.MilestoneVoteAttributes[] milestoneVoteAttributesList = new CPSCoreInterface.MilestoneVoteAttributes[]{ + milestoneVoteAttributes,milestoneVoteAttributes2}; + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swapTokens"), eq(8)); + Executable call = () ->cpsScore.invoke(owner, "voteProgressReport", "Report 1", "reason", + milestoneVoteAttributesList ,"_reject",false); + expectErrorMessage(call,"Reverted(0): CPS Score: Voting can only be done for milestone " + + "submitted in this progress report"); + + } + + @Test + void voteProgressReportException(){ + submitProgressReport(); + updateNextBlock(); + cpsScore.invoke(owner, "updatePeriod"); + getPeriodStatusMethod(); + CPSCoreInterface.MilestoneVoteAttributes milestoneVoteAttributes= new CPSCoreInterface.MilestoneVoteAttributes(); + milestoneVoteAttributes.vote = APPROVE; + milestoneVoteAttributes.id = 1; + + CPSCoreInterface.MilestoneVoteAttributes[] milestoneVoteAttributesList = new CPSCoreInterface.MilestoneVoteAttributes[]{ + milestoneVoteAttributes}; + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swapTokens"), eq(8)); + Executable call = () ->cpsScore.invoke(owner, "voteProgressReport", "Report 1", "reason", + milestoneVoteAttributesList ,"_reject",false); + expectErrorMessage(call,"Reverted(0): CPS Score:: You should submit votes for all milestones of the progress report"); + + milestoneVoteAttributes= new CPSCoreInterface.MilestoneVoteAttributes(); + milestoneVoteAttributes.vote = APPROVE; + milestoneVoteAttributes.id = 1; + + CPSCoreInterface.MilestoneVoteAttributes milestoneVoteAttributes2= new CPSCoreInterface.MilestoneVoteAttributes(); + milestoneVoteAttributes2.vote = APPROVE; + milestoneVoteAttributes2.id = 1; + + CPSCoreInterface.MilestoneVoteAttributes[] milestoneVoteAttributesList2 = new CPSCoreInterface.MilestoneVoteAttributes[]{ + milestoneVoteAttributes,milestoneVoteAttributes2}; + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swapTokens"), eq(8)); + Executable call2 = () ->cpsScore.invoke(owner, "voteProgressReport", "Report 1", "reason", + milestoneVoteAttributesList2 ,"_reject",false); + expectErrorMessage(call2,"Reverted(0): You should submit votes for all milestones of the progress report"); + + } + @Test void voteProgressReport(){ submitProgressReport(); updateNextBlock(); cpsScore.invoke(owner, "updatePeriod"); getPeriodStatusMethod(); - doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swap_tokens"), eq(8)); - cpsScore.invoke(owner, "voteProgressReport", "Proposal 1", "Report 1", APPROVE, "reason", APPROVE, false); + CPSCoreInterface.MilestoneVoteAttributes milestoneVoteAttributes= new CPSCoreInterface.MilestoneVoteAttributes(); + milestoneVoteAttributes.vote = APPROVE; + milestoneVoteAttributes.id = 1; + + CPSCoreInterface.MilestoneVoteAttributes milestoneVoteAttributes2= new CPSCoreInterface.MilestoneVoteAttributes(); + milestoneVoteAttributes2.vote = APPROVE; + milestoneVoteAttributes2.id = 2; + + CPSCoreInterface.MilestoneVoteAttributes[] milestoneVoteAttributesList = new CPSCoreInterface.MilestoneVoteAttributes[]{ + milestoneVoteAttributes,milestoneVoteAttributes2}; + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swapTokens"), eq(8)); + cpsScore.invoke(owner, "voteProgressReport", "Report 1", "reason", milestoneVoteAttributesList ,"_reject",false); contextMock.when(caller()).thenReturn(testingAccount.getAddress()); - cpsScore.invoke(testingAccount, "voteProgressReport", "Proposal 1", "Report 1", APPROVE, "reason", APPROVE, false); + cpsScore.invoke(testingAccount, "voteProgressReport", "Report 1", "reason", (Object)milestoneVoteAttributesList ,"_reject",false); contextMock.when(caller()).thenReturn(testingAccount1.getAddress()); - cpsScore.invoke(testingAccount1, "voteProgressReport", "Proposal 1", "Report 1", APPROVE, "reason", APPROVE, false); + cpsScore.invoke(testingAccount1, "voteProgressReport", "Report 1", "reason", milestoneVoteAttributesList ,"_reject",false); contextMock.when(caller()).thenReturn(testingAccount2.getAddress()); - cpsScore.invoke(testingAccount2, "voteProgressReport", "Proposal 1", "Report 1", APPROVE, "reason", APPROVE, false); + cpsScore.invoke(testingAccount2, "voteProgressReport", "Report 1", "reason", (Object)milestoneVoteAttributesList ,"_reject",false); contextMock.when(caller()).thenReturn(testingAccount3.getAddress()); - cpsScore.invoke(testingAccount3, "voteProgressReport", "Proposal 1", "Report 1", APPROVE, "reason", APPROVE, false); + cpsScore.invoke(testingAccount3, "voteProgressReport", "Report 1", "reason", (Object)milestoneVoteAttributesList ,"_reject",false); contextMock.when(caller()).thenReturn(testingAccount4.getAddress()); - cpsScore.invoke(testingAccount4, "voteProgressReport", "Proposal 1", "Report 1", APPROVE, "reason", APPROVE, false); + cpsScore.invoke(testingAccount4, "voteProgressReport", "Report 1", "reason", (Object)milestoneVoteAttributesList ,"_reject",false); contextMock.when(caller()).thenReturn(testingAccount5.getAddress()); - cpsScore.invoke(testingAccount5, "voteProgressReport", "Proposal 1", "Report 1", APPROVE, "reason", APPROVE, false); + cpsScore.invoke(testingAccount5, "voteProgressReport", "Report 1", "reason", (Object)milestoneVoteAttributesList ,"_reject",false); @SuppressWarnings("unchecked") - Map progressReportDetails = (Map) cpsScore.call("getProgressReportsByHash", "Report 1"); + Map progressReportVoteDetails = (Map) cpsScore.call("getProgressReportVoteDetails", "Report 1"); + Map budgetAdjustmentDetails = (Map) cpsScore.call("getBudgetAdjustmentDetails", "Report 1"); - assertEquals(7, progressReportDetails.get(TOTAL_VOTERS)); - assertEquals(7, progressReportDetails.get(BUDGET_APPROVE_VOTERS)); - assertEquals(7, progressReportDetails.get(APPROVE_VOTERS)); + + assertEquals(7, progressReportVoteDetails.get(TOTAL_VOTERS)); + assertEquals(0, budgetAdjustmentDetails.get(BUDGET_APPROVE_VOTERS)); + + Map milestoneReport = (Map) cpsScore.call("getMilestonesReport", "Proposal 1", 1); + assertEquals(7, milestoneReport.get(APPROVE_VOTERS)); Map voteResult = (Map) cpsScore.call("getProgressReportResult", "Report 1"); System.out.println("progress report vote Result: " + voteResult); } + @Test + void voteProgressReportAgain(){ + voteProgressReport(); + getPeriodStatusMethod(); + CPSCoreInterface.MilestoneVoteAttributes milestoneVoteAttributes= new CPSCoreInterface.MilestoneVoteAttributes(); + milestoneVoteAttributes.vote = APPROVE; + milestoneVoteAttributes.id = 1; + + CPSCoreInterface.MilestoneVoteAttributes milestoneVoteAttributes2= new CPSCoreInterface.MilestoneVoteAttributes(); + milestoneVoteAttributes2.vote = APPROVE; + milestoneVoteAttributes2.id = 2; + + CPSCoreInterface.MilestoneVoteAttributes[] milestoneVoteAttributesList = new CPSCoreInterface.MilestoneVoteAttributes[]{ + milestoneVoteAttributes,milestoneVoteAttributes2}; + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swapTokens"), eq(8)); + Executable call = () ->cpsScore.invoke(owner, "voteProgressReport", "Report 1", "reason", + milestoneVoteAttributesList ,"_reject",false); + expectErrorMessage(call,"Reverted(0): CPS Score:: Already Voted" ); + + } + @Test void voteProgressReportVoteChangeFromApproveToReject(){ submitProgressReport(); updateNextBlock(); cpsScore.invoke(owner, "updatePeriod"); getPeriodStatusMethod(); - doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swap_tokens"), eq(8)); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swapTokens"), eq(8)); + // vote change only on milestone 1 + CPSCoreInterface.MilestoneVoteAttributes milestoneVoteAttributes= new CPSCoreInterface.MilestoneVoteAttributes(); + milestoneVoteAttributes.vote = APPROVE; + milestoneVoteAttributes.id = 1; + + CPSCoreInterface.MilestoneVoteAttributes milestoneVoteAttributes2= new CPSCoreInterface.MilestoneVoteAttributes(); + milestoneVoteAttributes2.vote = APPROVE; + milestoneVoteAttributes2.id = 2; + + CPSCoreInterface.MilestoneVoteAttributes[] milestoneVoteAttributesList = new CPSCoreInterface.MilestoneVoteAttributes[]{ + milestoneVoteAttributes,milestoneVoteAttributes2}; + + cpsScore.invoke(owner, "voteProgressReport", "Report 1", "reason", milestoneVoteAttributesList ,"_reject",false); + + contextMock.when(caller()).thenReturn(testingAccount.getAddress()); + cpsScore.invoke(testingAccount, "voteProgressReport", "Report 1", "I accept", (Object)milestoneVoteAttributesList ,"_reject",false); + + assertEquals(0, cpsScore.call("checkChangeVote", owner.getAddress(), "Report 1", "progress_reports")); + assertEquals(0, cpsScore.call("checkChangeVote", testingAccount.getAddress(), "Report 1", "progress_reports")); + - cpsScore.invoke(owner, "voteProgressReport", "Proposal 1", "Report 1", APPROVE, "reason", APPROVE, false); Map progressReportDetails = (Map) cpsScore.call("getProgressReportsByHash", "Report 1"); + Map milestoneReport = (Map) cpsScore.call("getMilestonesReport", "Proposal 1", 1); - assertEquals(BigInteger.valueOf(1000), progressReportDetails.get(APPROVED_VOTES)); - assertEquals(BigInteger.valueOf(0), progressReportDetails.get(REJECTED_VOTES)); - assertEquals(BigInteger.valueOf(1000), progressReportDetails.get(BUDGET_APPROVED_VOTES)); - assertEquals(BigInteger.valueOf(0), progressReportDetails.get(BUDGET_REJECTED_VOTES)); - assertEquals(1, progressReportDetails.get(APPROVE_VOTERS)); - assertEquals(0, progressReportDetails.get(REJECT_VOTERS)); - assertEquals(1, progressReportDetails.get(BUDGET_APPROVE_VOTERS)); - assertEquals(0, progressReportDetails.get(BUDGET_REJECT_VOTERS)); + assertEquals(2, milestoneReport.get(APPROVE_VOTERS)); + assertEquals(BigInteger.valueOf(2000), milestoneReport.get(APPROVED_VOTES)); + assertEquals(BigInteger.valueOf(0), milestoneReport.get(REJECTED_VOTES)); + assertEquals(2, milestoneReport.get(APPROVE_VOTERS)); + assertEquals(0, milestoneReport.get(REJECT_VOTERS)); + milestoneVoteAttributes= new CPSCoreInterface.MilestoneVoteAttributes(); + milestoneVoteAttributes.vote = REJECT; + milestoneVoteAttributes.id = 1; - cpsScore.invoke(owner, "voteProgressReport", "Proposal 1", "Report 1", REJECT, "reason", REJECT, true); + milestoneVoteAttributesList = new CPSCoreInterface.MilestoneVoteAttributes[]{ + milestoneVoteAttributes}; + + System.out.println("reason "+cpsScore.call("getProgressReportVoters","Report 1")); + + contextMock.when(caller()).thenReturn(owner.getAddress()); + cpsScore.invoke(owner, "voteProgressReport", "Report 1", "I am rejecting", milestoneVoteAttributesList ,"_reject",true); + + assertEquals(1, cpsScore.call("checkChangeVote", owner.getAddress(), "Report 1", "progress_reports")); + assertEquals(0, cpsScore.call("checkChangeVote", testingAccount.getAddress(), "Report 1", "progress_reports")); + + + contextMock.when(caller()).thenReturn(testingAccount.getAddress()); + cpsScore.invoke(testingAccount, "voteProgressReport", "Report 1", "Lets rejects ", milestoneVoteAttributesList ,"_reject",true); + + + + + milestoneReport = (Map) cpsScore.call("getMilestonesReport", "Proposal 1", 1); + assertEquals(BigInteger.valueOf(0), milestoneReport.get(APPROVED_VOTES)); + assertEquals(BigInteger.valueOf(2000), milestoneReport.get(REJECTED_VOTES)); +// assertEquals(BigInteger.valueOf(0), progressReportDetails.get(BUDGET_APPROVED_VOTES)); +// assertEquals(BigInteger.valueOf(1000), progressReportDetails.get(BUDGET_REJECTED_VOTES)); + assertEquals(0, milestoneReport.get(APPROVE_VOTERS)); + assertEquals(2, milestoneReport.get(REJECT_VOTERS)); +// assertEquals(0, progressReportDetails.get(BUDGET_APPROVE_VOTERS)); +// assertEquals(1, progressReportDetails.get(BUDGET_REJECT_VOTERS)); + + System.out.println("reason 1 "+cpsScore.call("getProgressReportVoters","Report 1")); - progressReportDetails = (Map) cpsScore.call("getProgressReportsByHash", "Report 1"); - assertEquals(BigInteger.valueOf(0), progressReportDetails.get(APPROVED_VOTES)); - assertEquals(BigInteger.valueOf(1000), progressReportDetails.get(REJECTED_VOTES)); - assertEquals(BigInteger.valueOf(0), progressReportDetails.get(BUDGET_APPROVED_VOTES)); - assertEquals(BigInteger.valueOf(1000), progressReportDetails.get(BUDGET_REJECTED_VOTES)); - assertEquals(0, progressReportDetails.get(APPROVE_VOTERS)); - assertEquals(1, progressReportDetails.get(REJECT_VOTERS)); - assertEquals(0, progressReportDetails.get(BUDGET_APPROVE_VOTERS)); - assertEquals(1, progressReportDetails.get(BUDGET_REJECT_VOTERS)); assertEquals(1, cpsScore.call("checkChangeVote", owner.getAddress(), "Report 1", "progress_reports")); } @@ -886,15 +1071,15 @@ void updatePeriodAfterProgressReportSubmission(){ bnUSD, BigInteger.valueOf(1000).multiply(MULTIPLIER) ); - doReturn(totalFunds).when(scoreSpy).callScore(eq(Map.class), eq(cpfTreasury), eq("get_total_funds")); - doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("transfer_proposal_fund_to_cps_treasury"), - eq("Proposal 1"), eq(2), eq(testingAccount.getAddress()), eq(owner.getAddress()), + doReturn(totalFunds).when(scoreSpy).callScore(eq(Map.class), eq(cpfTreasury), eq("getTotalFunds")); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("transferProposalFundToCpsTreasury"), + eq("Proposal 1"),eq(2), eq(testingAccount.getAddress()), eq(owner.getAddress()), eq(bnUSD), eq(BigInteger.valueOf(100).multiply(MULTIPLIER))); - doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("reset_swap_state")); - doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("update_proposal_fund"), eq("Proposal 1"), eq(bnUSD), eq(BigInteger.valueOf(10).multiply(MULTIPLIER)), eq(1)); - doNothing().when(scoreSpy).callScore(eq(cpsTreasury), eq("send_installment_to_contributor"), eq("Proposal 1")); - doNothing().when(scoreSpy).callScore(eq(cpsTreasury), eq("send_reward_to_sponsor"), eq("Proposal 1")); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("resetSwapState")); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("updateProposalFund"), eq("Proposal 1"), eq(bnUSD), eq(BigInteger.valueOf(10).multiply(MULTIPLIER)), eq(1)); + doNothing().when(scoreSpy).callScore(eq(cpsTreasury), eq("sendInstallmentToContributor"), eq("Proposal 1"),eq(2)); + doNothing().when(scoreSpy).callScore(eq(cpsTreasury), eq("sendRewardToSponsor"), eq("Proposal 1"),eq(2)); doNothing().when(scoreSpy).callScore(eq(BigInteger.ZERO), eq(SYSTEM_ADDRESS), eq("burn")); updatePeriods(); @@ -902,8 +1087,10 @@ void updatePeriodAfterProgressReportSubmission(){ Map progressReportDetails = (Map) cpsScore.call("getProgressReportsByHash", "Report 1"); System.out.println(progressReportDetails); - assertEquals(APPROVED, progressReportDetails.get(STATUS)); - assertEquals(APPROVED, progressReportDetails.get(BUDGET_ADJUSTMENT_STATUS)); + // TODO: update progress report also -> assertEquals(APPROVED, progressReportDetails.get(STATUS)); + Map milestoneReport = (Map) cpsScore.call("getMilestonesReport", "Proposal 1", 1); + assertEquals(MILESTONE_REPORT_COMPLETED, milestoneReport.get(STATUS)); +// assertEquals(APPROVED, progressReportDetails.get(BUDGET_ADJUSTMENT_STATUS)); } @Test @@ -916,10 +1103,11 @@ void submitProgressReportWithoutBudgetAdjustment(){ progressReport.budget_adjustment = false; progressReport.additional_budget = BigInteger.valueOf(0); progressReport.additional_month = 0; - progressReport.percentage_completed = 50; + progressReport.milestoneCompleted = new int[]{1}; +// progressReport.percentage_completed = 50; updatePeriodAfterProposalVoting(); - doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swap_tokens"), any()); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swapTokens"), any()); cpsScore.invoke(owner, "toggleBudgetAdjustmentFeature"); cpsScore.invoke(owner, "submitProgressReport", progressReport); } @@ -930,26 +1118,38 @@ void voteProgressReportAfterSubmittingProposalWithoutBudgetAdjustment(){ updateNextBlock(); cpsScore.invoke(owner, "updatePeriod"); getPeriodStatusMethod(); - doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swap_tokens"), eq(8)); - cpsScore.invoke(owner, "voteProgressReport", "Proposal 1", "Report 1", APPROVE, "reason", APPROVE, false); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swapTokens"), eq(8)); + + + CPSCoreInterface.MilestoneVoteAttributes milestoneVoteAttributes= new CPSCoreInterface.MilestoneVoteAttributes(); + milestoneVoteAttributes.vote = APPROVE; + milestoneVoteAttributes.id = 1; + + + CPSCoreInterface.MilestoneVoteAttributes[] milestoneVoteAttributesList = new CPSCoreInterface.MilestoneVoteAttributes[]{ + milestoneVoteAttributes}; + + cpsScore.invoke(owner, "voteProgressReport", "Report 1", "reason", milestoneVoteAttributesList ,APPROVE,false); contextMock.when(caller()).thenReturn(testingAccount.getAddress()); - cpsScore.invoke(testingAccount, "voteProgressReport", "Proposal 1", "Report 1", APPROVE, "reason", APPROVE, false); + cpsScore.invoke(testingAccount, "voteProgressReport", "Report 1", "reason", milestoneVoteAttributesList ,APPROVE,false); contextMock.when(caller()).thenReturn(testingAccount1.getAddress()); - cpsScore.invoke(testingAccount1, "voteProgressReport", "Proposal 1", "Report 1", APPROVE, "reason", APPROVE, false); + cpsScore.invoke(testingAccount1, "voteProgressReport", "Report 1", "reason", milestoneVoteAttributesList ,APPROVE,false); contextMock.when(caller()).thenReturn(testingAccount2.getAddress()); - cpsScore.invoke(testingAccount2, "voteProgressReport", "Proposal 1", "Report 1", APPROVE, "reason", APPROVE, false); + cpsScore.invoke(testingAccount2, "voteProgressReport", "Report 1", "reason", milestoneVoteAttributesList ,APPROVE,false); contextMock.when(caller()).thenReturn(testingAccount3.getAddress()); - cpsScore.invoke(testingAccount3, "voteProgressReport", "Proposal 1", "Report 1", APPROVE, "reason", APPROVE, false); + cpsScore.invoke(testingAccount3, "voteProgressReport", "Report 1", "reason", milestoneVoteAttributesList ,APPROVE,false); contextMock.when(caller()).thenReturn(testingAccount4.getAddress()); - cpsScore.invoke(testingAccount4, "voteProgressReport", "Proposal 1", "Report 1", APPROVE, "reason", APPROVE, false); + cpsScore.invoke(testingAccount4, "voteProgressReport", "Report 1", "reason", milestoneVoteAttributesList ,APPROVE,false); contextMock.when(caller()).thenReturn(testingAccount5.getAddress()); - cpsScore.invoke(testingAccount5, "voteProgressReport", "Proposal 1", "Report 1", APPROVE, "reason", APPROVE, false); + cpsScore.invoke(testingAccount5, "voteProgressReport", "Report 1", "reason", milestoneVoteAttributesList ,APPROVE,false); @SuppressWarnings("unchecked") - Map progressReportDetails = (Map) cpsScore.call("getProgressReportsByHash", "Report 1"); + Map progressReportDetails = (Map) cpsScore.call("getProgressReportVoteDetails", "Report 1"); assertEquals(7, progressReportDetails.get(TOTAL_VOTERS)); - assertEquals(7, progressReportDetails.get(APPROVE_VOTERS)); + + Map milestonesReport =(Map) cpsScore.call("getMilestonesReport", "Proposal 1", 1); + assertEquals(7, milestonesReport.get(APPROVE_VOTERS)); contextMock.when(caller()).thenReturn(owner.getAddress()); updateNextBlock(); @@ -961,13 +1161,13 @@ void voteProgressReportAfterSubmittingProposalWithoutBudgetAdjustment(){ doReturn(totalFunds).when(scoreSpy).callScore(eq(Map.class), eq(cpfTreasury), eq("get_total_funds")); doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("transfer_proposal_fund_to_cps_treasury"), - eq("Proposal 1"), eq(2), eq(testingAccount.getAddress()), eq(owner.getAddress()), + eq("Proposal 1"), eq(2),eq(2), eq(testingAccount.getAddress()), eq(owner.getAddress()), eq(bnUSD), eq(BigInteger.valueOf(100).multiply(MULTIPLIER))); - doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("reset_swap_state")); - doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("update_proposal_fund"), eq("Proposal 1"), eq(bnUSD), eq(BigInteger.valueOf(10).multiply(MULTIPLIER)), eq(1)); - doNothing().when(scoreSpy).callScore(eq(cpsTreasury), eq("send_installment_to_contributor"), eq("Proposal 1")); - doNothing().when(scoreSpy).callScore(eq(cpsTreasury), eq("send_reward_to_sponsor"), eq("Proposal 1")); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("resetSwapState")); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("updateProposalFund"), eq("Proposal 1"), eq(bnUSD), eq(BigInteger.valueOf(10).multiply(MULTIPLIER)), eq(1)); + doNothing().when(scoreSpy).callScore(eq(cpsTreasury), eq("sendInstallmentToContributor"), eq("Proposal 1"),eq(1)); + doNothing().when(scoreSpy).callScore(eq(cpsTreasury), eq("sendRewardToSponsor"), eq("Proposal 1"),eq(1)); doNothing().when(scoreSpy).callScore(eq(BigInteger.ZERO), eq(SYSTEM_ADDRESS), eq("burn")); updatePeriods(); @@ -982,32 +1182,43 @@ void voteProgressReportAfterSubmittingProposalWithoutBudgetAdjustment(){ progressReport.budget_adjustment = false; progressReport.additional_budget = BigInteger.valueOf(0); progressReport.additional_month = 0; - progressReport.percentage_completed = 50; + progressReport.milestoneCompleted = new int[]{2}; +// progressReport.percentage_completed = 50; cpsScore.invoke(owner, "submitProgressReport", progressReport); updateNextBlock(); cpsScore.invoke(owner, "updatePeriod"); getPeriodStatusMethod(); - doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swap_tokens"), eq(8)); - cpsScore.invoke(owner, "voteProgressReport", "Proposal 1", "Report 2", APPROVE, "reason", APPROVE, false); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swapTokens"), eq(8)); + + milestoneVoteAttributes= new CPSCoreInterface.MilestoneVoteAttributes(); + milestoneVoteAttributes.vote = APPROVE; + milestoneVoteAttributes.id = 2; + + milestoneVoteAttributesList = new CPSCoreInterface.MilestoneVoteAttributes[]{ + milestoneVoteAttributes}; + + cpsScore.invoke(owner, "voteProgressReport", "Report 2", "reason", milestoneVoteAttributesList ,APPROVE,false); contextMock.when(caller()).thenReturn(testingAccount.getAddress()); - cpsScore.invoke(testingAccount, "voteProgressReport", "Proposal 1", "Report 2", APPROVE, "reason", APPROVE, false); + cpsScore.invoke(testingAccount, "voteProgressReport", "Report 2", "reason", milestoneVoteAttributesList ,APPROVE,false); contextMock.when(caller()).thenReturn(testingAccount1.getAddress()); - cpsScore.invoke(testingAccount1, "voteProgressReport", "Proposal 1", "Report 2", APPROVE, "reason", APPROVE, false); + cpsScore.invoke(testingAccount1, "voteProgressReport", "Report 2", "reason", milestoneVoteAttributesList ,APPROVE,false); contextMock.when(caller()).thenReturn(testingAccount2.getAddress()); - cpsScore.invoke(testingAccount2, "voteProgressReport", "Proposal 1", "Report 2", APPROVE, "reason", APPROVE, false); + cpsScore.invoke(testingAccount2, "voteProgressReport", "Report 2", "reason", milestoneVoteAttributesList ,APPROVE,false); contextMock.when(caller()).thenReturn(testingAccount3.getAddress()); - cpsScore.invoke(testingAccount3, "voteProgressReport", "Proposal 1", "Report 2", APPROVE, "reason", APPROVE, false); + cpsScore.invoke(testingAccount3, "voteProgressReport", "Report 2", "reason", milestoneVoteAttributesList ,APPROVE,false); contextMock.when(caller()).thenReturn(testingAccount4.getAddress()); - cpsScore.invoke(testingAccount4, "voteProgressReport", "Proposal 1", "Report 2", APPROVE, "reason", APPROVE, false); + cpsScore.invoke(testingAccount4, "voteProgressReport", "Report 2", "reason", milestoneVoteAttributesList ,APPROVE,false); contextMock.when(caller()).thenReturn(testingAccount5.getAddress()); - cpsScore.invoke(testingAccount5, "voteProgressReport", "Proposal 1", "Report 2", APPROVE, "reason", APPROVE, false); + cpsScore.invoke(testingAccount5, "voteProgressReport", "Report 2", "reason", milestoneVoteAttributesList ,APPROVE,false); - progressReportDetails = (Map) cpsScore.call("getProgressReportsByHash", "Report 1"); + progressReportDetails = (Map) cpsScore.call("getProgressReportVoteDetails", "Report 2"); assertEquals(7, progressReportDetails.get(TOTAL_VOTERS)); - assertEquals(7, progressReportDetails.get(APPROVE_VOTERS)); + + milestonesReport =(Map) cpsScore.call("getMilestonesReport", "Proposal 1", 2); + assertEquals(7, milestonesReport.get(APPROVE_VOTERS)); contextMock.when(caller()).thenReturn(owner.getAddress()); updateNextBlock(); @@ -1019,46 +1230,45 @@ void voteProgressReportAfterSubmittingProposalWithoutBudgetAdjustment(){ doReturn(totalFunds).when(scoreSpy).callScore(eq(Map.class), eq(cpfTreasury), eq("get_total_funds")); doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("transfer_proposal_fund_to_cps_treasury"), - eq("Proposal 1"), eq(2), eq(testingAccount.getAddress()), eq(owner.getAddress()), + eq("Proposal 1"), eq(2), eq(2),eq(testingAccount.getAddress()), eq(owner.getAddress()), eq(bnUSD), eq(BigInteger.valueOf(100).multiply(MULTIPLIER))); - doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("reset_swap_state")); - doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("update_proposal_fund"), eq("Proposal 1"), eq(bnUSD), eq(BigInteger.valueOf(10).multiply(MULTIPLIER)), eq(1)); - doNothing().when(scoreSpy).callScore(eq(cpsTreasury), eq("send_installment_to_contributor"), eq("Proposal 1")); - doNothing().when(scoreSpy).callScore(eq(cpsTreasury), eq("send_reward_to_sponsor"), eq("Proposal 1")); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("resetSwapState")); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("updateProposalFund"), eq("Proposal 1"), eq(bnUSD), eq(BigInteger.valueOf(10).multiply(MULTIPLIER)), eq(1)); + doNothing().when(scoreSpy).callScore(eq(cpsTreasury), eq("sendInstallmentToContributor"), eq("Proposal 1"),eq(1)); + doNothing().when(scoreSpy).callScore(eq(cpsTreasury), eq("sendRewardToSponsor"), eq("Proposal 1"),eq(1)); doNothing().when(scoreSpy).callScore(eq(BigInteger.ZERO), eq(SYSTEM_ADDRESS), eq("burn")); updatePeriods(); Map proposalDetails = (Map) cpsScore.call("getProposalDetailsByHash", "Proposal 1"); + proposalDetails.remove("sponsor_vote_reason"); assertEquals(COMPLETED, proposalDetails.get("status")); Map sponsorsRecord = (Map) cpsScore.call("getSponsorsRecord"); assertEquals(1, sponsorsRecord.get(testingAccount.getAddress().toString())); - Map>> projectAmounts = (Map>>) cpsScore.call("get_project_amounts"); + Map>> projectAmounts = (Map>>) cpsScore.call("getProjectAmounts"); System.out.println("Project Amount: " + projectAmounts); - Map> amount = Map.of( - AMOUNT, Map.of( - Constants.ICX, BigInteger.ZERO, - bnUSD, BigInteger.valueOf(100).multiply(MULTIPLIER) - ) - ); + Map amount = Map.of(AMOUNT, Map.of(Constants.ICX, BigInteger.ZERO, + bnUSD, BigInteger.valueOf(100).multiply(MULTIPLIER)), + "_count", 1); assertEquals(amount, (projectAmounts.get(COMPLETED))); Map progressReportsByProposal = (Map) cpsScore.call("getProgressReportsByProposal", "Proposal 1"); assertEquals(2, progressReportsByProposal.get(COUNT)); Map claimableSponsorBond = (Map) cpsScore.call("checkClaimableSponsorBond", testingAccount.getAddress()); - assertEquals(BigInteger.valueOf(10).multiply(MULTIPLIER), claimableSponsorBond.get(bnUSD)); + assertEquals(BigInteger.valueOf(12).multiply(MULTIPLIER), claimableSponsorBond.get(bnUSD)); Map proposalsHistory = (Map) cpsScore.call("getProposalsHistory", 0); - assertEquals(List.of(proposalDetails), proposalsHistory.get(DATA)); + List> proposalHistory = (List>) proposalsHistory.get(DATA); + assertEquals(proposalDetails.size(), proposalHistory.get(0).size()); } @Test void claimSponsorBond(){ voteProgressReportAfterSubmittingProposalWithoutBudgetAdjustment(); - doNothing().when(scoreSpy).callScore(eq(bnUSDScore), eq("transfer"), eq(testingAccount.getAddress()), eq(BigInteger.valueOf(10).multiply(MULTIPLIER))); + doNothing().when(scoreSpy).callScore(eq(bnUSDScore), eq("transfer"), eq(testingAccount.getAddress()), eq(BigInteger.valueOf(12).multiply(MULTIPLIER))); contextMock.when(caller()).thenReturn(testingAccount.getAddress()); cpsScore.invoke(testingAccount, "claimSponsorBond"); Map claimableSponsorBond = (Map) cpsScore.call("checkClaimableSponsorBond", testingAccount.getAddress()); @@ -1085,16 +1295,16 @@ void sortPriorityProposals(){ void setCpsTreasury(){ contextMock.when(caller()).thenReturn(owner.getAddress()); addAdminMethod(); - cpsScore.invoke(owner, "set_cps_treasury_score", cpsTreasury); - assertEquals(cpsTreasury, cpsScore.call("get_cps_treasury_score")); + cpsScore.invoke(owner, "setCpsTreasuryScore", cpsTreasury); + assertEquals(cpsTreasury, cpsScore.call("getCpsTreasuryScore")); } @Test void setCpfTreasury(){ addAdminMethod(); contextMock.when(caller()).thenReturn(owner.getAddress()); - cpsScore.invoke(owner, "set_cpf_treasury_score", cpfTreasury); - assertEquals(cpfTreasury, cpsScore.call("get_cpf_treasury_score")); + cpsScore.invoke(owner, "setCpfTreasuryScore", cpfTreasury); + assertEquals(cpfTreasury, cpsScore.call("getCpfTreasuryScore")); } @Test @@ -1120,13 +1330,15 @@ void payPrepPenalty(){ penaltyAmount[1] = BigInteger.valueOf(10); penaltyAmount[2] = BigInteger.valueOf(15); contextMock.when(caller()).thenReturn(owner.getAddress()); - cpsScore.invoke(owner, "set_prep_penalty_amount", (Object) penaltyAmount); + cpsScore.invoke(owner, "setPrepPenaltyAmount", (Object) penaltyAmount); updateNextBlock(); - cpsScore.invoke(owner, "update_period"); + doReturn(BigInteger.TEN).when(scoreSpy).getApplicationPeriod(); + cpsScore.invoke(owner, "updatePeriod"); getPeriodStatusMethod(); - doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swap_tokens"), eq(8)); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swapTokens"), eq(8)); String[] proposal = new String[1]; proposal[0] = "Proposal 1"; + cpsScore.invoke(owner, "voteProposal", "Proposal 1", APPROVE, "reason", false); cpsScore.invoke(owner, "votePriority", (Object) proposal); @@ -1158,19 +1370,20 @@ void payPrepPenalty(){ bnUSD, BigInteger.valueOf(1000).multiply(MULTIPLIER) ); - doReturn(totalFunds).when(scoreSpy).callScore(eq(Map.class), eq(cpfTreasury), eq("get_total_funds")); - doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("transfer_proposal_fund_to_cps_treasury"), - eq("Proposal 1"), eq(2), eq(testingAccount.getAddress()), eq(owner.getAddress()), + doReturn(totalFunds).when(scoreSpy).callScore(eq(Map.class), eq(cpfTreasury), eq("getTotalFunds")); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("transferProposalFundToCpsTreasury"), + eq("Proposal 1"), eq(2),eq(testingAccount.getAddress()), eq(owner.getAddress()), eq(bnUSD), eq(BigInteger.valueOf(100).multiply(MULTIPLIER))); - doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("reset_swap_state")); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("resetSwapState")); + doReturn(BigInteger.valueOf(15)).when(scoreSpy).getVotingPeriod(); updatePeriods(); Map proposalDetails = getProposalDetailsByHash("Proposal 1"); @SuppressWarnings("unchecked") - List
denyList = (List
) cpsScore.call("get_denylist"); + List
denyList = (List
) cpsScore.call("getDenylist"); assertEquals(List.of(testingAccount5.getAddress()), denyList); @SuppressWarnings("unchecked") @@ -1178,12 +1391,12 @@ void payPrepPenalty(){ System.out.println(loginPrep); JsonObject payPenalty = new JsonObject(); - payPenalty.add("method", "pay_prep_penalty"); + payPenalty.add("method", "payPrepPenalty"); JsonObject params = new JsonObject(); payPenalty.add("params", params); JsonObject burnTokens = new JsonObject(); - burnTokens.add("method", "burn_amount"); + burnTokens.add("method", "burnAmount"); doNothing().when(scoreSpy).callScore(eq(bnUSDScore), eq("transfer"), eq(cpfTreasury), eq(new BigInteger("5000000000000000000")), eq(burnTokens.toString().getBytes())); contextMock.when(caller()).thenReturn(bnUSDScore); cpsScore.invoke(owner, "tokenFallback", testingAccount5.getAddress(), new BigInteger("5000000000000000000"), payPenalty.toString().getBytes()); @@ -1193,16 +1406,16 @@ void payPrepPenalty(){ void disqualifyProposal(){ updatePeriodAfterProposalVoting(); updateNextBlock(); - doNothing().when(scoreSpy).callScore(eq(cpsTreasury), eq("disqualify_project"), eq("Proposal 1")); + doNothing().when(scoreSpy).callScore(eq(cpsTreasury), eq("disqualifyProject"), eq("Proposal 1")); JsonObject disqualifyProject = new JsonObject(); - disqualifyProject.add("method", "burn_amount"); + disqualifyProject.add("method", "returnFundAmount"); JsonObject params = new JsonObject(); params.add(SPONSOR_ADDRESS, testingAccount.getAddress().toString()); disqualifyProject.add("params", params); - doNothing().when(scoreSpy).callScore(eq(bnUSDScore), eq("transfer"), eq(cpfTreasury), eq(BigInteger.valueOf(10).multiply(MULTIPLIER)), eq(disqualifyProject.toString().getBytes())); - cpsScore.invoke(owner, "update_period"); + doNothing().when(scoreSpy).callScore(eq(bnUSDScore), eq("transfer"), eq(cpfTreasury), eq(BigInteger.valueOf(12).multiply(MULTIPLIER)), eq(disqualifyProject.toString().getBytes())); + cpsScore.invoke(owner, "updatePeriod"); Map proposalDetails = getProposalDetailsByHash("Proposal 1"); assertEquals(PAUSED, proposalDetails.get(STATUS)); @@ -1212,32 +1425,28 @@ void disqualifyProposal(){ Map sponsorsRecord = (Map) cpsScore.call("getSponsorsRecord"); assertEquals(1, sponsorsRecord.get(testingAccount.getAddress().toString())); - Map>> projectAmounts = (Map>>) cpsScore.call("get_project_amounts"); - Map> amount = Map.of( - AMOUNT, Map.of( - Constants.ICX, BigInteger.ZERO, - bnUSD, BigInteger.valueOf(100).multiply(MULTIPLIER) - ) - ); + Map>> projectAmounts = (Map>>) cpsScore.call("getProjectAmounts"); + Map amount = Map.of(AMOUNT, Map.of(Constants.ICX, BigInteger.ZERO, + bnUSD, BigInteger.valueOf(100).multiply(MULTIPLIER)), + "_count", 1); assertEquals(amount, (projectAmounts.get(PAUSED))); updateNextBlock(); - cpsScore.invoke(owner, "update_period"); + cpsScore.invoke(owner, "updatePeriod"); proposalDetails = getProposalDetailsByHash("Proposal 1"); + proposalDetails.remove("sponsor_vote_reason"); assertEquals(DISQUALIFIED, proposalDetails.get(STATUS)); assertEquals(BOND_CANCELLED, proposalDetails.get(SPONSOR_DEPOSIT_STATUS)); - projectAmounts = (Map>>) cpsScore.call("get_project_amounts"); - amount = Map.of( - AMOUNT, Map.of( - Constants.ICX, BigInteger.ZERO, - bnUSD, BigInteger.valueOf(100).multiply(MULTIPLIER) - ) - ); + projectAmounts = (Map>>) cpsScore.call("getProjectAmounts"); + amount = Map.of(AMOUNT, Map.of(Constants.ICX, BigInteger.ZERO, + bnUSD, BigInteger.valueOf(100).multiply(MULTIPLIER)), + "_count", 1); assertEquals(amount, (projectAmounts.get(DISQUALIFIED))); Map proposalsHistory = (Map) cpsScore.call("getProposalsHistory", 0); - assertEquals(List.of(proposalDetails), proposalsHistory.get(DATA)); + List> proposalHistory = (List>) proposalsHistory.get(DATA); + assertEquals(proposalDetails.size(), proposalHistory.get(0).size()); } @Test @@ -1254,7 +1463,7 @@ void rejectSponsorVote(){ contextMock.when(caller()).thenReturn(bnUSDScore); contextMock.when(() -> Context.transfer(any(), any())).thenAnswer((Answer) invocation -> null); JsonObject sponsorVoteParams = new JsonObject(); - sponsorVoteParams.add("method", "sponsor_vote"); + sponsorVoteParams.add("method", "sponsorVote"); JsonObject params = new JsonObject(); params.add(IPFS_HASH, "Proposal 1"); params.add(VOTE, REJECT); @@ -1270,34 +1479,45 @@ void disqualifyProjectByRejectingProgressReport(){ updateNextBlock(); cpsScore.invoke(owner, "updatePeriod"); getPeriodStatusMethod(); - doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swap_tokens"), eq(8)); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swapTokens"), eq(8)); JsonObject disqualifyProject = new JsonObject(); - disqualifyProject.add("method", "burn_amount"); + disqualifyProject.add("method", "returnFundAmount"); JsonObject params = new JsonObject(); params.add(SPONSOR_ADDRESS, testingAccount.getAddress().toString()); disqualifyProject.add("params", params); - doNothing().when(scoreSpy).callScore(eq(bnUSDScore), eq("transfer"), eq(cpfTreasury), eq(BigInteger.valueOf(10).multiply(MULTIPLIER)), eq(disqualifyProject.toString().getBytes())); - cpsScore.invoke(owner, "voteProgressReport", "Proposal 1", "Report 1", REJECT, "reason", APPROVE, false); + doNothing().when(scoreSpy).callScore(eq(bnUSDScore), eq("transfer"), eq(cpfTreasury), eq(BigInteger.valueOf(12).multiply(MULTIPLIER)), eq(disqualifyProject.toString().getBytes())); + + CPSCoreInterface.MilestoneVoteAttributes milestoneVoteAttributes = new CPSCoreInterface.MilestoneVoteAttributes(); + milestoneVoteAttributes.id = 1; + milestoneVoteAttributes.vote = REJECT; + + CPSCoreInterface.MilestoneVoteAttributes[] milestoneVoteAttributesList = new CPSCoreInterface.MilestoneVoteAttributes[]{ + milestoneVoteAttributes}; + contextMock.when(caller()).thenReturn(owner.getAddress()); + cpsScore.invoke(owner, "voteProgressReport", "Report 1", "reason", milestoneVoteAttributesList ,APPROVE,false); contextMock.when(caller()).thenReturn(testingAccount.getAddress()); - cpsScore.invoke(testingAccount, "voteProgressReport", "Proposal 1", "Report 1", REJECT, "reason", APPROVE, false); + cpsScore.invoke(testingAccount, "voteProgressReport", "Report 1", "reason", milestoneVoteAttributesList ,APPROVE,false); contextMock.when(caller()).thenReturn(testingAccount1.getAddress()); - cpsScore.invoke(testingAccount1, "voteProgressReport", "Proposal 1", "Report 1", REJECT, "reason", APPROVE, false); + cpsScore.invoke(testingAccount1, "voteProgressReport", "Report 1", "reason", milestoneVoteAttributesList ,APPROVE,false); contextMock.when(caller()).thenReturn(testingAccount2.getAddress()); - cpsScore.invoke(testingAccount2, "voteProgressReport", "Proposal 1", "Report 1", REJECT, "reason", APPROVE, false); + cpsScore.invoke(testingAccount2, "voteProgressReport", "Report 1", "reason", milestoneVoteAttributesList ,APPROVE,false); contextMock.when(caller()).thenReturn(testingAccount3.getAddress()); - cpsScore.invoke(testingAccount3, "voteProgressReport", "Proposal 1", "Report 1", REJECT, "reason", APPROVE, false); + cpsScore.invoke(testingAccount3, "voteProgressReport", "Report 1", "reason", milestoneVoteAttributesList ,APPROVE,false); contextMock.when(caller()).thenReturn(testingAccount4.getAddress()); - cpsScore.invoke(testingAccount4, "voteProgressReport", "Proposal 1", "Report 1", REJECT, "reason", APPROVE, false); + cpsScore.invoke(testingAccount4, "voteProgressReport", "Report 1", "reason", milestoneVoteAttributesList ,APPROVE,false); contextMock.when(caller()).thenReturn(testingAccount5.getAddress()); - cpsScore.invoke(testingAccount5, "voteProgressReport", "Proposal 1", "Report 1", REJECT, "reason", APPROVE, false); + cpsScore.invoke(testingAccount5, "voteProgressReport", "Report 1", "reason", milestoneVoteAttributesList ,APPROVE,false); @SuppressWarnings("unchecked") - Map progressReportDetails = (Map) cpsScore.call("getProgressReportsByHash", "Report 1"); + Map progressReportDetails = (Map) cpsScore.call("getProgressReportVoteDetails", "Report 1"); assertEquals(7, progressReportDetails.get(TOTAL_VOTERS)); - assertEquals(7, progressReportDetails.get(REJECT_VOTERS)); + + Map milestoneReportDetailes = (Map) cpsScore.call("getMilestonesReport", "Proposal 1", 1); + + assertEquals(7, milestoneReportDetailes.get(REJECT_VOTERS)); contextMock.when(caller()).thenReturn(owner.getAddress()); updateNextBlock(); @@ -1307,15 +1527,15 @@ void disqualifyProjectByRejectingProgressReport(){ bnUSD, BigInteger.valueOf(1000).multiply(MULTIPLIER) ); - doReturn(totalFunds).when(scoreSpy).callScore(eq(Map.class), eq(cpfTreasury), eq("get_total_funds")); - doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("transfer_proposal_fund_to_cps_treasury"), + doReturn(totalFunds).when(scoreSpy).callScore(eq(Map.class), eq(cpfTreasury), eq("getTotalFunds")); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("transferProposalFundToCpsTreasury"), eq("Proposal 1"), eq(2), eq(testingAccount.getAddress()), eq(owner.getAddress()), eq(bnUSD), eq(BigInteger.valueOf(100).multiply(MULTIPLIER))); - doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("reset_swap_state")); - doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("update_proposal_fund"), eq("Proposal 1"), eq(bnUSD), eq(BigInteger.valueOf(10).multiply(MULTIPLIER)), eq(1)); - doNothing().when(scoreSpy).callScore(eq(cpsTreasury), eq("send_installment_to_contributor"), eq("Proposal 1")); - doNothing().when(scoreSpy).callScore(eq(cpsTreasury), eq("send_reward_to_sponsor"), eq("Proposal 1")); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("resetSwapState")); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("updateProposalFund"), eq("Proposal 1"), eq(bnUSD), eq(BigInteger.valueOf(10).multiply(MULTIPLIER)), eq(1)); + doNothing().when(scoreSpy).callScore(eq(cpsTreasury), eq("sendInstallmentToContributor"), eq("Proposal 1")); + doNothing().when(scoreSpy).callScore(eq(cpsTreasury), eq("sendRewardToSponsor"), eq("Proposal 1")); doNothing().when(scoreSpy).callScore(eq(BigInteger.ZERO), eq(SYSTEM_ADDRESS), eq("burn")); updatePeriods(); @@ -1330,33 +1550,45 @@ void disqualifyProjectByRejectingProgressReport(){ progressReport.budget_adjustment = false; progressReport.additional_budget = BigInteger.valueOf(0); progressReport.additional_month = 0; - progressReport.percentage_completed = 50; + progressReport.milestoneCompleted = new int[]{2}; +// progressReport.percentage_completed = 50; cpsScore.invoke(owner, "submitProgressReport", progressReport); + milestoneVoteAttributes = new CPSCoreInterface.MilestoneVoteAttributes(); + milestoneVoteAttributes.id = 2; + milestoneVoteAttributes.vote = REJECT; + + milestoneVoteAttributesList = new CPSCoreInterface.MilestoneVoteAttributes[]{ + milestoneVoteAttributes}; + updateNextBlock(); cpsScore.invoke(owner, "updatePeriod"); getPeriodStatusMethod(); - doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swap_tokens"), eq(8)); - doNothing().when(scoreSpy).callScore(eq(cpsTreasury), eq("disqualify_project"), eq("Proposal 1")); - cpsScore.invoke(owner, "voteProgressReport", "Proposal 1", "Report 2", REJECT, "reason", APPROVE, false); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swapTokens"), eq(8)); + doNothing().when(scoreSpy).callScore(eq(cpsTreasury), eq("disqualifyProject"), eq("Proposal 1")); + contextMock.when(caller()).thenReturn(owner.getAddress()); + cpsScore.invoke(owner, "voteProgressReport", "Report 2", "reason", milestoneVoteAttributesList ,APPROVE,false); contextMock.when(caller()).thenReturn(testingAccount.getAddress()); - cpsScore.invoke(testingAccount, "voteProgressReport", "Proposal 1", "Report 2", REJECT, "reason", APPROVE, false); + cpsScore.invoke(testingAccount, "voteProgressReport", "Report 2", "reason", milestoneVoteAttributesList ,APPROVE,false); contextMock.when(caller()).thenReturn(testingAccount1.getAddress()); - cpsScore.invoke(testingAccount1, "voteProgressReport", "Proposal 1", "Report 2", REJECT, "reason", APPROVE, false); + cpsScore.invoke(testingAccount1, "voteProgressReport", "Report 2", "reason", milestoneVoteAttributesList ,APPROVE,false); contextMock.when(caller()).thenReturn(testingAccount2.getAddress()); - cpsScore.invoke(testingAccount2, "voteProgressReport", "Proposal 1", "Report 2", REJECT, "reason", APPROVE, false); + cpsScore.invoke(testingAccount2, "voteProgressReport", "Report 2", "reason", milestoneVoteAttributesList ,APPROVE,false); contextMock.when(caller()).thenReturn(testingAccount3.getAddress()); - cpsScore.invoke(testingAccount3, "voteProgressReport", "Proposal 1", "Report 2", REJECT, "reason", APPROVE, false); + cpsScore.invoke(testingAccount3, "voteProgressReport", "Report 2", "reason", milestoneVoteAttributesList ,APPROVE,false); contextMock.when(caller()).thenReturn(testingAccount4.getAddress()); - cpsScore.invoke(testingAccount4, "voteProgressReport", "Proposal 1", "Report 2", REJECT, "reason", APPROVE, false); + cpsScore.invoke(testingAccount4, "voteProgressReport", "Report 2", "reason", milestoneVoteAttributesList ,APPROVE,false); contextMock.when(caller()).thenReturn(testingAccount5.getAddress()); - cpsScore.invoke(testingAccount5, "voteProgressReport", "Proposal 1", "Report 2", REJECT, "reason", APPROVE, false); + cpsScore.invoke(testingAccount5, "voteProgressReport", "Report 2", "reason", milestoneVoteAttributesList ,APPROVE,false); - progressReportDetails = (Map) cpsScore.call("getProgressReportsByHash", "Report 1"); + progressReportDetails = (Map) cpsScore.call("getProgressReportVoteDetails", "Report 1"); assertEquals(7, progressReportDetails.get(TOTAL_VOTERS)); - assertEquals(7, progressReportDetails.get(REJECT_VOTERS)); + + milestoneReportDetailes = (Map) cpsScore.call("getMilestonesReport", "Proposal 1", 2); + + assertEquals(7, milestoneReportDetailes.get(REJECT_VOTERS)); contextMock.when(caller()).thenReturn(owner.getAddress()); updateNextBlock(); @@ -1366,29 +1598,32 @@ void disqualifyProjectByRejectingProgressReport(){ bnUSD, BigInteger.valueOf(1000).multiply(MULTIPLIER) ); - doReturn(totalFunds).when(scoreSpy).callScore(eq(Map.class), eq(cpfTreasury), eq("get_total_funds")); - doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("transfer_proposal_fund_to_cps_treasury"), - eq("Proposal 1"), eq(2), eq(testingAccount.getAddress()), eq(owner.getAddress()), + doReturn(totalFunds).when(scoreSpy).callScore(eq(Map.class), eq(cpfTreasury), eq("getTotalFunds")); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("transferProposalFundToCpsTreasury"), + eq("Proposal 1"), eq(2),eq(testingAccount.getAddress()), eq(owner.getAddress()), eq(bnUSD), eq(BigInteger.valueOf(100).multiply(MULTIPLIER))); - doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("reset_swap_state")); - doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("update_proposal_fund"), eq("Proposal 1"), eq(bnUSD), eq(BigInteger.valueOf(10).multiply(MULTIPLIER)), eq(1)); - doNothing().when(scoreSpy).callScore(eq(cpsTreasury), eq("send_installment_to_contributor"), eq("Proposal 1")); - doNothing().when(scoreSpy).callScore(eq(cpsTreasury), eq("send_reward_to_sponsor"), eq("Proposal 1")); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("resetSwapState")); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("updateProposalFund"), eq("Proposal 1"), eq(bnUSD), eq(BigInteger.valueOf(10).multiply(MULTIPLIER)), eq(1)); + doNothing().when(scoreSpy).callScore(eq(cpsTreasury), eq("sendInstallmentToContributor"), eq("Proposal 1"),eq(1)); + doNothing().when(scoreSpy).callScore(eq(cpsTreasury), eq("sendRewardToSponsor"), eq("Proposal 1"),eq(1)); doNothing().when(scoreSpy).callScore(eq(BigInteger.ZERO), eq(SYSTEM_ADDRESS), eq("burn")); + doNothing().when(scoreSpy).callScore(eq(cpsTreasury), eq("disqualifyProject"), eq("Proposal 1")); + + + doNothing().when(scoreSpy).callScore(eq(bnUSDScore), eq("transfer"), eq(cpfTreasury), eq(BigInteger.valueOf(10).multiply(MULTIPLIER)), eq(disqualifyProject.toString().getBytes())); + + updatePeriods(); Map proposalDetails = (Map) cpsScore.call("getProposalDetailsByHash", "Proposal 1"); assertEquals(DISQUALIFIED, proposalDetails.get("status")); - Map>> projectAmounts = (Map>>) cpsScore.call("get_project_amounts"); + Map>> projectAmounts = (Map>>) cpsScore.call("getProjectAmounts"); System.out.println("Project Amount: " + projectAmounts); - Map> amount = Map.of( - AMOUNT, Map.of( - Constants.ICX, BigInteger.ZERO, - bnUSD, BigInteger.valueOf(100).multiply(MULTIPLIER) - ) - ); + Map amount = Map.of(AMOUNT, Map.of(Constants.ICX, BigInteger.ZERO, + bnUSD, BigInteger.valueOf(100).multiply(MULTIPLIER)), + "_count", 1); assertEquals(amount, (projectAmounts.get(DISQUALIFIED))); Map voteResult = (Map) cpsScore.call("getProgressReportResult", "Report 1"); @@ -1401,7 +1636,7 @@ void disqualifyProjectByRejectingProgressReport(){ @Test void setSwapCount(){ addAdminMethod(); - cpsScore.invoke(owner, "set_swap_count", 10); + cpsScore.invoke(owner, "setSwapCount", 10); assertEquals(10, cpsScore.call("getSwapCount")); } @@ -1413,7 +1648,60 @@ void fallback(){ @Test void getPeriodCount(){ - assertEquals(20, cpsScore.call("getPeriodCount")); + assertEquals(0, cpsScore.call("getPeriodCount")); + } + + @Test + void sponsorDepositsLessThanBondPercentage(){ + submitProposalMethod(); + contextMock.when(caller()).thenReturn(bnUSDScore); + + doReturn(BigInteger.valueOf(15)).when(scoreSpy).getSponsorBondPercentage(); + JsonObject sponsorVoteParams = new JsonObject(); + sponsorVoteParams.add("method", "sponsorVote"); + JsonObject params = new JsonObject(); + params.add(IPFS_HASH, "Proposal 1"); + params.add(VOTE, ACCEPT); + params.add(VOTE_REASON, "reason"); + sponsorVoteParams.add("params", params); + + Executable bondPercentageRevert = () -> cpsScore.invoke(testingAccount, "tokenFallback", testingAccount.getAddress(), BigInteger.valueOf(10).multiply(MULTIPLIER), sponsorVoteParams.toString().getBytes()); + expectErrorMessage(bondPercentageRevert,"Reverted(0): CPS Score: Deposit 15% of the total budget of the project."); + } + + @Test + void bondPercentageExceptions(){ + Executable percentageNotAdmin = () -> cpsScore.invoke(testingAccount, "setSponsorBondPercentage", BigInteger.valueOf(15)); + expectErrorMessage(percentageNotAdmin, "Reverted(0): CPS Score: Only CPF treasury can call this method"); + + doReturn(cpfTreasuryScore.getAddress()).when(scoreSpy).getCpfTreasuryScore(); + Executable percentageLessTwelve = () -> cpsScore.invoke(cpfTreasuryScore, "setSponsorBondPercentage", BigInteger.valueOf(11)); + expectErrorMessage(percentageLessTwelve, "Reverted(0): CPS Score: Cannot set bond percentage less than 12%"); + } + + @Test + void setApplicationPeriodExceptions(){ + Executable setPeriodNotAdmin = () -> cpsScore.invoke(testingAccount, "setPeriod", BigInteger.valueOf(10)); + expectErrorMessage(setPeriodNotAdmin, "Reverted(0): CPS Score: Only CPF treasury can call this method"); + + + doReturn(cpfTreasuryScore.getAddress()).when(scoreSpy).getCpfTreasuryScore(); + Executable periodis15 = () -> cpsScore.invoke(cpfTreasuryScore, "setPeriod", BigInteger.valueOf(28)); + expectErrorMessage(periodis15, "Reverted(0): CPS Score: Voting period must be more than or equal to 10 days"); + + } + + @Test + void setPeriod(){ + + doReturn(cpfTreasuryScore.getAddress()).when(scoreSpy).getCpfTreasuryScore(); + cpsScore.invoke(cpfTreasuryScore, "setPeriod", BigInteger.valueOf(20)); + + BigInteger applicationPeriod = (BigInteger) cpsScore.call("getApplicationPeriod"); + assertEquals(applicationPeriod,BigInteger.valueOf(20)); + + BigInteger votingPeriod = (BigInteger) cpsScore.call("getVotingPeriod"); + assertEquals(votingPeriod,BigInteger.valueOf(10)); } diff --git a/CPSCore/src/test/java/community/icon/cps/score/cpscore/MigrationTest.java b/CPSCore/src/test/java/community/icon/cps/score/cpscore/MigrationTest.java new file mode 100644 index 00000000..1841d31e --- /dev/null +++ b/CPSCore/src/test/java/community/icon/cps/score/cpscore/MigrationTest.java @@ -0,0 +1,350 @@ +package community.icon.cps.score.cpscore; + +import com.eclipsesource.json.JsonObject; +import com.iconloop.score.test.Account; +import community.icon.cps.score.cpscore.utils.Constants; +import community.icon.cps.score.lib.interfaces.CPSCoreInterface; +import org.junit.jupiter.api.Test; +import score.Context; + +import java.math.BigInteger; +import java.util.List; +import java.util.Map; + +import static community.icon.cps.score.cpscore.utils.Constants.ABSTAIN; +import static community.icon.cps.score.cpscore.utils.Constants.ABSTAINED_VOTES; +import static community.icon.cps.score.cpscore.utils.Constants.ABSTAIN_VOTERS; +import static community.icon.cps.score.cpscore.utils.Constants.ACCEPT; +import static community.icon.cps.score.cpscore.utils.Constants.APPROVE; +import static community.icon.cps.score.cpscore.utils.Constants.APPROVED_REPORTS; +import static community.icon.cps.score.cpscore.utils.Constants.APPROVED_VOTES; +import static community.icon.cps.score.cpscore.utils.Constants.APPROVE_VOTERS; +import static community.icon.cps.score.cpscore.utils.Constants.CONTRIBUTOR_ADDRESS; +import static community.icon.cps.score.cpscore.utils.Constants.IPFS_HASH; +import static community.icon.cps.score.cpscore.utils.Constants.IS_MILESTONE; +import static community.icon.cps.score.cpscore.utils.Constants.MILESTONE_COUNT; +import static community.icon.cps.score.cpscore.utils.Constants.PROJECT_DURATION; +import static community.icon.cps.score.cpscore.utils.Constants.PROJECT_TITLE; +import static community.icon.cps.score.cpscore.utils.Constants.REJECT; +import static community.icon.cps.score.cpscore.utils.Constants.SPONSOR_ADDRESS; +import static community.icon.cps.score.cpscore.utils.Constants.SPONSOR_DEPOSIT_AMOUNT; +import static community.icon.cps.score.cpscore.utils.Constants.STATUS; +import static community.icon.cps.score.cpscore.utils.Constants.TIMESTAMP; +import static community.icon.cps.score.cpscore.utils.Constants.TOTAL_BUDGET; +import static community.icon.cps.score.cpscore.utils.Constants.TOTAL_VOTERS; +import static community.icon.cps.score.cpscore.utils.Constants.TOTAL_VOTES; +import static community.icon.cps.score.cpscore.utils.Constants.VOTE; +import static community.icon.cps.score.cpscore.utils.Constants.VOTE_REASON; +import static community.icon.cps.score.cpscore.utils.Constants.bnUSD; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; + +public class MigrationTest extends CPSScoreTest { + private static final Account alice = sm.createAccount(); + + private void submitOldProposal(){ + registerPrepsMethod(); + CPSCoreInterface.ProposalAttributes proposalAttributes = new CPSCoreInterface.ProposalAttributes(); + proposalAttributes.ipfs_hash = "Proposal 1"; + proposalAttributes.project_title = "Title"; + proposalAttributes.project_duration = 2; + proposalAttributes.total_budget = BigInteger.valueOf(100); + proposalAttributes.token = bnUSD; + proposalAttributes.sponsor_address = testingAccount.getAddress(); + proposalAttributes.ipfs_link = "link"; + proposalAttributes.milestoneCount = 2; + + Map remainingSwapAmount = Map.of( + "remaining_swap_amount", BigInteger.valueOf(1000).multiply(MULTIPLIER), + "maxCap", BigInteger.valueOf(1000).multiply(MULTIPLIER)); + doReturn(remainingSwapAmount).when(scoreSpy).callScore(eq(Map.class), eq(cpfTreasury), eq("getRemainingSwapAmount")); + contextMock.when(() -> Context.getValue()).thenReturn(BigInteger.valueOf(50).multiply(MULTIPLIER)); + byte [] tx_hash = "transaction".getBytes(); + contextMock.when(() -> Context.getTransactionHash()).thenReturn(tx_hash); + doNothing().when(scoreSpy).callScore(eq(BigInteger.valueOf(25).multiply(MULTIPLIER)), eq(SYSTEM_ADDRESS), eq("burn")); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swapTokens"), eq(0)); + + contextMock.when(caller()).thenReturn(alice.getAddress()); + cpsScore.invoke(alice,"submitProposal",proposalAttributes ); + } + + private void migrateProposal(){ + CPSCoreInterface.ProposalAttributes proposalAttributes = new CPSCoreInterface.ProposalAttributes(); + proposalAttributes.ipfs_hash = "New Proposal 1"; + proposalAttributes.project_title = "Title"; + proposalAttributes.project_duration = 2; + proposalAttributes.total_budget = BigInteger.valueOf(100); + proposalAttributes.token = bnUSD; + proposalAttributes.sponsor_address = testingAccount.getAddress(); + proposalAttributes.ipfs_link = "link"; + proposalAttributes.milestoneCount = 2; + proposalAttributes.isMilestone = true; + + int[] milestones = new int[]{1,2}; + + contextMock.when(caller()).thenReturn(alice.getAddress()); + cpsScore.invoke(alice,"submitProposalMock",proposalAttributes,"Proposal 1", milestones); + } + + @Test + void submitedProposalMigration() throws InterruptedException { + String oldHash = "Proposal 1"; + String newHash = "New Proposal 1"; + submitOldProposal(); + + Map proposalDetails = (Map) cpsScore.call("getProposalDetailsByHash", + oldHash); + List proposalKeys = (List) cpsScore.call("getProposalKeys"); + assertEquals(proposalKeys.get(0),"Proposal 1"); + + Thread.sleep(5); + migrateProposal(); + + Map newProposalDetails = (Map) cpsScore.call("getProposalDetailsByHash", + newHash); + // asserting the proposal details + assertEquals(proposalDetails.get(PROJECT_TITLE),newProposalDetails.get(PROJECT_TITLE)); + assertEquals(proposalDetails.get(TOTAL_BUDGET),newProposalDetails.get(TOTAL_BUDGET)); + assertEquals(proposalDetails.get(PROJECT_DURATION),newProposalDetails.get(PROJECT_DURATION)); + assertEquals(proposalDetails.get(APPROVED_REPORTS),newProposalDetails.get(APPROVED_REPORTS)); + assertEquals(proposalDetails.get(SPONSOR_ADDRESS),newProposalDetails.get(SPONSOR_ADDRESS)); + assertEquals(proposalDetails.get(CONTRIBUTOR_ADDRESS),newProposalDetails.get(CONTRIBUTOR_ADDRESS)); + assertEquals(proposalDetails.get(STATUS),newProposalDetails.get(STATUS)); + assertEquals(proposalDetails.get(TOTAL_VOTES),newProposalDetails.get(TOTAL_VOTES)); + assertEquals(proposalDetails.get(APPROVED_VOTES),newProposalDetails.get(APPROVED_VOTES)); + assertEquals(proposalDetails.get(ABSTAINED_VOTES),newProposalDetails.get(ABSTAINED_VOTES)); + assertEquals(proposalDetails.get(SPONSOR_DEPOSIT_AMOUNT),newProposalDetails.get(SPONSOR_DEPOSIT_AMOUNT)); + assertEquals(proposalDetails.get(TIMESTAMP),newProposalDetails.get(TIMESTAMP)); + + // old proposal details + assertEquals(proposalDetails.get(IPFS_HASH),oldHash); + assertEquals(proposalDetails.get(IS_MILESTONE),true); + + // new proposal details + assertEquals(newProposalDetails.get(IPFS_HASH),newHash); + assertEquals(newProposalDetails.get(MILESTONE_COUNT),2); + assertEquals(newProposalDetails.get(IS_MILESTONE),true); + + proposalKeys = (List) cpsScore.call("getProposalKeys"); + assertEquals(proposalKeys.get(0),"New Proposal 1"); + + + } + + private void submitSponsorVote(String ipfsHash){ + contextMock.when(caller()).thenReturn(bnUSDScore); + JsonObject sponsorVoteParams = new JsonObject(); + sponsorVoteParams.add("method", "sponsorVote"); + JsonObject params = new JsonObject(); + params.add(IPFS_HASH, ipfsHash); + params.add(VOTE, ACCEPT); + params.add(VOTE_REASON, "reason"); + sponsorVoteParams.add("params", params); + + cpsScore.invoke(testingAccount, "tokenFallback", testingAccount.getAddress(), + BigInteger.valueOf(12).multiply(MULTIPLIER), sponsorVoteParams.toString().getBytes()); + } + + private void voteProposal1(){ + contextMock.when(caller()).thenReturn(owner.getAddress()); + updateNextBlock(); + doReturn(BigInteger.valueOf(15)).when(scoreSpy).getApplicationPeriod(); + cpsScore.invoke(owner, "updatePeriod"); + getPeriodStatusMethod(); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swapTokens"), eq(8)); + String[] proposal = new String[]{"Proposal 1"}; + + cpsScore.invoke(owner, "voteProposal", "Proposal 1", APPROVE, "voting okay", false); + cpsScore.invoke(owner, "votePriority", (Object) proposal); + + contextMock.when(caller()).thenReturn(testingAccount.getAddress()); + cpsScore.invoke(testingAccount, "voteProposal", "Proposal 1", APPROVE, "reason", false); + cpsScore.invoke(owner, "votePriority", (Object) proposal); + + contextMock.when(caller()).thenReturn(testingAccount1.getAddress()); + cpsScore.invoke(testingAccount1, "voteProposal", "Proposal 1", APPROVE, "reason", false); + cpsScore.invoke(owner, "votePriority", (Object) proposal); + + contextMock.when(caller()).thenReturn(testingAccount2.getAddress()); + cpsScore.invoke(testingAccount2, "voteProposal", "Proposal 1", APPROVE, "reason", false); + cpsScore.invoke(owner, "votePriority", (Object) proposal); + + contextMock.when(caller()).thenReturn(testingAccount3.getAddress()); + cpsScore.invoke(testingAccount3, "voteProposal", "Proposal 1", APPROVE, "reason", false); + cpsScore.invoke(owner, "votePriority", (Object) proposal); + + contextMock.when(caller()).thenReturn(testingAccount4.getAddress()); + cpsScore.invoke(testingAccount4, "voteProposal", "Proposal 1", ABSTAIN, "I am neutral", false); + cpsScore.invoke(owner, "votePriority", (Object) proposal); + + contextMock.when(caller()).thenReturn(testingAccount5.getAddress()); + cpsScore.invoke(testingAccount5, "voteProposal", "Proposal 1", REJECT, "I am rejecting", false); + cpsScore.invoke(owner, "votePriority", (Object) proposal); + } + + @Test + void votedProposalMigration() throws InterruptedException { + String oldHash = "Proposal 1"; + String newHash = "New Proposal 1"; + + submitOldProposal(); + submitSponsorVote(oldHash); + voteProposal1(); + + Map proposalDetails = (Map) cpsScore.call("getProposalDetailsByHash", + oldHash); + + Map oldVoteResult = (Map) cpsScore.call("getVoteResult", + oldHash); + + Thread.sleep(5); + migrateProposal(); + + Map newProposalDetails = (Map) cpsScore.call("getProposalDetailsByHash", + newHash); + Map migratedVoteResult = (Map) cpsScore.call("getVoteResult", + oldHash); + + // asserting the proposal details + assertEquals(proposalDetails.get(APPROVED_REPORTS),newProposalDetails.get(APPROVED_REPORTS)); + assertEquals(proposalDetails.get(STATUS),newProposalDetails.get(STATUS)); + assertEquals(proposalDetails.get(TOTAL_VOTES),newProposalDetails.get(TOTAL_VOTES)); + assertEquals(proposalDetails.get(TOTAL_VOTERS),newProposalDetails.get(TOTAL_VOTERS)); + assertEquals(proposalDetails.get(APPROVED_VOTES),newProposalDetails.get(APPROVED_VOTES)); + assertEquals(proposalDetails.get(APPROVE_VOTERS),newProposalDetails.get(APPROVE_VOTERS)); + assertEquals(proposalDetails.get(ABSTAINED_VOTES),newProposalDetails.get(ABSTAINED_VOTES)); + assertEquals(proposalDetails.get(ABSTAIN_VOTERS),newProposalDetails.get(ABSTAIN_VOTERS)); + assertEquals(proposalDetails.get(TIMESTAMP),newProposalDetails.get(TIMESTAMP)); + + + // comparing voter's reason + List> oldVoters = (List>) oldVoteResult.get("data"); + + List> migratedVoters = (List>) migratedVoteResult.get("data"); + assertEquals(oldVoters,migratedVoters); + } + + private void submitProgressReport1(){ + CPSCoreInterface.ProgressReportAttributes progressReport = new CPSCoreInterface.ProgressReportAttributes(); + progressReport.ipfs_hash = "Proposal 1"; + progressReport.report_hash = "Report 1"; + progressReport.ipfs_link = "Link"; + progressReport.progress_report_title = "Progress Report Title"; + progressReport.budget_adjustment = false; + progressReport.additional_budget = BigInteger.ZERO; + progressReport.additional_month = 0; + progressReport.milestoneCompleted = new int[]{1}; + + + contextMock.when(caller()).thenReturn(alice.getAddress()); + cpsScore.invoke(alice, "submitProgressReport", progressReport); + } + + private void voteOnProgressReport(){ + CPSCoreInterface.MilestoneVoteAttributes milestoneVoteAttributes= new CPSCoreInterface.MilestoneVoteAttributes(); + milestoneVoteAttributes.vote = APPROVE; + milestoneVoteAttributes.id = 1; + + CPSCoreInterface.MilestoneVoteAttributes[] milestoneVoteAttributesList = new CPSCoreInterface.MilestoneVoteAttributes[]{ + milestoneVoteAttributes}; +// doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("swap_tokens"), eq(8)); + + cpsScore.invoke(owner, "voteProgressReport", "Report 1", "reason", milestoneVoteAttributesList ,"_reject",false); + + contextMock.when(caller()).thenReturn(testingAccount.getAddress()); + cpsScore.invoke(testingAccount, "voteProgressReport", "Report 1", "reason", (Object)milestoneVoteAttributesList ,"_reject",false); + + contextMock.when(caller()).thenReturn(testingAccount1.getAddress()); + cpsScore.invoke(testingAccount1, "voteProgressReport", "Report 1", "reason", milestoneVoteAttributesList ,"_reject",false); + + contextMock.when(caller()).thenReturn(testingAccount2.getAddress()); + cpsScore.invoke(testingAccount2, "voteProgressReport", "Report 1", "reason", (Object)milestoneVoteAttributesList ,"_reject",false); + + contextMock.when(caller()).thenReturn(testingAccount3.getAddress()); + cpsScore.invoke(testingAccount3, "voteProgressReport", "Report 1", "reason", (Object)milestoneVoteAttributesList ,"_reject",false); + + contextMock.when(caller()).thenReturn(testingAccount4.getAddress()); + cpsScore.invoke(testingAccount4, "voteProgressReport", "Report 1", "reason", (Object)milestoneVoteAttributesList ,"_reject",false); + + contextMock.when(caller()).thenReturn(testingAccount5.getAddress()); + cpsScore.invoke(testingAccount5, "voteProgressReport", "Report 1", "reason", (Object)milestoneVoteAttributesList ,"_reject",false); + + } + + + + @Test + void submitAndVoteProgressReport(){ + String oldHash = "Proposal 1"; + + submitOldProposal(); + submitSponsorVote(oldHash); + voteProposal1(); + + contextMock.when(caller()).thenReturn(owner.getAddress()); + updateNextBlock(); + Map totalFunds = Map.of( + Constants.ICX, BigInteger.valueOf(1000).multiply(MULTIPLIER), + bnUSD, BigInteger.valueOf(1000).multiply(MULTIPLIER) + ); + doReturn(totalFunds).when(scoreSpy).callScore(eq(Map.class), eq(cpfTreasury), eq("getTotalFunds")); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("transferProposalFundToCpsTreasury"), + eq("Proposal 1"), eq(2), eq(testingAccount.getAddress()), eq(alice.getAddress()), + eq(bnUSD), eq(BigInteger.valueOf(100).multiply(MULTIPLIER))); + + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("resetSwapState")); + doReturn(BigInteger.valueOf(15)).when(scoreSpy).getVotingPeriod(); + updatePeriods(); + + contextMock.when(caller()).thenReturn(alice.getAddress()); + submitProgressReport1(); + + contextMock.when(caller()).thenReturn(owner.getAddress()); + updateNextBlock(); + cpsScore.invoke(owner, "updatePeriod"); + voteOnProgressReport(); + } + + + + + + @Test + void updatePeriodAfterVotingProgressReport(){ + String newHash = "New Proposal 1"; + + submitAndVoteProgressReport(); + contextMock.when(caller()).thenReturn(owner.getAddress()); + updateNextBlock(); + + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("resetSwapState")); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("updateProposalFund"), eq("Proposal 1"), eq(bnUSD), eq(BigInteger.valueOf(10).multiply(MULTIPLIER)), eq(1)); + doNothing().when(scoreSpy).callScore(eq(cpsTreasury), eq("sendInstallmentToContributor"), eq("Proposal 1"),eq(1)); + doNothing().when(scoreSpy).callScore(eq(cpsTreasury), eq("sendRewardToSponsor"), eq("Proposal 1"),eq(1)); + doNothing().when(scoreSpy).callScore(eq(BigInteger.ZERO), eq(SYSTEM_ADDRESS), eq("burn")); + + updatePeriods(); + + + // proposal with old hash + Map progressReportDetails = (Map) cpsScore.call("getProgressReports", + "_approved",0); + Map oldHashData = (Map)(((List) progressReportDetails.get("data")).get(0)); + assertEquals(oldHashData.get(IPFS_HASH),"Proposal 1"); + assertEquals(oldHashData.get(STATUS),"_approved"); + + migrateProposal(); + + // proposal with new hash + Map newProgressReportDetails = (Map) cpsScore.call("getProgressReports", + "_approved",0); + Map newHashData = (Map)(((List) newProgressReportDetails.get("data")).get(0)); + assertEquals(newHashData.get(IPFS_HASH),"New Proposal 1"); + assertEquals(newHashData.get(STATUS),"_approved"); + + } + + +} diff --git a/CPSTreasury/build.gradle b/CPSTreasury/build.gradle index 0fd824d8..ee65a3f1 100644 --- a/CPSTreasury/build.gradle +++ b/CPSTreasury/build.gradle @@ -1,4 +1,4 @@ -version = '0.9.1' +version = '1.3.2' dependencies { compileOnly 'foundation.icon:javaee-api:0.9.2' @@ -44,6 +44,11 @@ deployJar { nid = 0x7 to = 'cx3e2a9648e4365added55bfa6a84e515d99f1bb67' } + mainnet { + uri = 'https://ctz.solidwallet.io/api/v3' + nid = 0x1 + to = 'cxd965531d1cce5daad1d1d3ee1efb39ce68f442fc' + } } keystore = rootProject.hasProperty('keystoreName') ? "$keystoreName" : '' password = rootProject.hasProperty('keystorePass') ? "$keystorePass" : '' diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java index 995a2bee..90cfaf54 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/CPSTreasury.java @@ -1,10 +1,11 @@ package community.icon.cps.score.cpstreasury; -import community.icon.cps.score.cpstreasury.db.ProposalData; -import community.icon.cps.score.cpstreasury.utils.ArrayDBUtils; -import score.*; import com.eclipsesource.json.Json; import com.eclipsesource.json.JsonObject; +import community.icon.cps.score.cpstreasury.db.ProposalData; +import community.icon.cps.score.cpstreasury.utils.consts; +import community.icon.cps.score.lib.interfaces.CPSTreasuryInterface; +import score.*; import score.annotation.EventLog; import score.annotation.External; import score.annotation.Payable; @@ -14,9 +15,7 @@ import java.util.List; import java.util.Map; -import community.icon.cps.score.lib.interfaces.CPSTreasuryInterface; - -import community.icon.cps.score.cpstreasury.utils.consts; +import static community.icon.cps.score.cpstreasury.utils.ArrayDBUtils.replaceArrayItem; public class CPSTreasury extends ProposalData implements CPSTreasuryInterface { private static final String TAG = "CPS_TREASURY"; @@ -34,6 +33,13 @@ public class CPSTreasury extends ProposalData implements CPSTreasuryInterface { private static final String COMPLETED = "completed"; private static final String CONTRIBUTOR_PROJECTS = "contributor_projects"; private static final String SPONSOR_PROJECTS = "sponsor_projects"; + public static final String ONSET_PAYMENT = "onset_payment"; + public static final String DATA = "data"; + public static final String PROJECT_COUNT = "project_count"; + public static final String TOTAL_AMOUNT = "total_amount"; + public static final String WITHDRAWN_ICX = "withdraw_amount_icx"; + public static final String WITHDRAWN_BNUSD = "withdraw_amount_bnUSD"; + public static final String TOTAL_SPONSOR_BOND = "total_sponsor_bond"; private final ArrayDB proposalsKeys = Context.newArrayDB(PROPOSALS_KEYS, String.class); private final DictDB proposalsKeyListIndex = Context.newDictDB(PROPOSALS_KEY_LIST_INDEX, Integer.class); @@ -44,9 +50,15 @@ public class CPSTreasury extends ProposalData implements CPSTreasuryInterface { private final VarDB
balancedDollar = Context.newVarDB(BALANCED_DOLLAR, Address.class); private final BranchDB> contributorProjects = Context.newBranchDB(CONTRIBUTOR_PROJECTS, String.class); private final BranchDB> sponsorProjects = Context.newBranchDB(SPONSOR_PROJECTS, String.class); - private final VarDB batchSize = Context.newVarDB("batch_size", Integer.class); + private final VarDB onsetPaymentPercentage = Context.newVarDB(ONSET_PAYMENT, BigInteger.class); + + private static final BigInteger HUNDRED = BigInteger.valueOf(100); + public static final BigInteger MAX_ONSET_PAYMENT = BigInteger.valueOf(20); public CPSTreasury() { + if (onsetPaymentPercentage.get() == null) { + onsetPaymentPercentage.set(BigInteger.TEN); + } } @Override @@ -70,7 +82,7 @@ private Boolean proposalExists(String _ipfs_key) { } private void validateAdmins() { - Boolean isAdmin = callScore(Boolean.class, cpsScore.get(), "is_admin", Context.getCaller()); + Boolean isAdmin = callScore(Boolean.class, cpsScore.get(), "isAdmin", Context.getCaller()); Context.require(isAdmin, TAG + ": Only admins can call this method"); } @@ -97,9 +109,9 @@ private void addRecord(ProposalAttributes _proposal) { @Override @External - public void setCpsScore(Address _score) { - validateAdminScore(_score); - cpsScore.set(_score); + public void setCpsScore(Address score) { + validateAdminScore(score); + cpsScore.set(score); } @Override @@ -110,9 +122,9 @@ public Address getCpsScore() { @Override @External - public void setCpfTreasuryScore(Address _score) { - validateAdminScore(_score); - cpfTreasuryScore.set(_score); + public void setCpfTreasuryScore(Address score) { + validateAdminScore(score); + cpfTreasuryScore.set(score); } @Override @@ -123,65 +135,82 @@ public Address getCpfTreasuryScore() { @Override @External - public void setBnUSDScore(Address _score) { - validateAdminScore(_score); - balancedDollar.set(_score); + public void setBnUSDScore(Address score) { + validateAdminScore(score); + balancedDollar.set(score); } @Override - @External + @External(readonly = true) public Address getBnUSDScore() { return balancedDollar.get(); } + @External + public void setOnsetPayment(BigInteger paymentPercentage) { + Context.require(Context.getCaller().equals(cpfTreasuryScore.get()), TAG + ": Only receiving from " + + cpfTreasuryScore.get()); + Context.require(paymentPercentage.compareTo(MAX_ONSET_PAYMENT) <= 0, + TAG + ": Initial payment cannot be greater than " + MAX_ONSET_PAYMENT + " percentage"); + + BigInteger bondPercentage = callScore(BigInteger.class, getCpsScore(), "getSponsorBondPercentage"); + Context.require(paymentPercentage.compareTo(bondPercentage) <= 0, + TAG + ": Payment cannot be greater than sponsor bond percentage"); + + onsetPaymentPercentage.set(paymentPercentage); + } + + @External(readonly = true) + public BigInteger getOnsetPayment() { + return onsetPaymentPercentage.get(); + } + + @Override @External(readonly = true) - public Map get_contributor_projected_fund(Address _wallet_address) { - BigInteger totalAmountToBePaidICX = BigInteger.ZERO; + public Map getContributorProjectedFund(Address walletAddress) { BigInteger totalAmountToBePaidbnUSD = BigInteger.ZERO; List> projectDetails = new ArrayList<>(); - ArrayDB proposalKeysArray = contributorProjects.at(_wallet_address.toString()); + ArrayDB proposalKeysArray = contributorProjects.at(walletAddress.toString()); int proposalKeysSize = proposalKeysArray.size(); for (int i = 0; i < proposalKeysSize; i++) { String _ipfs_key = proposalKeysArray.get(i); String proposalPrefix = proposalPrefix(_ipfs_key); Map proposal_details = getDataFromProposalDB(proposalPrefix); if (!proposal_details.get(consts.STATUS).equals(DISQUALIFIED)) { - if (proposal_details.get(consts.CONTRIBUTOR_ADDRESS).equals(_wallet_address)) { - int totalInstallment = (int) proposal_details.get(consts.PROJECT_DURATION); - int totalPaidCount = totalInstallment - (int) proposal_details.get(consts.INSTALLMENT_COUNT); - - if (totalPaidCount < totalInstallment) { - String flag = (String) proposal_details.get(consts.TOKEN); - BigInteger totalBudget = (BigInteger) proposal_details.get(consts.TOTAL_BUDGET); - BigInteger totalPaidAmount = (BigInteger) proposal_details.get(consts.WITHDRAW_AMOUNT); - - Map project_details = Map.of( - consts.IPFS_HASH, _ipfs_key, - consts.TOKEN, flag, - consts.TOTAL_BUDGET, totalBudget, - consts.TOTAL_INSTALLMENT_PAID, totalPaidAmount, - consts.TOTAL_INSTALLMENT_COUNT, totalInstallment, - consts.TOTAL_TIMES_INSTALLMENT_PAID, totalPaidCount, - consts.INSTALLMENT_AMOUNT, totalBudget.divide(BigInteger.valueOf(totalInstallment))); - - projectDetails.add(project_details); - if (flag.equals(consts.ICX)) { - totalAmountToBePaidICX = totalAmountToBePaidICX.add(totalBudget.divide(BigInteger.valueOf(totalInstallment))); - } else { - totalAmountToBePaidbnUSD = totalAmountToBePaidbnUSD.add(totalBudget.divide(BigInteger.valueOf(totalInstallment))); - } - } + + int totalInstallment = (int) proposal_details.get(consts.PROJECT_DURATION); + int totalPaidCount = totalInstallment - (int) proposal_details.get(consts.INSTALLMENT_COUNT); + + if (totalPaidCount < totalInstallment) { + String flag = (String) proposal_details.get(consts.TOKEN); + BigInteger totalBudget = (BigInteger) proposal_details.get(consts.TOTAL_BUDGET); + BigInteger totalPaidAmount = (BigInteger) proposal_details.get(consts.WITHDRAW_AMOUNT); + + BigInteger remainingAmount = totalBudget.subtract(totalPaidAmount); + Map project_details = Map.of( + consts.IPFS_HASH, _ipfs_key, + consts.TOKEN, flag, + consts.TOTAL_BUDGET, totalBudget, + consts.TOTAL_INSTALLMENT_PAID, totalPaidAmount, + consts.TOTAL_INSTALLMENT_COUNT, totalInstallment, + consts.TOTAL_TIMES_INSTALLMENT_PAID, totalPaidCount, + consts.INSTALLMENT_AMOUNT, remainingAmount.divide(BigInteger.valueOf(totalInstallment - totalPaidCount))); + + projectDetails.add(project_details); + + totalAmountToBePaidbnUSD = totalAmountToBePaidbnUSD.add(totalBudget.divide(BigInteger.valueOf(totalInstallment))); + } + } } - DictDB installmentRecord = installmentFundRecord.at(_wallet_address.toString()); + DictDB installmentRecord = installmentFundRecord.at(walletAddress.toString()); return Map.of( - "data", projectDetails, - "project_count", projectDetails.size(), - "total_amount", Map.of("ICX", totalAmountToBePaidICX, "bnUSD", totalAmountToBePaidbnUSD), - "withdraw_amount_icx", installmentRecord.getOrDefault(consts.ICX, BigInteger.ZERO), - "withdraw_amount_bnUSD", installmentRecord.getOrDefault(consts.bnUSD, BigInteger.ZERO)); + DATA, projectDetails, + PROJECT_COUNT, projectDetails.size(), + TOTAL_AMOUNT, Map.of(consts.bnUSD, totalAmountToBePaidbnUSD), + WITHDRAWN_BNUSD, installmentRecord.getOrDefault(consts.bnUSD, BigInteger.ZERO)); } @Override @@ -206,59 +235,56 @@ public List getSponsorProjects(Address address) { @Override @External(readonly = true) - public Map get_sponsor_projected_fund(Address _wallet_address) { + public Map getSponsorProjectedFund(Address walletAddress) { ProposalData proposalData = new ProposalData(); - BigInteger totalAmountToBePaidICX = BigInteger.ZERO; BigInteger totalAmountToBePaidbnUSD = BigInteger.ZERO; - BigInteger totalSponsorBondICX = BigInteger.ZERO; BigInteger totalSponsorBondbnUSD = BigInteger.ZERO; List> projectDetails = new ArrayList<>(); - ArrayDB proposalKeysArray = sponsorProjects.at(_wallet_address.toString()); + ArrayDB proposalKeysArray = sponsorProjects.at(walletAddress.toString()); int proposalKeysSize = proposalKeysArray.size(); for (int i = 0; i < proposalKeysSize; i++) { String _ipfs_key = proposalKeysArray.get(i); String proposalPrefix = proposalPrefix(_ipfs_key); Map proposal_details = proposalData.getDataFromProposalDB(proposalPrefix); if (!proposal_details.get(consts.STATUS).equals(DISQUALIFIED)) { - if (proposal_details.get(consts.SPONSOR_ADDRESS).equals(_wallet_address)) { - int totalInstallment = (int) proposal_details.get(consts.PROJECT_DURATION); - int totalPaidCount = totalInstallment - (int) proposal_details.get(consts.SPONSOR_REWARD_COUNT); - if (totalPaidCount < totalInstallment) { - String flag = (String) proposal_details.get(consts.TOKEN); - BigInteger totalBudget = (BigInteger) proposal_details.get(consts.SPONSOR_REWARD); - BigInteger totalPaidAmount = (BigInteger) proposal_details.get(consts.WITHDRAW_AMOUNT); - BigInteger depositedSponsorBond = ((BigInteger) proposal_details.get(consts.TOTAL_BUDGET)).divide(BigInteger.TEN); - - Map project_details = Map.of( - consts.IPFS_HASH, _ipfs_key, - consts.TOKEN, flag, - consts.TOTAL_BUDGET, totalBudget, - consts.TOTAL_INSTALLMENT_PAID, totalPaidAmount, - consts.TOTAL_INSTALLMENT_COUNT, totalInstallment, - consts.TOTAL_TIMES_INSTALLMENT_PAID, totalPaidCount, - consts.INSTALLMENT_AMOUNT, totalBudget.divide(BigInteger.valueOf(totalInstallment)), - consts.SPONSOR_BOND_AMOUNT, depositedSponsorBond); - - projectDetails.add(project_details); - if (flag.equals(consts.ICX)) { - totalAmountToBePaidICX = totalAmountToBePaidICX.add(totalBudget.divide(BigInteger.valueOf(totalInstallment))); - totalSponsorBondICX = totalSponsorBondICX.add(depositedSponsorBond); - } else { - totalAmountToBePaidbnUSD = totalAmountToBePaidbnUSD.add(totalBudget.divide(BigInteger.valueOf(totalInstallment))); - totalSponsorBondbnUSD = totalSponsorBondbnUSD.add(depositedSponsorBond); - } - } + + int totalInstallment = (int) proposal_details.get(consts.PROJECT_DURATION); + int totalPaidCount = totalInstallment - (int) proposal_details.get(consts.SPONSOR_REWARD_COUNT); + if (totalPaidCount < totalInstallment) { + String flag = (String) proposal_details.get(consts.TOKEN); + BigInteger totalBudget = (BigInteger) proposal_details.get(consts.SPONSOR_REWARD); + BigInteger totalPaidAmount = (BigInteger) proposal_details.get(consts.SPONSOR_WITHDRAW_AMOUNT); + BigInteger depositedSponsorBond = ((BigInteger) proposal_details.get(consts.TOTAL_BUDGET)).divide(BigInteger.TEN); + BigInteger remainingAmount = totalBudget.subtract(totalPaidAmount); + + Map project_details = Map.of( + consts.IPFS_HASH, _ipfs_key, + consts.TOKEN, flag, + consts.TOTAL_BUDGET, totalBudget, + consts.TOTAL_INSTALLMENT_PAID, totalPaidAmount, + consts.TOTAL_INSTALLMENT_COUNT, totalInstallment, + consts.TOTAL_TIMES_INSTALLMENT_PAID, totalPaidCount, + consts.INSTALLMENT_AMOUNT, remainingAmount.divide(BigInteger.valueOf(totalInstallment - totalPaidCount)), + consts.SPONSOR_BOND_AMOUNT, depositedSponsorBond); + + projectDetails.add(project_details); + + + totalAmountToBePaidbnUSD = totalAmountToBePaidbnUSD.add(totalBudget.divide(BigInteger.valueOf(totalInstallment))); + totalSponsorBondbnUSD = totalSponsorBondbnUSD.add(depositedSponsorBond); + } + } } - DictDB installmentRecord = installmentFundRecord.at(_wallet_address.toString()); + DictDB installmentRecord = installmentFundRecord.at(walletAddress.toString()); return Map.of( - "data", projectDetails, - "project_count", projectDetails.size(), - "total_amount", Map.of("ICX", totalAmountToBePaidICX, "bnUSD", totalAmountToBePaidbnUSD), - "withdraw_amount_icx", installmentRecord.getOrDefault(consts.ICX, BigInteger.ZERO), - "withdraw_amount_bnUSD", installmentRecord.getOrDefault(consts.bnUSD, BigInteger.ZERO), - "total_sponsor_bond", Map.of("ICX", totalSponsorBondICX, "bnUSD", totalSponsorBondbnUSD) + DATA, projectDetails, + PROJECT_COUNT, projectDetails.size(), + TOTAL_AMOUNT, Map.of(consts.bnUSD, totalAmountToBePaidbnUSD), + WITHDRAWN_ICX, installmentRecord.getOrDefault(consts.ICX, BigInteger.ZERO), + WITHDRAWN_BNUSD, installmentRecord.getOrDefault(consts.bnUSD, BigInteger.ZERO), + TOTAL_SPONSOR_BOND, Map.of(consts.bnUSD, totalSponsorBondbnUSD) ); } @@ -271,11 +297,11 @@ private void depositProposalFund(ProposalData.ProposalAttributes _proposals, Big @Override @External @Payable - public void update_proposal_fund(String _ipfs_key, BigInteger _added_budget, BigInteger _added_sponsor_reward, - int _added_installment_count) { + public void updateProposalFund(String ipfsKey, BigInteger addedBudget, BigInteger addedSponsorReward, + int addedInstallmentCount) { ProposalData proposalData = new ProposalData(); - Context.require(proposalExists(_ipfs_key), TAG + ": Invalid IPFS hash."); - String proposalPrefix = proposalPrefix(_ipfs_key); + Context.require(proposalExists(ipfsKey), TAG + ": Invalid IPFS hash."); + String proposalPrefix = proposalPrefix(ipfsKey); Map proposalDetails = proposalData.getDataFromProposalDB(proposalPrefix); BigInteger totalBudget = (BigInteger) proposalDetails.get(consts.TOTAL_BUDGET); BigInteger sponsorReward = (BigInteger) proposalDetails.get(consts.SPONSOR_REWARD); @@ -286,41 +312,47 @@ public void update_proposal_fund(String _ipfs_key, BigInteger _added_budget, Big int sponsorRewardCount = (int) proposalDetails.get(consts.SPONSOR_REWARD_COUNT); String flag = (String) proposalDetails.get(consts.TOKEN); - setTotalBudget(proposalPrefix, totalBudget.add(_added_budget)); - setSponsorReward(proposalPrefix, sponsorReward.add(_added_sponsor_reward)); - setProjectDuration(proposalPrefix, totalDuration + _added_installment_count); - setRemainingAmount(proposalPrefix, remainingAmount.add(_added_budget)); - setSponsorRemainingAmount(proposalPrefix, sponsorRemainingAmount.add(_added_sponsor_reward)); - setInstallmentCount(proposalPrefix, installmentCount + _added_installment_count); - setSponsorRewardCount(proposalPrefix, sponsorRewardCount + _added_installment_count); + setTotalBudget(proposalPrefix, totalBudget.add(addedBudget)); + setSponsorReward(proposalPrefix, sponsorReward.add(addedSponsorReward)); + setProjectDuration(proposalPrefix, totalDuration + addedInstallmentCount); + setRemainingAmount(proposalPrefix, remainingAmount.add(addedBudget)); + setSponsorRemainingAmount(proposalPrefix, sponsorRemainingAmount.add(addedSponsorReward)); + setInstallmentCount(proposalPrefix, installmentCount + addedInstallmentCount); + setSponsorRewardCount(proposalPrefix, sponsorRewardCount + addedInstallmentCount); - ProposalFundDeposited(_ipfs_key, _ipfs_key + ": Added Budget: " + _added_budget + " " + - flag + "and Added time: " + _added_installment_count + " Successfully"); + ProposalFundDeposited(ipfsKey, ipfsKey + ": Added Budget: " + addedBudget + " " + + flag + "and Added time: " + addedInstallmentCount + " Successfully"); } @Override @External - public void send_installment_to_contributor(String _ipfs_key) { + public void sendInstallmentToContributor(String ipfsKey, BigInteger milestoneBudget) { validateCpsScore(); - Context.require(proposalExists(_ipfs_key), TAG + ": Invalid IPFS Hash."); + Context.require(proposalExists(ipfsKey), TAG + ": Invalid IPFS Hash."); BigInteger installmentAmount; - String prefix = proposalPrefix(_ipfs_key); + String prefix = proposalPrefix(ipfsKey); Map proposalData = getDataFromProposalDB(prefix); - int installmentCount = (int) proposalData.get(consts.INSTALLMENT_COUNT); + int _installmentCount = (int) proposalData.get(consts.INSTALLMENT_COUNT); BigInteger withdrawAmount = (BigInteger) proposalData.get(consts.WITHDRAW_AMOUNT); BigInteger remainingAmount = (BigInteger) proposalData.get(consts.REMAINING_AMOUNT); Address contributorAddress = (Address) proposalData.get(consts.CONTRIBUTOR_ADDRESS); String flag = (String) proposalData.get(consts.TOKEN); - if (installmentCount == 1) { - installmentAmount = remainingAmount; - } else { - installmentAmount = remainingAmount.divide(BigInteger.valueOf(installmentCount)); - } - int newInstallmentCount = installmentCount - 1; + Context.require(milestoneBudget.compareTo(remainingAmount)<= 0,TAG+"Requested budget is greater than remaining amount."); +// installmentAmount = remainingAmount.subtract(milestoneBudget); - setInstallmentCount(prefix, newInstallmentCount); + installmentAmount = milestoneBudget; + Context.println("yhe installment is "+ installmentAmount); + +// if (_installmentCount == 1) { +// installmentAmount = remainingAmount; +// } else { +// installmentAmount = remainingAmount.subtract(milestoneBudget); +// } +// int newInstallmentCount = _installmentCount - milestoneApproved; + +// setInstallmentCount(prefix, newInstallmentCount); setRemainingAmount(prefix, remainingAmount.subtract(installmentAmount)); setWithdrawAmount(prefix, withdrawAmount.add(installmentAmount)); DictDB installmentFund = this.installmentFundRecord.at(contributorAddress.toString()); @@ -328,19 +360,43 @@ public void send_installment_to_contributor(String _ipfs_key) { installmentFund.set(flag, installmentFundAmount.add(installmentAmount)); ProposalFundSent(contributorAddress, "new installment " + installmentAmount + " " + flag + " sent to contributors address."); - if (newInstallmentCount == 0) { + if (remainingAmount.subtract(installmentAmount).equals(BigInteger.ZERO)) { setStatus(prefix, COMPLETED); } } + private void onsetPaymentContributor(String _ipfs_key) { + Context.require(proposalExists(_ipfs_key), TAG + ": Invalid IPFS Hash."); + String prefix = proposalPrefix(_ipfs_key); + Map proposalData = getDataFromProposalDB(prefix); + Address contributorAddress = (Address) proposalData.get(consts.CONTRIBUTOR_ADDRESS); + String flag = (String) proposalData.get(consts.TOKEN); + + BigInteger totalBudget = (BigInteger) proposalData.get(consts.TOTAL_BUDGET); + BigInteger withdrawAmount = (BigInteger) proposalData.get(consts.WITHDRAW_AMOUNT); + + BigInteger onSetPaymentPercentage = getOnsetPayment(); + BigInteger onsetAmount = (totalBudget.multiply(onSetPaymentPercentage).divide(HUNDRED)); + + setRemainingAmount(prefix, totalBudget.subtract(onsetAmount)); + + setWithdrawAmount(prefix, withdrawAmount.add(onsetAmount)); + DictDB installmentFund = this.installmentFundRecord.at(contributorAddress.toString()); + + BigInteger installmentFundAmount = installmentFund.getOrDefault(flag, BigInteger.ZERO); + installmentFund.set(flag, installmentFundAmount.add(onsetAmount)); + + InitialPaymentSent(contributorAddress, "initial payment of " + onsetAmount + " " + flag + " is send to contributor address"); + } + @Override @External - public void send_reward_to_sponsor(String _ipfs_key) { + public void sendRewardToSponsor(String ipfsKey, int installmentCount) { validateCpsScore(); - Context.require(proposalExists(_ipfs_key), TAG + ": Invalid IPFS Hash."); + Context.require(proposalExists(ipfsKey), TAG + ": Invalid IPFS Hash."); BigInteger installmentAmount; - String prefix = proposalPrefix(_ipfs_key); + String prefix = proposalPrefix(ipfsKey); int sponsorRewardCount = getSponsorRewardCount(prefix); BigInteger sponsorWithdrawAmount = getSponsorWithdrawAmount(prefix); @@ -351,9 +407,9 @@ public void send_reward_to_sponsor(String _ipfs_key) { if (sponsorRewardCount == 1) { installmentAmount = sponsorRemainingAmount; } else { - installmentAmount = sponsorRemainingAmount.divide(BigInteger.valueOf(sponsorRewardCount)); + installmentAmount = sponsorRemainingAmount.divide(BigInteger.valueOf(sponsorRewardCount)).multiply(BigInteger.valueOf(installmentCount)); } - int newSponsorRewardCount = sponsorRewardCount - 1; + int newSponsorRewardCount = sponsorRewardCount - installmentCount; setSponsorRewardCount(prefix, newSponsorRewardCount); setSponsorWithdrawAmount(prefix, sponsorWithdrawAmount.add(installmentAmount)); @@ -364,12 +420,37 @@ public void send_reward_to_sponsor(String _ipfs_key) { flag + " sent to sponsor address."); } + private void onsetPaymentSponsor(String ipfsKey) { + Context.require(proposalExists(ipfsKey), TAG + ": Invalid IPFS Hash."); + String prefix = proposalPrefix(ipfsKey); + + BigInteger sponsorWithdrawAmount = getSponsorWithdrawAmount(prefix); + BigInteger sponsorRemainingAmount = getSponsorRemainingAmount(prefix); + Address sponsorAddress = getSponsorAddress(prefix); + String flag = getToken(prefix); + + BigInteger onSetPaymentPercentage = getOnsetPayment(); + BigInteger onsetAmount = (sponsorRemainingAmount.multiply(onSetPaymentPercentage).divide(HUNDRED)); + + setSponsorRemainingAmount(prefix, sponsorRemainingAmount.subtract(onsetAmount)); + setSponsorWithdrawAmount(prefix, sponsorWithdrawAmount.add(onsetAmount)); + + DictDB installmentFunds = installmentFundRecord.at(sponsorAddress.toString()); + BigInteger installmentFundAmount = installmentFunds.getOrDefault(flag, BigInteger.ZERO); + installmentFunds.set(flag, installmentFundAmount.add(onsetAmount)); + + + InitialPaymentSent(sponsorAddress, " initial amount of " + onsetAmount + " " + flag + + " sent to sponsor address."); + + } + @Override @External - public void disqualify_project(String _ipfs_key) { + public void disqualifyProject(String ipfsKey) { validateCpsScore(); - Context.require(proposalExists(_ipfs_key), TAG + ": Project not found. Invalid IPFS hash."); - String prefix = proposalPrefix(_ipfs_key); + Context.require(proposalExists(ipfsKey), TAG + ": Project not found. Invalid IPFS hash."); + String prefix = proposalPrefix(ipfsKey); setStatus(prefix, DISQUALIFIED); BigInteger totalBudget = getTotalBudget(prefix); @@ -382,27 +463,27 @@ public void disqualify_project(String _ipfs_key) { BigInteger remainingReward = sponsorReward.subtract(sponsorWithdrawAmount); BigInteger totalReturnAmount = remainingBudget.add(remainingReward); - Address cpfTreasuryAddres = cpfTreasuryScore.get(); + Address cpfTreasuryAddress = cpfTreasuryScore.get(); if (flag.equals(consts.ICX)) { - callScore(totalReturnAmount, cpfTreasuryAddres, "disqualify_proposal_fund", _ipfs_key); + callScore(totalReturnAmount, cpfTreasuryAddress, "disqualifyProposalFund", ipfsKey); } else if (flag.equals(consts.bnUSD)) { JsonObject disqualifyProjectParams = new JsonObject(); - disqualifyProjectParams.add("method", "disqualify_project"); + disqualifyProjectParams.add("method", "disqualifyProject"); JsonObject params = new JsonObject(); - params.add("ipfs_key", _ipfs_key); + params.add("ipfs_key", ipfsKey); disqualifyProjectParams.add("params", params); - callScore(balancedDollar.get(), "transfer", cpfTreasuryAddres, totalReturnAmount, disqualifyProjectParams.toString().getBytes()); + callScore(balancedDollar.get(), "transfer", cpfTreasuryAddress, totalReturnAmount, disqualifyProjectParams.toString().getBytes()); } else { Context.revert(TAG + ": Not supported token."); } - ProposalDisqualified(_ipfs_key, _ipfs_key + ", Proposal disqualified"); + ProposalDisqualified(ipfsKey, ipfsKey + ", Proposal disqualified"); } @Override @External - public void claim_reward() { + public void claimReward() { Address caller = Context.getCaller(); DictDB installmentFundRecord = this.installmentFundRecord.at(caller.toString()); BigInteger availableAmountICX = installmentFundRecord.getOrDefault(consts.ICX, BigInteger.ZERO); @@ -429,7 +510,7 @@ public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { JsonObject jsonObject = Json.parse(unpacked_data).asObject(); JsonObject params = jsonObject.get("params").asObject(); String methodName = jsonObject.get("method").asString(); - if (methodName.equals("deposit_proposal_fund")) { + if (methodName.equals("depositProposalFund")) { String ipfs_hash = params.get("ipfs_hash").asString(); int project_duration = params.get("project_duration").asInt(); BigInteger total_budget = new BigInteger(params.get("total_budget").asString(), 16); @@ -440,6 +521,7 @@ public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { ProposalAttributes proposalAttributes = new ProposalAttributes(); proposalAttributes.ipfs_hash = ipfs_hash; proposalAttributes.project_duration = project_duration; + proposalAttributes.milestoneCount = project_duration; proposalAttributes.total_budget = total_budget; proposalAttributes.sponsor_reward = sponsor_reward; proposalAttributes.token = token; @@ -447,38 +529,75 @@ public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { proposalAttributes.sponsor_address = sponsor_address; proposalAttributes.status = ACTIVE; depositProposalFund(proposalAttributes, _value); - } else if (methodName.equals("budget_adjustment")) { + onsetPaymentContributor(proposalAttributes.ipfs_hash); + onsetPaymentSponsor(proposalAttributes.ipfs_hash); + + } else if (methodName.equals("budgetAdjustment")) { String ipfs_key = params.get("_ipfs_key").asString(); BigInteger added_budget = new BigInteger(params.get("_added_budget").asString(), 16); BigInteger added_sponsor_reward = new BigInteger(params.get("_added_sponsor_reward").asString(), 16); int added_installment_count = params.get("_added_installment_count").asInt(); - update_proposal_fund(ipfs_key, added_budget, added_sponsor_reward, added_installment_count); + updateProposalFund(ipfs_key, added_budget, added_sponsor_reward, added_installment_count); } else { Context.revert(TAG + methodName + " Not a valid method."); } } - // for migration into java contract - @Override @External - public void updateSponsorAndContributorProjects() { - validateAdmins(); - int startIndex = batchSize.getOrDefault(0); - int size = proposalsKeys.size(); - int endIndex = startIndex + 10; - if (endIndex > size) { - endIndex = size; - } - for (int i = startIndex; i < endIndex; i++) { - String proposalKey = proposalsKeys.get(i); - String proposalPrefix = proposalPrefix(proposalKey); - Address contributorAddress = getContributorAddress(proposalPrefix); - Address sponsorAddress = getSponsorAddress(proposalPrefix); - contributorProjects.at(contributorAddress.toString()).add(proposalKey); - sponsorProjects.at(sponsorAddress.toString()).add(proposalKey); - batchSize.set(endIndex); - } + public void updateNewProjects(String oldHash, String newHash, int milestoneCount) { + validateCpsScore(); + + String newIpfsHashPrefix = proposalPrefix(newHash); + String oldProposalPrefix = proposalPrefix(oldHash); + + Address _contributorAddress = getContributorAddress(oldProposalPrefix); + Address _sponsorAddress = getSponsorAddress(oldProposalPrefix); + + ArrayDB contributedProjects = contributorProjects.at(_contributorAddress.toString()); + replaceArrayItem(contributedProjects, oldHash, newHash); + + ArrayDB sponsoredProjects = sponsorProjects.at(_sponsorAddress.toString()); + replaceArrayItem(sponsoredProjects, oldHash, newHash); + + replaceArrayItem(proposalsKeys, oldHash, newHash); + int getIndex = proposalsKeyListIndex.get(oldHash); + proposalsKeyListIndex.set(oldHash, null); + proposalsKeyListIndex.set(newHash, getIndex); + + ipfsHash.at(newIpfsHashPrefix).set(newHash); + projectDuration.at(newIpfsHashPrefix).set(milestoneCount); + sponsorAddress.at(newIpfsHashPrefix).set(_sponsorAddress); + contributorAddress.at(newIpfsHashPrefix).set(_contributorAddress); + installmentCount.at(newIpfsHashPrefix).set(milestoneCount); + + BigInteger _totalBudget = totalBudget.at(oldProposalPrefix).get(); + totalBudget.at(newIpfsHashPrefix).set(_totalBudget); + + BigInteger _sponsorReward = sponsorReward.at(oldProposalPrefix).get(); + sponsorReward.at(newIpfsHashPrefix).set(_sponsorReward); + + String _token = token.at(oldProposalPrefix).get(); + token.at(newIpfsHashPrefix).set(_token); + + BigInteger _withdrawAmount = withdrawAmount.at(oldProposalPrefix).get(); + withdrawAmount.at(newIpfsHashPrefix).set(_withdrawAmount); + + BigInteger _sponsorWithdrawAmount = sponsorWithdrawAmount.at(oldProposalPrefix).get(); + sponsorWithdrawAmount.at(newIpfsHashPrefix).set(_sponsorWithdrawAmount); + + String _status = status.at(oldProposalPrefix).get(); + status.at(newIpfsHashPrefix).set(_status); + + BigInteger _remainingAmount = remainingAmount.at(oldProposalPrefix).get(); + remainingAmount.at(newIpfsHashPrefix).set(_remainingAmount); + + BigInteger _sponsorRemainingAmount = sponsorRemainingAmount.at(oldProposalPrefix).get(); + sponsorRemainingAmount.at(newIpfsHashPrefix).set(_sponsorRemainingAmount); + + int _sponsorRewardCount = sponsorRewardCount.at(oldProposalPrefix).get(); + sponsorRewardCount.at(newIpfsHashPrefix).set(_sponsorRewardCount); + } @Override @@ -499,7 +618,7 @@ public void update_contributor_address(String _ipfs_key, Address _new_contributo setContributorAddress(prefix, _new_contributor_address); } - public T callScore(Class t, Address address, String method, Object... params) { + public T callScore(Class t, Address address, String method, Object... params) { return Context.call(t, address, method, params); } @@ -526,27 +645,15 @@ public void ProposalFundDeposited(String _ipfs_key, String note) { public void ProposalFundSent(Address _receiver_address, String note) { } - @Override @EventLog(indexed = 1) - public void ProposalFundWithdrawn(Address _receiver_address, String note) { + public void InitialPaymentSent(Address _receiver_address, String note) { } - /*----------------------------------------------------------------------------------------------------------------- - ***************************************************** to be removed in production********************************** - -----------------------------------------------------------------------------------------------------------------*/ - @External - public void depositProposalFunds(ProposalData.ProposalAttributes proposals){ - addRecord(proposals); + @Override + @EventLog(indexed = 1) + public void ProposalFundWithdrawn(Address _receiver_address, String note) { } - @External(readonly = true) - public String returnString(){ - return ""; - } -// @External -// public void removeArrayItems(){ -// ArrayDBUtils.remove_array_item_address(contributorProjects); -// } } diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/db/ProposalData.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/db/ProposalData.java index e13c4253..33bbf0c6 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/db/ProposalData.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/db/ProposalData.java @@ -16,21 +16,22 @@ public static class ProposalAttributes{ public String contributor_address; public String sponsor_address; public String status; + public int milestoneCount; } - private final BranchDB> ipfsHash = Context.newBranchDB(consts.IPFS_HASH, String.class); - private final BranchDB> totalBudget = Context.newBranchDB(consts.TOTAL_BUDGET, BigInteger.class); - private final BranchDB> sponsorReward = Context.newBranchDB(consts.SPONSOR_REWARD, BigInteger.class); - private final BranchDB> projectDuration = Context.newBranchDB(consts.PROJECT_DURATION, Integer.class); - private final BranchDB> sponsorAddress = Context.newBranchDB(consts.SPONSOR_ADDRESS, Address.class); - private final BranchDB> contributorAddress = Context.newBranchDB(consts.CONTRIBUTOR_ADDRESS, Address.class); - private final BranchDB> token = Context.newBranchDB(consts.TOKEN, String.class); - private final BranchDB> withdrawAmount = Context.newBranchDB(consts.WITHDRAW_AMOUNT, BigInteger.class); - private final BranchDB> sponsorWithdrawAmount = Context.newBranchDB(consts.SPONSOR_WITHDRAW_AMOUNT, BigInteger.class); - private final BranchDB> remainingAmount = Context.newBranchDB(consts.REMAINING_AMOUNT, BigInteger.class); - private final BranchDB> sponsorRemainingAmount = Context.newBranchDB(consts.SPONSOR_REMAINING_AMOUNT, BigInteger.class); - private final BranchDB> installmentCount = Context.newBranchDB(consts.INSTALLMENT_COUNT, Integer.class); - private final BranchDB> sponsorRewardCount = Context.newBranchDB(consts.SPONSOR_REWARD_COUNT, Integer.class); - private final BranchDB> status = Context.newBranchDB(consts.STATUS, String.class); + public final BranchDB> ipfsHash = Context.newBranchDB(consts.IPFS_HASH, String.class); + public final BranchDB> totalBudget = Context.newBranchDB(consts.TOTAL_BUDGET, BigInteger.class); + public final BranchDB> sponsorReward = Context.newBranchDB(consts.SPONSOR_REWARD, BigInteger.class); + public final BranchDB> projectDuration = Context.newBranchDB(consts.PROJECT_DURATION, Integer.class); + public final BranchDB> sponsorAddress = Context.newBranchDB(consts.SPONSOR_ADDRESS, Address.class); + public final BranchDB> contributorAddress = Context.newBranchDB(consts.CONTRIBUTOR_ADDRESS, Address.class); + public final BranchDB> token = Context.newBranchDB(consts.TOKEN, String.class); + public final BranchDB> withdrawAmount = Context.newBranchDB(consts.WITHDRAW_AMOUNT, BigInteger.class); + public final BranchDB> sponsorWithdrawAmount = Context.newBranchDB(consts.SPONSOR_WITHDRAW_AMOUNT, BigInteger.class); + public final BranchDB> remainingAmount = Context.newBranchDB(consts.REMAINING_AMOUNT, BigInteger.class); + public final BranchDB> sponsorRemainingAmount = Context.newBranchDB(consts.SPONSOR_REMAINING_AMOUNT, BigInteger.class); + public final BranchDB> installmentCount = Context.newBranchDB(consts.INSTALLMENT_COUNT, Integer.class); + public final BranchDB> sponsorRewardCount = Context.newBranchDB(consts.SPONSOR_REWARD_COUNT, Integer.class); + public final BranchDB> status = Context.newBranchDB(consts.STATUS, String.class); @@ -39,15 +40,15 @@ public void addDataToProposalDB(ProposalAttributes _proposals, String prefix){ ipfsHash.at(prefix).set(_proposals.ipfs_hash); totalBudget.at(prefix).set(_proposals.total_budget); sponsorReward.at(prefix).set(_proposals.sponsor_reward); - projectDuration.at(prefix).set(_proposals.project_duration); + projectDuration.at(prefix).set(_proposals.milestoneCount); sponsorAddress.at(prefix).set(Address.fromString(_proposals.sponsor_address)); contributorAddress.at(prefix).set(Address.fromString(_proposals.contributor_address)); withdrawAmount.at(prefix).set(BigInteger.ZERO); sponsorWithdrawAmount.at(prefix).set(BigInteger.ZERO); remainingAmount.at(prefix).set(_proposals.total_budget); sponsorRemainingAmount.at(prefix).set(_proposals.sponsor_reward); - installmentCount.at(prefix).set(_proposals.project_duration); - sponsorRewardCount.at(prefix).set(_proposals.project_duration); + installmentCount.at(prefix).set(_proposals.milestoneCount); + sponsorRewardCount.at(prefix).set(_proposals.milestoneCount); token.at(prefix).set(_proposals.token); status.at(prefix).set(_proposals.status); } diff --git a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/utils/ArrayDBUtils.java b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/utils/ArrayDBUtils.java index 8f09e223..c3bc7213 100644 --- a/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/utils/ArrayDBUtils.java +++ b/CPSTreasury/src/main/java/community/icon/cps/score/cpstreasury/utils/ArrayDBUtils.java @@ -107,6 +107,17 @@ public static boolean remove_array_item_string(ArrayDB array_db, Object return false; } + public static void replaceArrayItem(ArrayDB array_db, Object target, Object newTarget) { + int size = array_db.size(); + + for (int i = 0; i < size; i++) { + if (array_db.get(i).equals(target)) { + array_db.set(i, (T) newTarget); + return; + } + } + } + } diff --git a/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java b/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java index dc4b17e3..49523c1c 100644 --- a/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java +++ b/CPSTreasury/src/test/java/community/icon/cps/score/cpstreasury/CPSTreasuryTest.java @@ -7,6 +7,7 @@ import com.iconloop.score.test.TestBase; import community.icon.cps.score.cpstreasury.utils.consts; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.function.Executable; @@ -14,11 +15,8 @@ import org.mockito.Mockito; import score.Address; import score.Context; -import score.DictDB; -import score.VarDB; import java.math.BigInteger; -import java.security.SecureRandom; import java.util.List; import java.util.Map; @@ -28,17 +26,12 @@ import static org.mockito.Mockito.*; public class CPSTreasuryTest extends TestBase { - private static final Address ZERO_ADDRESS = new Address(new byte[Address.LENGTH]); - private static final Address treasury_score = new Address(new byte[Address.LENGTH]); private static final Address score_address = Address.fromString("cx0000000000000000000000000000000000000000"); private static final Address cpfTreasury = Address.fromString("cx0000000000000000000000000000000000000001"); private static final Address bnUSDScore = Address.fromString("cx0000000000000000000000000000000000000002"); - private static final Address dexScore = Address.fromString("cx0000000000000000000000000000000000000003"); - private static final Address cpsTreasuryScore = Address.fromString("cx0000000000000000000000000000000000000004"); private static final String name = "CPS_TREASURY"; public static final String TAG = "CPS_TREASURY"; - CPSTreasury cpsTreasury; private static final BigInteger MULTIPLIER = new BigInteger("1000000000000000000"); @@ -48,11 +41,8 @@ public class CPSTreasuryTest extends TestBase { private static final Account testing_account2 = sm.createAccount(); private Score tokenScore; - private final SecureRandom secureRandom = new SecureRandom(); - DictDB proposalBudgets = Mockito.mock(DictDB.class); - VarDB swapState = Mockito.mock(VarDB.class); - VarDB swapCount = Mockito.mock(VarDB.class); + public static MockedStatic contextMock; CPSTreasury scoreSpy; @@ -62,6 +52,13 @@ public void setup() throws Exception { CPSTreasury instance = (CPSTreasury) tokenScore.getInstance(); scoreSpy = spy(instance); tokenScore.setInstance(scoreSpy); + contextMock.reset(); +// setScoresMethod(); + } + + @BeforeAll + public static void init(){ + contextMock = Mockito.mockStatic(Context.class, CALLS_REAL_METHODS); } @Test @@ -89,13 +86,22 @@ void fallback() { expectErrorMessage(fallback, "Reverted(0):" + " " + TAG + ": ICX can only be send by CPF Treasury Score"); } + @Test + public void setScoresMethod(){ + setCpsScore(); + setCPFTreasuryScoreMethod(); + setBnUSDScoreMethod(); + setOnsetPayment(); + } + @Test void setCpsScore() { setCpsScoreMethod(); } private void setCpsScoreMethod() { - doReturn(Boolean.TRUE).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("is_admin"), eq(owner.getAddress())); + contextMock.when(caller()).thenReturn(owner.getAddress()); + doReturn(Boolean.TRUE).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("isAdmin"),eq(owner.getAddress())); tokenScore.invoke(owner, "setCpsScore", score_address); assertEquals(score_address, tokenScore.call("getCpsScore")); } @@ -106,7 +112,8 @@ void setCPFTreasuryScore() { } private void setCPFTreasuryScoreMethod() { - doReturn(Boolean.TRUE).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("is_admin"), eq(owner.getAddress())); + contextMock.when(caller()).thenReturn(owner.getAddress()); + doReturn(Boolean.TRUE).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("isAdmin"), eq(owner.getAddress())); tokenScore.invoke(owner, "setCpfTreasuryScore", cpfTreasury); assertEquals(cpfTreasury, tokenScore.call("getCpfTreasuryScore")); } @@ -115,42 +122,61 @@ private void setCPFTreasuryScoreMethod() { void setBnUSDScore() { setBnUSDScoreMethod(); } + @Test + void setOnsetPayment(){ + setCPFTreasuryScoreMethod(); + doReturn(BigInteger.valueOf(10)).when(scoreSpy).callScore(eq(BigInteger.class),any(),eq("getSponsorBondPercentage")); + BigInteger per = BigInteger.ONE; + contextMock.when(caller()).thenReturn(cpfTreasury); + tokenScore.invoke(owner,"setOnsetPayment",per); + } + + public MockedStatic.Verification caller(){ + return () -> score.Context.getCaller(); + } private void setBnUSDScoreMethod() { - doReturn(Boolean.TRUE).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("is_admin"), eq(owner.getAddress())); + contextMock.when(caller()).thenReturn(owner.getAddress()); + doReturn(Boolean.TRUE).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("isAdmin"), eq(owner.getAddress())); tokenScore.invoke(owner, "setBnUSDScore", bnUSDScore); assertEquals(bnUSDScore, tokenScore.call("getBnUSDScore")); } - void setCpsScoreExceptions(Boolean is_admin, Address score_address) { - doReturn(is_admin).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("is_admin"), eq(owner.getAddress())); + void setCpsScoreExceptions(Boolean isAdmin, Address score_address) { + contextMock.when(caller()).thenReturn(owner.getAddress()); + doReturn(isAdmin).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("isAdmin"), eq(owner.getAddress())); tokenScore.invoke(owner, "setCpsScore", score_address); } - void setCpfTreasuryScoreExceptions(Boolean is_admin, Address score_address) { - doReturn(is_admin).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("is_admin"), eq(owner.getAddress())); + void setCpfTreasuryScoreExceptions(Boolean isAdmin, Address score_address) { + contextMock.when(caller()).thenReturn(owner.getAddress()); + doReturn(isAdmin).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("isAdmin"), eq(owner.getAddress())); tokenScore.invoke(owner, "setCpfTreasuryScore", score_address); } - void setBnUSDScoreExceptions(Boolean is_admin, Address score_address) { - doReturn(is_admin).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("is_admin"), eq(owner.getAddress())); + void setBnUSDScoreExceptions(Boolean isAdmin, Address score_address) { + contextMock.when(caller()).thenReturn(owner.getAddress()); + doReturn(isAdmin).when(scoreSpy).callScore(eq(Boolean.class), any(), eq("isAdmin"), eq(owner.getAddress())); tokenScore.invoke(owner, "setBnUSDScore", score_address); } @Test void setCpsScoreNotAdmin() { + setScoresMethod(); Executable setCpsScoreNotAdmin = () -> setCpsScoreExceptions(false, score_address); expectErrorMessage(setCpsScoreNotAdmin, "Reverted(0): " + TAG + ": Only admins can call this method"); } @Test void setCpfTreasuryScoreNotAdmin() { + setScoresMethod(); Executable setCpfTreasuryScoreNotAdmin = () -> setCpfTreasuryScoreExceptions(false, score_address); expectErrorMessage(setCpfTreasuryScoreNotAdmin, "Reverted(0): " + TAG + ": Only admins can call this method"); } @Test void setBnUSDScoreNotAdmin() { + setScoresMethod(); Executable setBnUSDScoreNotAdmin = () -> setBnUSDScoreExceptions(false, score_address); expectErrorMessage(setBnUSDScoreNotAdmin, "Reverted(0): " + TAG + ": Only admins can call this method"); } @@ -175,25 +201,30 @@ void setBnUSDScoreNotContract() { @Test void depositProposalFund() { + /* totalBudget = 100, onsetPayment = 1% installmentCount = 2 + * remainingBudgetAfter onsetPayment = 99 + * installMentAmount = 99/2 =49.5 + */ + setOnsetPayment(); depositProposalFundMethod(); @SuppressWarnings("unchecked") - Map proposalDataDetails = (Map) tokenScore.call("get_contributor_projected_fund", testing_account2.getAddress()); + Map proposalDataDetails = (Map) tokenScore.call("getContributorProjectedFund", testing_account2.getAddress()); @SuppressWarnings("unchecked") List> proposalDetails = (List>) proposalDataDetails.get("data"); Map expectedData = Map.of( consts.IPFS_HASH, "Proposal 1", consts.TOKEN, "bnUSD", consts.TOTAL_BUDGET, BigInteger.valueOf(100).multiply(MULTIPLIER), - consts.TOTAL_INSTALLMENT_PAID, BigInteger.ZERO, + consts.TOTAL_INSTALLMENT_PAID, BigInteger.ONE.multiply(MULTIPLIER), consts.TOTAL_INSTALLMENT_COUNT, 2, consts.TOTAL_TIMES_INSTALLMENT_PAID, 0, - consts.INSTALLMENT_AMOUNT, BigInteger.valueOf(50).multiply(MULTIPLIER)); + consts.INSTALLMENT_AMOUNT, BigInteger.valueOf(495).multiply(MULTIPLIER).divide(BigInteger.TEN)); assertEquals(proposalDetails.get(0), expectedData); } private void depositProposalFundMethod() { JsonObject depositProposal = new JsonObject(); - depositProposal.add("method", "deposit_proposal_fund"); + depositProposal.add("method", "depositProposalFund"); JsonObject params = new JsonObject(); params.add("ipfs_hash", "Proposal 1"); params.add("project_duration", 2); @@ -217,6 +248,7 @@ void depositProposalFundExceptions(){ } @Test void depositProposalFundProposalAlreadyExists(){ + setOnsetPayment(); depositProposalFundMethod(); Executable depositProposalFundProposalAlreadyExists = () -> depositProposalFundExceptions(); expectErrorMessage(depositProposalFundProposalAlreadyExists, "Reverted(0): " + "CPS_TREASURY: Already have this project"); @@ -224,9 +256,17 @@ void depositProposalFundProposalAlreadyExists(){ @Test void updateProposalFund() { + /* before budget adjustment: + totalBudget = 100 installmentCount = 2 onsetPayment = 1 + installmentAmount = (100-1)/2 = 49.5 + after budget adjustment : + totalBudget = 200 installCount = 3 onsetPayment = 1 + installmentAmount = (200-1)/3 = 66.33 + * */ + setOnsetPayment(); depositProposalFundMethod(); JsonObject budgetAdjustmentData = new JsonObject(); - budgetAdjustmentData.add("method", "budget_adjustment"); + budgetAdjustmentData.add("method", "budgetAdjustment"); JsonObject params = new JsonObject(); params.add("_ipfs_key", "Proposal 1"); params.add("_added_budget", BigInteger.valueOf(100).multiply(MULTIPLIER).toString(16)); @@ -237,17 +277,17 @@ void updateProposalFund() { tokenScore.invoke(owner, "tokenFallback", cpfTreasury, BigInteger.valueOf(102).multiply(MULTIPLIER), budgetAdjustmentData.toString().getBytes()); @SuppressWarnings("unchecked") - Map proposalDataDetails = (Map) tokenScore.call("get_contributor_projected_fund", testing_account2.getAddress()); + Map proposalDataDetails = (Map) tokenScore.call("getContributorProjectedFund", testing_account2.getAddress()); @SuppressWarnings("unchecked") List> proposalDetails = (List>) proposalDataDetails.get("data"); Map expectedData = Map.of( consts.IPFS_HASH, "Proposal 1", consts.TOKEN, "bnUSD", consts.TOTAL_BUDGET, BigInteger.valueOf(200).multiply(MULTIPLIER), - consts.TOTAL_INSTALLMENT_PAID, BigInteger.ZERO, + consts.TOTAL_INSTALLMENT_PAID, BigInteger.ONE.multiply(ICX), consts.TOTAL_INSTALLMENT_COUNT, 3, consts.TOTAL_TIMES_INSTALLMENT_PAID, 0, - consts.INSTALLMENT_AMOUNT, new BigInteger("66666666666666666666")); + consts.INSTALLMENT_AMOUNT, new BigInteger("66333333333333333333")); assertEquals(proposalDetails.get(0), expectedData); } @@ -255,7 +295,7 @@ void updateProposalFundProposalException(){ try { setCPFTreasuryScoreMethod(); JsonObject budgetAdjustmentData = new JsonObject(); - budgetAdjustmentData.add("method", "budget_adjustment"); + budgetAdjustmentData.add("method", "budgetAdjustment"); JsonObject params = new JsonObject(); params.add("_ipfs_key", "Proposal 1"); params.add("_added_budget", BigInteger.valueOf(100).multiply(MULTIPLIER).toString(16)); @@ -276,79 +316,143 @@ void updateProposalFundProposalDoesnotExist(){ expectErrorMessage(updateProposalFundProposalDoesnotExist, "Reverted(0): " + "CPS_TREASURY: Invalid IPFS hash."); } + private void depositProposalFund_MilestoneCheck() { + /* Sponsor bond = 10 % intital payement = 1% + * duration = 2 months milestone = 3 */ + JsonObject depositProposal = new JsonObject(); + depositProposal.add("method", "depositProposalFund"); + JsonObject params = new JsonObject(); + params.add("ipfs_hash", "Proposal 1"); + params.add("project_duration", 4); + params.add("sponsor_address", testing_account.getAddress().toString()); + params.add("contributor_address", testing_account2.getAddress().toString()); + params.add("total_budget", BigInteger.valueOf(100).multiply(MULTIPLIER).toString(16)); + params.add("sponsor_reward", BigInteger.valueOf(10).multiply(MULTIPLIER).toString(16)); + params.add("token", "bnUSD"); + depositProposal.add("params", params); + setCPFTreasuryScoreMethod(); + tokenScore.invoke(owner, "tokenFallback", cpfTreasury, BigInteger.valueOf(102).multiply(MULTIPLIER), depositProposal.toString().getBytes()); + } + @Test - void sendInstallmentToContributor() { - depositProposalFundMethod(); + void sendInstallmentToContributor() { // send first installment + setOnsetPayment(); + depositProposalFund_MilestoneCheck(); setCpsScoreMethod(); - try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { - theMock.when(() -> Context.getCaller()).thenReturn(score_address); - tokenScore.invoke(owner, "send_installment_to_contributor", "Proposal 1"); - } + + // proposal details after submission + Map proposalDataDetails_before = (Map) tokenScore.call("getContributorProjectedFund", testing_account2.getAddress()); + assertEquals(proposalDataDetails_before.get("withdraw_amount_bnUSD"), BigInteger.valueOf(1).multiply(MULTIPLIER)); + + List> proposalDetailsData = (List>) proposalDataDetails_before.get("data"); + assertEquals(proposalDetailsData.get(0).get("total_installment_paid"), BigInteger.valueOf(1).multiply(MULTIPLIER)); + assertEquals(proposalDetailsData.get(0).get("total_installment_count"), 4); + assertEquals(proposalDetailsData.get(0).get("installment_amount"), BigInteger.valueOf(2475).multiply(MULTIPLIER).divide(BigInteger.valueOf(100))); + + contextMock.when(caller()).thenReturn(score_address); + tokenScore.invoke(owner, "sendInstallmentToContributor", "Proposal 1", 1); @SuppressWarnings("unchecked") - Map proposalDataDetails = (Map) tokenScore.call("get_contributor_projected_fund", testing_account2.getAddress()); - assertEquals(proposalDataDetails.get("withdraw_amount_bnUSD"), BigInteger.valueOf(50).multiply(MULTIPLIER)); + Map proposalDataDetails_after = (Map) tokenScore.call("getContributorProjectedFund", testing_account2.getAddress()); + assertEquals(proposalDataDetails_after.get("withdraw_amount_bnUSD"), BigInteger.valueOf(2575).multiply(MULTIPLIER).divide(BigInteger.valueOf(100))); - try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { - theMock.when(() -> Context.getCaller()).thenReturn(score_address); - tokenScore.invoke(owner, "send_installment_to_contributor", "Proposal 1"); - } + proposalDetailsData = (List>) proposalDataDetails_after.get("data"); + assertEquals(proposalDetailsData.get(0).get("total_installment_paid"), BigInteger.valueOf(2575).multiply(MULTIPLIER).divide(BigInteger.valueOf(100))); + assertEquals(proposalDetailsData.get(0).get("total_installment_count"), 4); + assertEquals(proposalDetailsData.get(0).get("installment_amount"), BigInteger.valueOf(2475).multiply(MULTIPLIER).divide(BigInteger.valueOf(100))); + + } + + + @Test + void sendInstallmentToContributor_SecondInstallment() { // send first installment + sendInstallmentToContributor(); + + tokenScore.invoke(owner, "sendInstallmentToContributor", "Proposal 1", 1); + @SuppressWarnings("unchecked") + Map proposalDataDetails_after = (Map) tokenScore.call("getContributorProjectedFund", testing_account2.getAddress()); + assertEquals(proposalDataDetails_after.get("withdraw_amount_bnUSD"), BigInteger.valueOf(505).multiply(MULTIPLIER).divide(BigInteger.valueOf(10))); + + List> proposalDetailsData = (List>) proposalDataDetails_after.get("data"); + assertEquals(proposalDetailsData.get(0).get("total_installment_paid"), BigInteger.valueOf(505).multiply(MULTIPLIER).divide(BigInteger.valueOf(10))); + assertEquals(proposalDetailsData.get(0).get("total_installment_count"), 4); + assertEquals(proposalDetailsData.get(0).get("installment_amount"), BigInteger.valueOf(2475).multiply(MULTIPLIER).divide(BigInteger.valueOf(100))); + + } + + @Test + void sendInstallmentToContributor_Completed(){ + // total Milestone = 4, remaining milestone = 2 + sendInstallmentToContributor_SecondInstallment(); + + tokenScore.invoke(owner, "sendInstallmentToContributor", "Proposal 1", 2); @SuppressWarnings("unchecked") - Map proposalDataDetails2 = (Map) tokenScore.call("get_contributor_projected_fund", testing_account2.getAddress()); - assertEquals(proposalDataDetails2.get("withdraw_amount_bnUSD"), BigInteger.valueOf(100).multiply(MULTIPLIER)); + Map proposalDataDetails_after = (Map) tokenScore.call("getContributorProjectedFund", testing_account2.getAddress()); + assertEquals(proposalDataDetails_after.get("withdraw_amount_bnUSD"), BigInteger.valueOf(100).multiply(MULTIPLIER)); + } @Test void sendRewardToSponsor() { - depositProposalFundMethod(); + setOnsetPayment(); + depositProposalFund_MilestoneCheck(); setCpsScoreMethod(); - sendRewardToSponsorMethod(); @SuppressWarnings("unchecked") - Map proposalDataDetails = (Map) tokenScore.call("get_sponsor_projected_fund", testing_account.getAddress()); - assertEquals(proposalDataDetails.get("withdraw_amount_bnUSD"), BigInteger.valueOf(1).multiply(MULTIPLIER)); + Map proposalDataDetails = (Map) tokenScore.call("getSponsorProjectedFund", testing_account.getAddress()); + assertEquals(proposalDataDetails.get("withdraw_amount_bnUSD"), BigInteger.valueOf(1).multiply(MULTIPLIER).divide(BigInteger.TEN)); + + sendRewardToSponsorMethod(); + Map proposalDataDetails2 = (Map) tokenScore.call("getSponsorProjectedFund", testing_account.getAddress()); + assertEquals(proposalDataDetails2.get("withdraw_amount_bnUSD"), BigInteger.valueOf(2575).multiply(MULTIPLIER).divide(BigInteger.valueOf(1000))); + + + List> proposalDetailsData = (List>) proposalDataDetails2.get("data"); + assertEquals(proposalDetailsData.get(0).get("total_installment_paid"), BigInteger.valueOf(2575).multiply(MULTIPLIER).divide(BigInteger.valueOf(1000))); + assertEquals(proposalDetailsData.get(0).get("total_installment_count"), 4); + assertEquals(proposalDetailsData.get(0).get("installment_amount"), BigInteger.valueOf(2475).multiply(MULTIPLIER).divide(BigInteger.valueOf(1000))); - try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { - theMock.when(() -> Context.getCaller()).thenReturn(score_address); - tokenScore.invoke(owner, "send_reward_to_sponsor", "Proposal 1"); - } - @SuppressWarnings("unchecked") - Map proposalDataDetails2 = (Map) tokenScore.call("get_sponsor_projected_fund", testing_account.getAddress()); - assertEquals(proposalDataDetails2.get("withdraw_amount_bnUSD"), BigInteger.valueOf(2).multiply(MULTIPLIER)); } private void sendRewardToSponsorMethod() { - try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { - theMock.when(() -> Context.getCaller()).thenReturn(score_address); - tokenScore.invoke(owner, "send_reward_to_sponsor", "Proposal 1"); - } + contextMock.when(caller()).thenReturn(score_address); + tokenScore.invoke(owner, "sendRewardToSponsor", "Proposal 1", 1); } @Test void disqualifyProject(){ + setOnsetPayment(); depositProposalFundMethod(); setCPFTreasuryScoreMethod(); setCpsScoreMethod(); setBnUSDScoreMethod(); - try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { - theMock.when(() -> Context.getCaller()).thenReturn(score_address); - tokenScore.invoke(owner, "disqualify_project", "Proposal 1"); - JsonObject disqualifyProjectParams = new JsonObject(); - disqualifyProjectParams.add("method", "disqualify_project"); - JsonObject params = new JsonObject(); - params.add("ipfs_key", "Proposal 1"); - disqualifyProjectParams.add("params", params); - theMock.verify(() -> Context.call(bnUSDScore, "transfer", cpfTreasury, BigInteger.valueOf(102).multiply(MULTIPLIER), disqualifyProjectParams.toString().getBytes()), times(1)); - } + + /* total budget = 100 sponsor reward = 2 + * on proposal submission : contributor_reward = 1 and sponsor_reward = 0.02 + * remainning budget = 102 -1-0.02 = 100.98 + * */ + BigInteger remainingBudget = BigInteger.valueOf(10098).multiply(MULTIPLIER).divide(BigInteger.valueOf(100)); + doNothing().when(scoreSpy).callScore(eq(bnUSDScore), eq("transfer"), eq(cpfTreasury), + eq(remainingBudget),any()); + contextMock.when(caller()).thenReturn(score_address); + tokenScore.invoke(owner, "disqualifyProject", "Proposal 1"); + JsonObject disqualifyProjectParams = new JsonObject(); + disqualifyProjectParams.add("method", "disqualifyProject"); + JsonObject params = new JsonObject(); + params.add("ipfs_key", "Proposal 1"); + disqualifyProjectParams.add("params", params); + } @Test void claimReward(){ + setScoresMethod(); depositProposalFundMethod(); - sendRewardToSponsorMethod(); +// sendRewardToSponsorMethod(); setBnUSDScoreMethod(); - try(MockedStatic theMock = Mockito.mockStatic(Context.class)) { - theMock.when(() -> Context.getCaller()).thenReturn(testing_account.getAddress()); - tokenScore.invoke(testing_account, "claim_reward"); - theMock.verify(() -> Context.call(bnUSDScore, "transfer", testing_account.getAddress(), BigInteger.valueOf(1).multiply(MULTIPLIER)), times(1)); - } + BigInteger reward = BigInteger.valueOf(2).multiply(MULTIPLIER).divide(BigInteger.valueOf(100)); + doNothing().when(scoreSpy).callScore(eq(bnUSDScore),eq("transfer"),eq(testing_account.getAddress()),eq(reward)); + contextMock.when(caller()).thenReturn(testing_account.getAddress()); + tokenScore.invoke(testing_account, "claimReward"); + + } } \ No newline at end of file diff --git a/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPFTreasuryInterface.java b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPFTreasuryInterface.java index 23ec5ecc..d8b03b15 100644 --- a/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPFTreasuryInterface.java +++ b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPFTreasuryInterface.java @@ -18,86 +18,121 @@ public interface CPFTreasuryInterface { String name(); @External - void setCpsScore(Address _score); + void setCpsScore(Address score); @External(readonly = true) Address getCpsScore(); @External - void setCpsTreasuryScore(Address _score); + void setCpsTreasuryScore(Address score); @External(readonly = true) Address getCpsTreasuryScore(); @External - void setBnUSDScore(Address _score); + void setBnUSDScore(Address score); @External(readonly = true) Address getBnUSDScore(); @External - void setSicxScore(Address _score); + void setSicxScore(Address score); @External(readonly = true) Address getSicxScore(); @External - void setDexScore(Address _score); + void setDexScore(Address score); @External(readonly = true) Address getDexScore(); @External - void setRouterScore(Address _score); + void setRouterScore(Address score); @External(readonly = true) Address getRouterScore(); @External - void setMaximumTreasuryFundIcx(BigInteger _value); + void setOracleAddress(Address score); + + @External(readonly = true) + Address getOracleAddress(); + + @External + void setSponsorBondPercentage(BigInteger bondValue); @External - void setMaximumTreasuryFundBnusd(BigInteger _value); + void setPeriod(BigInteger applicationPeriod); + + @External + void setOnsetPayment(BigInteger paymentPercentage); @External(readonly = true) - Map get_total_funds(); + int getSlippagePercentage(); @External(readonly = true) - Map get_remaining_swap_amount(); + BigInteger getEmergencyFund(); @External - void transfer_proposal_fund_to_cps_treasury(String ipfs_key, int total_installment_count, - Address sponsor_address, Address contributor_address, - String token_flag, BigInteger _total_budget); + void setMaximumTreasuryFundIcx(BigInteger value); @External - void update_proposal_fund(String ipfs_key, @Optional String flag, @Optional BigInteger _added_budget, - @Optional int _total_installment_count); + void setMaximumTreasuryFundBnusd(BigInteger value); + + @External + void setSwapLimitAmount(BigInteger value); + + @External(readonly = true) + Map getTotalFunds(); + + @External(readonly = true) + Map getRemainingSwapAmount(); + + @External + void transferProposalFundToCpsTreasury(String ipfsKey, int projectDuration, + Address sponsorAddress, Address contributorAddress, + String tokenFlag, BigInteger totalBudget); + + @External + void updateProposalFund(String ipfsKey, @Optional String flag, @Optional BigInteger addedBudget, + @Optional int totalInstallmentCount); + + @External + void withdrawFromEmergencyFund(BigInteger value, Address address, String purpose); + + @External + void allocateEmergencyFund(BigInteger value); + + @External + void setOraclePercentageDifference(int value); @External @Payable - void add_fund(); + void addFund(); @External void swapICXToBnUSD(BigInteger amount, @Optional BigInteger _minReceive); @External - void swap_tokens(int _count); + void swapTokens(int _count); @External(readonly = true) - Map get_swap_state_status(); + Map getSwapStateStatus(); @External - void reset_swap_state(); + void resetSwapState(); @External(readonly = true) - Map get_proposal_details(@Optional int start_index, @Optional int end_index); + Map getProposalDetails(@Optional int startIndex, @Optional int endIndex); @External void tokenFallback(Address from, BigInteger value, byte[] _data); @Payable void fallback(); + @External + void toggleSwapFlag(); //EventLogs @EventLog(indexed = 1) @@ -111,4 +146,7 @@ void update_proposal_fund(String ipfs_key, @Optional String flag, @Optional BigI @EventLog(indexed = 1) void FundReceived(Address _sponsor_address, String note); + + @EventLog(indexed = 1) + void EmergencyFundTransferred(Address _address, BigInteger _value, String _purpose); } diff --git a/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPSCoreInterface.java b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPSCoreInterface.java index 1e4a3b37..add2f5ce 100644 --- a/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPSCoreInterface.java +++ b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPSCoreInterface.java @@ -24,6 +24,9 @@ public static class ProposalAttributes { public String token; public Address sponsor_address; public String ipfs_link; + public int milestoneCount; + public Boolean isMilestone; + } public static class ProgressReportAttributes { @@ -34,7 +37,23 @@ public static class ProgressReportAttributes { public Boolean budget_adjustment; public BigInteger additional_budget; public int additional_month; - public int percentage_completed; +// public int[] milestoneCompleted; + } + + public static class MilestonesAttributes { + public int id; + public int completionPeriod; + public BigInteger budget; + } + + public static class MilestoneSubmission{ + public int id; + public boolean status; + } + + public static class MilestoneVoteAttributes { + public int id; + public String vote; } @External(readonly = true) @@ -44,37 +63,21 @@ public static class ProgressReportAttributes { String progressReportPrefix(String progressKey); - - @External - void set_cps_treasury_score(Address _score); - @External void setCpsTreasuryScore(Address score); - - @External(readonly = true) - Address get_cps_treasury_score(); - @External(readonly = true) Address getCpsTreasuryScore(); - - @External - void set_cpf_treasury_score(Address _score); - @External void setCpfTreasuryScore(Address score); - - @External(readonly = true) - Address get_cpf_treasury_score(); - @External(readonly = true) Address getCpfTreasuryScore(); @External - void setBnusdScore(Address _score); + void setBnusdScore(Address score); @External(readonly = true) @@ -110,11 +113,11 @@ public static class ProgressReportAttributes { @External - void unregister_prep(); + void unregisterPrep(); @External - void register_prep(); + void registerPrep(); @External(readonly = true) boolean checkPriorityVoting(Address prep); @@ -138,11 +141,11 @@ public static class ProgressReportAttributes { @External(readonly = true) - Map login_prep(Address _address); + Map loginPrep(Address address); @External(readonly = true) - List
get_admins(); + List
getAdmins(); @SuppressWarnings("unchecked") @@ -151,66 +154,66 @@ public static class ProgressReportAttributes { @External(readonly = true) - List> get_PReps(); + List> getPReps(); @External(readonly = true) - List
get_denylist(); + List
getDenylist(); @External(readonly = true) - Map get_period_status(); + Map getPeriodStatus(); @External(readonly = true) - List
get_contributors(); + List
getContributors(); @External(readonly = true) - Map check_claimable_sponsor_bond(Address _address); + Map checkClaimableSponsorBond(Address address); @Payable @External - void submit_proposal(ProposalAttributes _proposals); + void submitProposal(ProposalAttributes proposals, MilestonesAttributes[] milestones); @External - void vote_proposal(String _ipfs_key, String _vote, String _vote_reason, @Optional boolean _vote_change); + void voteProposal(String ipfsKey, String vote, String voteReason, @Optional boolean voteChange); @External - void submit_progress_report(ProgressReportAttributes _progress_report); + void submitProgressReport(ProgressReportAttributes progressReport, MilestoneSubmission[] milestoneSubmissions); @External - void vote_progress_report(String _ipfs_key, String _report_key, String _vote, String _vote_reason, @Optional String _budget_adjustment_vote, @Optional boolean _vote_change); + void voteProgressReport(String reportKey, String voteReason, MilestoneVoteAttributes[] votes, @Optional String budgetAdjustmentVote,@Optional boolean voteChange); @External(readonly = true) - List get_proposals_keys_by_status(String _status); + List getProposalsKeysByStatus(String _status); @External(readonly = true) - int check_change_vote(Address _address, String _ipfs_hash, String _proposal_type); + int checkChangeVote(Address address, String ipfsHash, String proposalType); @External(readonly = true) - Map get_project_amounts(); + Map getProjectAmounts(); @External(readonly = true) - Map get_sponsors_record(); + Map getSponsorsRecord(); @External - void update_period(); + void updatePeriod(); @External(readonly = true) Map getProposalDetails(String status, @Optional Address walletAddress, @Optional int startIndex); @External(readonly = true) - Map get_proposal_details_by_hash(String _ipfs_key); + Map getProposalDetailsByHash(String ipfs_key); @External(readonly = true) @@ -218,36 +221,36 @@ public static class ProgressReportAttributes { @External(readonly = true) - Map get_progress_reports_by_hash(String _report_key); + Map getProgressReportsByHash(String reportKey); @External(readonly = true) - Map get_progress_reports_by_proposal(String _ipfs_key); + Map getProgressReportsByProposal(String ipfsKey); @External(readonly = true) Map getSponsorsRequests(String status, Address sponsorAddress, @Optional int startIndex); @External(readonly = true) - Map get_vote_result(String _ipfs_key); + Map getVoteResult(String ipfsKey); @External(readonly = true) - Map get_progress_report_result(String _report_key); + Map getProgressReportResult(String reportKey); @External(readonly = true) - Map get_budget_adjustment_vote_result(String _report_key); + Map getBudgetAdjustmentVoteResult(String reportKey); @External - void tokenFallback(Address _from, BigInteger _value, byte[] _data); + void tokenFallback(Address from, BigInteger value, byte[] data); @External - void remove_denylist_preps(); + void removeDenylistPreps(); @External - void claim_sponsor_bond(); + void claimSponsorBond(); @External - void set_swap_count(int value); + void setSwapCount(int value); @External void updateNextBlock(int blockCount); diff --git a/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPSTreasuryInterface.java b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPSTreasuryInterface.java index 86e736c8..ba9867b4 100644 --- a/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPSTreasuryInterface.java +++ b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/CPSTreasuryInterface.java @@ -2,11 +2,9 @@ import foundation.icon.score.client.ScoreClient; import foundation.icon.score.client.ScoreInterface; - import score.Address; import score.annotation.EventLog; import score.annotation.External; -import score.annotation.Optional; import score.annotation.Payable; import java.math.BigInteger; @@ -23,26 +21,25 @@ public interface CPSTreasuryInterface { void fallback(); @External - void setCpsScore(Address _score); + void setCpsScore(Address score); @External(readonly = true) - //Todo java convention in get methods?? Address getCpsScore(); @External - void setCpfTreasuryScore(Address _score); + void setCpfTreasuryScore(Address score); @External(readonly = true) Address getCpfTreasuryScore(); @External - void setBnUSDScore(Address _score); + void setBnUSDScore(Address score); @External(readonly = true) Address getBnUSDScore(); @External(readonly = true) - Map get_contributor_projected_fund(Address _wallet_address); + Map getContributorProjectedFund(Address walletAddress); @External(readonly = true) List getContributorProjects(Address address); @@ -51,31 +48,33 @@ public interface CPSTreasuryInterface { List getSponsorProjects(Address address); @External(readonly = true) - Map get_sponsor_projected_fund(Address _wallet_address); + Map getSponsorProjectedFund(Address walletAddress); @External @Payable - void update_proposal_fund(String ipfs_key, BigInteger added_budget, BigInteger _added_sponsor_reward, - int _added_installment_count); + void updateProposalFund(String ipfsKey, BigInteger addedBudget, BigInteger addedSponsorReward, + int addedInstallmentCount); @External - void send_installment_to_contributor(String _ipfs_key); + void sendInstallmentToContributor(String ipfsKey, BigInteger milestoneBudget); @External - void send_reward_to_sponsor(String _ipfs_key); + void sendRewardToSponsor(String ipfsKey, int installmentCount); @External - void disqualify_project(String _ipfs_key); + void disqualifyProject(String ipfsKey); @External - void claim_reward(); + void claimReward(); @External void tokenFallback(Address from, BigInteger value, byte[] _data); - // for migration into java contract @External - void updateSponsorAndContributorProjects(); + void setOnsetPayment(BigInteger paymentPercentage); + + @External(readonly = true) + BigInteger getOnsetPayment(); @External void update_contributor_address(String _ipfs_key, Address _new_contributor_address);