diff --git a/.gitignore b/.gitignore index 6151cd4b..68f9b533 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,6 @@ gradle.properties .classpath .settings **/bin/ + +*.ipynb +*.csv \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..e2636d58 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "cps-gochain-local"] + path = cps-gochain-local + url = git@github.com:naneey/cps-gochain-local.git diff --git a/CPFTreasury/build.gradle b/CPFTreasury/build.gradle index cbfe0f77..fdbdfcef 100644 --- a/CPFTreasury/build.gradle +++ b/CPFTreasury/build.gradle @@ -1,18 +1,21 @@ -version = '1.2.0' +version = '1.5.0' dependencies { - compileOnly 'foundation.icon:javaee-api:0.9.1' - implementation project(':score-lib') - - implementation 'com.github.sink772:javaee-tokens:0.6.1' - implementation 'com.github.sink772:minimal-json:0.9.6' +// compileOnly 'foundation.icon:javaee-api:0.9.1' +// implementation project(':score-lib') +// +// implementation 'com.github.sink772:javaee-tokens:0.6.1' +// implementation 'com.github.sink772:minimal-json:0.9.6' +// +// testImplementation 'foundation.icon:javaee-unittest:0.9.2' +// implementation 'org.mockito:mockito-core:4.3.1' +// testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2' +// testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' + testImplementation('org.mockito:mockito-inline:4.8.0') +// implementation 'foundation.icon:javaee-scorex:0.5.2' - testImplementation 'foundation.icon:javaee-unittest:0.9.2' - implementation 'org.mockito:mockito-core:4.3.1' - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' - testImplementation('org.mockito:mockito-inline:4.3.1') - implementation 'foundation.icon:javaee-scorex:0.5.2' + implementation project(':score-lib') + testImplementation project(':test-lib') } @@ -28,27 +31,29 @@ deployJar { lisbon { uri = 'https://lisbon.net.solidwallet.io/api/v3' nid = 0x2 - to = 'cx3d4182c0e783b7ef97ba63409c4bdf808853bd9f' - } - local { - uri = 'http://localhost:9082/api/v3' - nid = 0x3 - } - berlin { - uri = 'https://berlin.net.solidwallet.io/api/v3' - nid = 0x7 + to = "cxd19ed92de2050a87c709097b6297aadf5f8d7432" } + mainnet { uri = 'https://ctz.solidwallet.io/api/v3' nid = 0x1 to = 'cxdca1178010b5368aea929ad5c06abee64b91acc2' } + devnet{ + uri = "https://tt.net.solidwallet.io/api/v3" + nid = 0x3 + to = "cx0d0638e5764ede3ed2c9eadd179bc67785868842" + } } keystore = rootProject.hasProperty('keystoreName') ? "$keystoreName" : '' password = rootProject.hasProperty('keystorePass') ? "$keystorePass" : '' + parameters { + arg("cpsScore", "cx5100c8b221cc373939d8a720ecfbd90440c75ed3") + } } + test { useJUnitPlatform() } diff --git a/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/CPFTreasury.java b/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/CPFTreasury.java index abbbe140..3e4d6415 100644 --- a/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/CPFTreasury.java +++ b/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/CPFTreasury.java @@ -26,10 +26,14 @@ public class CPFTreasury extends SetterGetter implements CPFTreasuryInterface { public static final VarDB
sICXScore = Context.newVarDB(SICX_SCORE, Address.class); public static final VarDB
routerScore = Context.newVarDB(ROUTER_SCORE, Address.class); public static final VarDB
oracleAddress = Context.newVarDB(ORACLE_ADDRESS, Address.class); + private final ArrayDB proposalsKeys = Context.newArrayDB(PROPOSALS_KEYS, String.class); private final DictDB proposalBudgets = Context.newDictDB(PROPOSAL_BUDGETS, BigInteger.class); + private final VarDB treasuryFund = Context.newVarDB(TREASURY_FUND, BigInteger.class); private final VarDB emergencyFund = Context.newVarDB(EMERGENCY_FUND, BigInteger.class); + public static final DictDB rewardPool = Context.newDictDB(REWARD_POOL, BigInteger.class); + private final VarDB treasuryFundbnUSD = Context.newVarDB(TREASURY_FUND_BNUSD, BigInteger.class); private final VarDB swapState = Context.newVarDB(SWAP_STATE, Integer.class); @@ -39,13 +43,29 @@ public class CPFTreasury extends SetterGetter implements CPFTreasuryInterface { private final VarDB swapFlag = Context.newVarDB(SWAP_FLAG, Boolean.class); private final VarDB swapLimitAmount = Context.newVarDB(SWAP_LIMIT_AMOUNT, BigInteger.class); - public CPFTreasury() { + public static final VarDB councilFlag = Context.newVarDB(COUNCIL_FLAG, Boolean.class); + public static final ArrayDB
councilManagers = Context.newArrayDB(COUNCIL_MANAGERS, Address.class); + + public static final VarDB councilManagerRewardPercentage = Context.newVarDB(COUNCIL_MANAGERS_REWARD_PERCENTAGE, Integer.class); + public static final DictDB councilManagersReward = Context.newDictDB(COUNCIL_MANAGERS_REWARD, BigInteger.class); + + + public CPFTreasury(@Optional Address cpsScore) { if (treasuryFund.get() == null) { - treasuryFund.set(BigInteger.valueOf(1000000).multiply(EXA)); + treasuryFund.set(BigInteger.valueOf(5000000).multiply(EXA)); swapCount.set(SwapReset); swapState.set(SwapReset); swapFlag.set(false); + treasuryFundbnUSD.set(BigInteger.valueOf(5000000).multiply(EXA)); + CPFTreasury.cpsScore.set(cpsScore); } + + councilFlag.set(true); + councilManagers.add(Address.fromString("hxd4eb0a6c591b5e7a76e9a6677da055ebfdd897da")); + councilManagers.add(Address.fromString("hx9fa9d224306b0722099d30471b3c2306421aead7")); + councilManagers.add(Address.fromString("hx03907c67a68e8d6948cff58f49d39b3d7c8d95ad")); + councilManagerRewardPercentage.set(0); + } private boolean proposalExists(String ipfsKey) { @@ -102,8 +122,7 @@ private void burn(BigInteger amount) { @Override @External(readonly = true) public Map getTotalFunds() { - return Map.of(ICX, Context.getBalance(Context.getAddress()), - bnUSD, getBNUSDAvailableBalance()); + return Map.of(ICX, Context.getBalance(Context.getAddress()), bnUSD, getBNUSDAvailableBalance()); } @External(readonly = true) @@ -116,22 +135,32 @@ public BigInteger getEmergencyFund() { return getTotalFundBNUSD().get(EMERGENCY_FUND); } + @External + public void setFundManagersRewards(int paymentPercentage) { +// validateGovernanceContract(); + validateAdmins(); + Context.require(paymentPercentage >= 0 && paymentPercentage <= 100, TAG + " :InvalidPercentage"); + councilManagerRewardPercentage.set(paymentPercentage); + setRewardPool(INITIAL_FUND); + } + + @External(readonly = true) + public int getFundManagersRewards() { + return councilManagerRewardPercentage.getOrDefault(0); + } private Map getTotalFundBNUSD() { BigInteger bnusdBalance = (BigInteger) Context.call(balancedDollar.get(), "balanceOf", Context.getAddress()); BigInteger emergencyFund = this.emergencyFund.getOrDefault(BigInteger.ZERO); BigInteger availableBalance = bnusdBalance.subtract(emergencyFund); - return Map.of(BNUSD_BALANCE, bnusdBalance, - EMERGENCY_FUND, emergencyFund, - AVAILABLE_BALANCE, availableBalance); + return Map.of(BNUSD_BALANCE, bnusdBalance, EMERGENCY_FUND, emergencyFund, AVAILABLE_BALANCE, availableBalance); } @Override @External(readonly = true) public Map getRemainingSwapAmount() { BigInteger maxCap = treasuryFundbnUSD.get(); - return Map.of(MAX_CAP, maxCap, - REMAINING_TO_SWAP, maxCap.subtract(getBNUSDAvailableBalance())); + return Map.of(MAX_CAP, maxCap, REMAINING_TO_SWAP, maxCap.subtract(getBNUSDAvailableBalance())); } private void returnFundAmount(Address address, BigInteger value) { @@ -142,9 +171,7 @@ private void returnFundAmount(Address address, BigInteger value) { @Override @External - public void transferProposalFundToCpsTreasury(String ipfsKey, int projectDuration, - Address sponsorAddress, Address contributorAddress, - String tokenFlag, BigInteger totalBudget) { + public void transferProposalFundToCpsTreasury(String ipfsKey, int projectDuration, Address sponsorAddress, Address contributorAddress, String tokenFlag, BigInteger totalBudget) { validateCpsScore(); Context.require(!proposalExists(ipfsKey), TAG + ": Project already exists. Invalid IPFS Hash"); Context.require(tokenFlag.equals(bnUSD), TAG + ": " + tokenFlag + " is not supported. Only " + bnUSD + " token available."); @@ -176,8 +203,7 @@ public void transferProposalFundToCpsTreasury(String ipfsKey, int projectDuratio @Override @External - public void updateProposalFund(String ipfsKey, @Optional String flag, @Optional BigInteger addedBudget, - @Optional int totalInstallmentCount) { + public void updateProposalFund(String ipfsKey, @Optional String flag, @Optional BigInteger addedBudget, @Optional int totalInstallmentCount) { validateCpsScore(); Context.require(proposalExists(ipfsKey), TAG + ": IPFS hash does not exist."); Context.require(flag != null && flag.equals(bnUSD), TAG + ": Unsupported token. " + flag); @@ -273,7 +299,7 @@ private void swapIcxBnusd(BigInteger amount, BigInteger _minReceive) { } Context.call(amount, routerScore.get(), "route", path, _minReceive); } catch (Exception e) { - Context.println("Ignoring Errors from Router. Error Message: " + e.getMessage()); + Context.println("Ignoring Errors from Router. Error Message: " + e.getMessage()); } } } @@ -331,7 +357,7 @@ public void withdrawFromEmergencyFund(BigInteger value, Address address, String Address balancedDollar = CPFTreasury.balancedDollar.get(); Context.call(balancedDollar, TRANSFER, address, value, "".getBytes()); - EmergencyFundTransferred(address, value,purpose); + EmergencyFundTransferred(address, value, purpose); } @@ -394,6 +420,66 @@ public void setOraclePercentageDifference(int value) { oraclePerDiff.set(value); } + @External + public void setRewardPool(String key) { + validateCpsScore(); + Context.require(key.equals(INITIAL_FUND) || key.equals(FINAL_FUND), TAG + ": incorrectKeyForPool"); + rewardPool.set(key, getTotalFundBNUSD().get(AVAILABLE_BALANCE)); + } + + @External(readonly = true) + public Map getRewardPool() { + BigInteger finalFund = rewardPool.getOrDefault(FINAL_FUND, BigInteger.ZERO); + BigInteger initialFund = rewardPool.getOrDefault(INITIAL_FUND, BigInteger.ZERO); + BigInteger fundDiff = finalFund.subtract(initialFund); + BigInteger rewardPool = fundDiff.multiply(BigInteger.valueOf(getFundManagersRewards())).divide(BigInteger.valueOf(100)); + return Map.of(INITIAL_FUND, initialFund, FINAL_FUND, finalFund, REWARD_POOL, rewardPool); + } + + @External + public void distributeRewardToFundManagers() { + validateCpsScore(); + if (getFundManagersRewards() > 0) { + try { + Map rewardPool = getRewardPool(); + BigInteger initialFund = rewardPool.get(INITIAL_FUND); + BigInteger finalFund = rewardPool.get(FINAL_FUND); + + Context.require((initialFund.compareTo(BigInteger.ZERO) > 0 && finalFund.compareTo(BigInteger.ZERO) > 0), TAG + ": RewardPoolIsEmpty"); + + BigInteger rewardPoolAmount = rewardPool.get(REWARD_POOL); + int len = councilManagers.size(); + BigInteger rewardAmount = rewardPoolAmount.divide(BigInteger.valueOf(len)); + + for (int i = 0; i < len; i++) { + Address manager = councilManagers.get(i); + councilManagersReward.set(manager, councilManagersReward.getOrDefault(manager, BigInteger.ZERO).add(rewardAmount)); + FundManagerRewardSet(manager, rewardAmount); + } + + } catch (Exception e) { + Context.println("Error in distributeRewardToFundManagers: " + e.getMessage()); + } + setRewardPool(INITIAL_FUND); + } + } + + @External(readonly = true) + public BigInteger getRewardAmountForManager(Address manager) { + return councilManagersReward.getOrDefault(manager, BigInteger.ZERO); + } + + @External + public void claimFundManagerReward() { + Address manager = Context.getCaller(); + BigInteger rewardAmount = councilManagersReward.getOrDefault(manager, BigInteger.ZERO); + Context.require(rewardAmount.compareTo(BigInteger.ZERO) > 0, TAG + ": No reward to claim."); + + councilManagersReward.set(manager, BigInteger.ZERO); + Context.call(balancedDollar.get(), TRANSFER, manager, rewardAmount, "".getBytes()); + FundManagerRewardClaimed(manager, rewardAmount); + } + @Override @External(readonly = true) public Map getProposalDetails(@Optional int startIndex, @Optional int endIndex) { @@ -433,8 +519,7 @@ public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { Address sICX = sICXScore.get(); Address caller = Context.getCaller(); - Context.require(caller.equals(bnUSDScore) || caller.equals(sICX), TAG + - " Only " + bnUSDScore + " and " + sICX + " can send tokens to CPF Treasury."); + Context.require(caller.equals(bnUSDScore) || caller.equals(sICX), TAG + " Only " + bnUSDScore + " and " + sICX + " can send tokens to CPF Treasury."); if (caller.equals(sICX)) { if (_from.equals(dexScore.get())) { JsonObject swapICX = new JsonObject(); @@ -444,7 +529,6 @@ public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { Context.revert(TAG + ": sICX can be approved only from Balanced DEX."); } } else { - if (_data == null || new String(_data).equalsIgnoreCase("none")) { _data = "{}".getBytes(); } @@ -484,7 +568,7 @@ public void fallback() { } @External - public void migrateOldHashToNewHash(String oldHash, String newHash){ + public void migrateOldHashToNewHash(String oldHash, String newHash) { validateCpsScore(); int size = proposalsKeys.size(); for (int i = 0; i < size; i++) { @@ -494,8 +578,8 @@ public void migrateOldHashToNewHash(String oldHash, String newHash){ } BigInteger totalBudget = proposalBudgets.get(oldHash); - proposalBudgets.set(oldHash,null); - proposalBudgets.set(newHash,totalBudget); + proposalBudgets.set(oldHash, null); + proposalBudgets.set(newHash, totalBudget); } @@ -523,4 +607,12 @@ public void FundReceived(Address _sponsor_address, String note) { @EventLog(indexed = 1) public void EmergencyFundTransferred(Address _address, BigInteger _value, String _purpose) { } + + @EventLog(indexed = 1) + public void FundManagerRewardSet(Address _address, BigInteger _value) { + } + + @EventLog(indexed = 1) + public void FundManagerRewardClaimed(Address _address, BigInteger _value) { + } } diff --git a/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/Constants.java b/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/Constants.java index a440ebdb..ff084bda 100644 --- a/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/Constants.java +++ b/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/Constants.java @@ -17,6 +17,11 @@ public class Constants { public static final String PROPOSALS_KEYS = "_proposals_keys"; public static final String TREASURY_FUND = "treasury_fund"; public static final String EMERGENCY_FUND = "emergencyFund"; + public static final String REWARD_POOL = "rewardPool"; + + public static final String INITIAL_FUND = "initialFund"; + public static final String FINAL_FUND = "finalFund"; + public static final String AVAILABLE_BALANCE = "availableBalance"; public static final String TREASURY_FUND_BNUSD = "treasury_fund_bnusd"; @@ -49,6 +54,11 @@ public class Constants { public static final String STATE = "state"; public static final Address SYSTEM_ADDRESS = Address.fromString("cx0000000000000000000000000000000000000000"); + public static final String COUNCIL_FLAG = "council_flag"; + public static final String COUNCIL_MANAGERS = "council_managers"; + public static final String COUNCIL_MANAGERS_REWARD = "councilManagersReward"; + public static final String COUNCIL_MANAGERS_REWARD_PERCENTAGE = "councilManagersRewardPercentage"; + public static final int sICXICXPoolID = 1; public static final int sICXBNUSDPoolID = 2; diff --git a/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/SetterGetter.java b/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/SetterGetter.java index 41808227..1698c965 100644 --- a/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/SetterGetter.java +++ b/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/SetterGetter.java @@ -1,11 +1,18 @@ package community.icon.cps.score.cpftreasury; import score.Address; +import score.ArrayDB; import score.Context; import score.annotation.External; +import scorex.util.ArrayList; import java.math.BigInteger; +import java.util.List; +import static community.icon.cps.score.cpftreasury.CPFTreasury.councilFlag; +import static community.icon.cps.score.cpftreasury.CPFTreasury.councilManagers; +import static community.icon.cps.score.cpftreasury.Constants.TAG; +import static community.icon.cps.score.cpftreasury.Validations.validateAdmins; import static community.icon.cps.score.cpftreasury.Validations.validateGovernanceContract; public class SetterGetter { @@ -153,20 +160,67 @@ public Address getOracleAddress() { @External public void setSponsorBondPercentage(BigInteger bondValue) { - validateGovernanceContract(); - Context.call( getCpsScore(), "setSponsorBondPercentage",bondValue); + validateAdmins(); + Context.call(getCpsScore(), "setSponsorBondPercentage", bondValue); } @External public void setPeriod(BigInteger applicationPeriod) { validateGovernanceContract(); - Context.call(getCpsScore(), "setPeriod",applicationPeriod); + Context.call(getCpsScore(), "setPeriod", applicationPeriod); } @External public void setOnsetPayment(BigInteger paymentPercentage) { validateGovernanceContract(); - Context.call(getCpsTreasuryScore(), "setOnsetPayment",paymentPercentage); + Context.call(getCpsTreasuryScore(), "setOnsetPayment", paymentPercentage); + } + + @External + public void toggleCouncilFlag() { + validateGovernanceContract(); + councilFlag.set(!councilFlag.getOrDefault(false)); + } + + @External(readonly = true) + public boolean getCouncilFlag() { + return councilFlag.getOrDefault(false); + } + + @External + public void setCouncilManagers(Address[] newCouncilManagers) { + validateGovernanceContract(); + int sizeOfCouncilManagers = newCouncilManagers.length; + Context.require(sizeOfCouncilManagers >= 3, TAG + ":: council managers should be greater than 3"); + Context.require(sizeOfCouncilManagers % 2 == 1, TAG + ":: council managers should be an odd number"); + if (councilManagers.size() > 0) { + clearArrayDb(councilManagers); + } + for (Address newCouncilManager : newCouncilManagers) { + councilManagers.add(newCouncilManager); + } + } + + @External(readonly = true) + public List
getCouncilManagers() { + return arrayDBtoList(councilManagers); + } + + + List arrayDBtoList(ArrayDB arraydb) { + List list = new ArrayList<>(); + for (int i = 0; i < arraydb.size(); i++) { + list.add(arraydb.get(i)); + } + return list; + } + + void clearArrayDb(ArrayDB array_db) { + int size = array_db.size(); + for (int i = 0; i < size; i++) { + array_db.pop(); + } + } } diff --git a/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/Validations.java b/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/Validations.java index d3defdab..3fd3d6eb 100644 --- a/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/Validations.java +++ b/CPFTreasury/src/main/java/community/icon/cps/score/cpftreasury/Validations.java @@ -3,7 +3,6 @@ import score.Address; import score.Context; -import static community.icon.cps.score.cpftreasury.Constants.SYSTEM_ADDRESS; import static community.icon.cps.score.cpftreasury.Constants.TAG; public class Validations { @@ -14,7 +13,9 @@ public static void validateAdmins() { } public static void validateGovernanceContract() { - Context.require(Context.getCaller().equals(SYSTEM_ADDRESS), + Address caller = Context.getCaller(); + Address owner = Context.getOwner(); + Context.require(caller.equals(owner), TAG + ": Only Admins can call this method"); } diff --git a/CPFTreasury/src/test/java/community/icon/cps/score/cpftreasury/CPFTTreasuryTest.java b/CPFTreasury/src/test/java/community/icon/cps/score/cpftreasury/CPFTTreasuryTest.java index 86629044..2cc6a6af 100644 --- a/CPFTreasury/src/test/java/community/icon/cps/score/cpftreasury/CPFTTreasuryTest.java +++ b/CPFTreasury/src/test/java/community/icon/cps/score/cpftreasury/CPFTTreasuryTest.java @@ -15,15 +15,27 @@ import score.Context; import score.DictDB; import score.VarDB; +import scorex.util.HashMap; +import java.util.Arrays; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; import java.util.Map; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; public class CPFTTreasuryTest extends TestBase { private static final Address score_address = Address.fromString("cx0000000000000000000000000000000000000000"); @@ -36,6 +48,8 @@ public class CPFTTreasuryTest extends TestBase { public static final String TAG = "CPF_TREASURY"; private static final BigInteger MULTIPLIER = new BigInteger("1000000000000000000"); + VarDB
cpsScore = mock(VarDB.class); + private static final ServiceManager sm = getServiceManager(); private static final Account owner = sm.createAccount(); @@ -49,7 +63,7 @@ public class CPFTTreasuryTest extends TestBase { @BeforeEach public void setup() throws Exception { - tokenScore = sm.deploy(owner, CPFTreasury.class); + tokenScore = sm.deploy(owner, CPFTreasury.class,cpsScore.get()); } @Test @@ -76,7 +90,6 @@ public void setMaximumTreasuryFundBNUSDExceptions(Account address) { @Test void setCPSScore() { - VarDB
cpsScore = mock(VarDB.class); try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true); tokenScore.invoke(owner, "setCpsScore", score_address); @@ -86,7 +99,6 @@ void setCPSScore() { @Test void setCPSTreasuryScore() { - VarDB
cpsScore = mock(VarDB.class); try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true); tokenScore.invoke(owner, "setCpsTreasuryScore", score_address); @@ -96,7 +108,6 @@ void setCPSTreasuryScore() { @Test void setBMUSDScore() { - VarDB
cpsScore = mock(VarDB.class); try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true); tokenScore.invoke(owner, "setBnUSDScore", score_address); @@ -106,7 +117,6 @@ void setBMUSDScore() { @Test void setSICXScore() { - VarDB
cpsScore = mock(VarDB.class); try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true); tokenScore.invoke(owner, "setSicxScore", score_address); @@ -116,7 +126,6 @@ void setSICXScore() { @Test void setDEXScore() { - VarDB
cpsScore = mock(VarDB.class); try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true); tokenScore.invoke(owner, "setDexScore", score_address); @@ -126,7 +135,6 @@ void setDEXScore() { @Test void setRouterScore() { - VarDB
cpsScore = mock(VarDB.class); try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true); tokenScore.invoke(owner, "setRouterScore", score_address); @@ -175,7 +183,6 @@ void setDEXScoreExceptions(Account address, Address _score) { } void setRouterScoreExceptions(Account address, Address _score) { - VarDB
cpsScore = mock(VarDB.class); try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(false); tokenScore.invoke(address, "setRouterScore", _score); @@ -186,7 +193,6 @@ void setRouterScoreExceptions(Account address, Address _score) { @Test void setCPSScoreNotAdmin() { - VarDB
cpsScore = mock(VarDB.class); try (MockedStatic theMock = Mockito.mockStatic(Context.class)){ theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(false); tokenScore.invoke(testing_account, "setCpsScore", score_address); @@ -290,7 +296,6 @@ void updateProposalFund() { } void setMaxCapIcxAndBnusd() { - VarDB
cpsScore = mock(VarDB.class); try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true); tokenScore.invoke(owner, "setMaximumTreasuryFundIcx", BigInteger.valueOf(2000).multiply(MULTIPLIER)); @@ -301,7 +306,6 @@ void setMaxCapIcxAndBnusd() { @Test void setMaxCapIcxAndBnusdTest() { - VarDB
cpsScore = mock(VarDB.class); try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true); tokenScore.invoke(owner, "setMaximumTreasuryFundIcx", BigInteger.valueOf(2000).multiply(MULTIPLIER)); @@ -313,7 +317,6 @@ void setMaxCapIcxAndBnusdTest() { void swapIcxBnusd() { setSICXScoreMethod(sicxScore); setBNUSDScoreMethod(bnUSDScore); - VarDB
cpsScore = mock(VarDB.class); VarDB
routerScore = mock(VarDB.class); try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true); @@ -687,7 +690,6 @@ void fallbackSenderIsNotDex() { @Test void toggleSwapFlag(){ - VarDB
cpsScore = mock(VarDB.class); try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true); tokenScore.invoke(owner,"toggleSwapFlag"); @@ -697,7 +699,6 @@ void toggleSwapFlag(){ @Test void transferToEmergencyFund(){ - VarDB
cpsScore = mock(VarDB.class); VarDB
balanceDollar = mock(VarDB.class); BigInteger emergencyFund = BigInteger.valueOf(10).multiply(ICX); try (MockedStatic theMock = Mockito.mockStatic(Context.class)){ @@ -712,7 +713,6 @@ void transferToEmergencyFund(){ @Test void withdrawFromEmergencyFund(){ transferToEmergencyFund(); - VarDB
cpsScore = mock(VarDB.class); VarDB
balanceDollar = mock(VarDB.class); BigInteger withdrawAmount = BigInteger.valueOf(4).multiply(ICX); try (MockedStatic theMock = Mockito.mockStatic(Context.class)){ @@ -727,7 +727,6 @@ void withdrawFromEmergencyFund(){ @Test void slippagePercentage() { - VarDB
cpsScore = mock(VarDB.class); int value = 10; try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true); @@ -739,6 +738,120 @@ void slippagePercentage() { } } + @Test + void toggleCouncilFlag(){ + try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { + theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true); + tokenScore.invoke(owner,"toggleCouncilFlag"); + assertEquals(true,tokenScore.call("getCouncilFlag")); + } + } + + @Test +void setCouncilManagers() { + Address A = Address.fromString("hx0000000000000000000000000000000000000007"); + Address B = Address.fromString("hx0000000000000000000000000000000000000008"); + Address C = Address.fromString("hx0000000000000000000000000000000000000009"); + + Address[] CManagers = {A, B, C}; + + try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { + theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true); + tokenScore.invoke(owner, "setCouncilManagers", (Object) CManagers); + + List
returnedManagers = (List
) tokenScore.call("getCouncilManagers"); + + for (int i = 0; i < CManagers.length; i++) { + assertEquals(CManagers[i], returnedManagers.get(i)); + } + } +} + +@Test +public void testSetRewardPool() { + setCPSScoreMethod(score_address); + + final String AVAILABLE_BALANCE = "availableBalance"; + + String initialFundKey = "INITIAL_FUND"; + String finalFundKey = "FINAL_FUND"; + String invalidKey = "INVALID_KEY"; + BigInteger availableBalance = BigInteger.valueOf(1000); + + Map totalFund = new HashMap<>(); + totalFund.put(AVAILABLE_BALANCE, availableBalance); + + VarDB rewardPoolMock = mock(VarDB.class); + + CPFTreasury cpsScore = mock(CPFTreasury.class); + + when(rewardPoolMock.get()).thenReturn(availableBalance); + + cpsScore.setRewardPool(initialFundKey); + + assertEquals(availableBalance, rewardPoolMock.get()); + + cpsScore.setRewardPool(finalFundKey); + + assertEquals(availableBalance, rewardPoolMock.get()); + + // IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + // cpsScore.setRewardPool(invalidKey); + // }); + // assertTrue(exception.getMessage().contains("incorrectKeyForPool")); +} + + +public class RewardVoteTest { + + private final BigInteger EXA = BigInteger.valueOf(1_000_000_000_000_000_000L); + + @Test + public void testRewardVote() { + setCPSScoreMethod(score_address); + MockedStatic contextMock = mockStatic(Context.class); + + BigInteger newFunds = BigInteger.valueOf(400).multiply(EXA); + + contextMock.when(() -> getRemainingFund()).thenReturn(newFunds); + + Address A = Address.fromString("hx0000000000000000000000000000000000000001"); + Address B = Address.fromString("hx0000000000000000000000000000000000000002"); + List
councilManagers = Arrays.asList(A, B); + contextMock.when(() -> getCouncilManagers()).thenReturn(councilManagers); + + rewardVote(); + + BigInteger expectedRewardPerManager = BigInteger.valueOf(4).multiply(EXA); + contextMock.verify(() -> Context.call(A, "distributeRewardToFundManagers", expectedRewardPerManager)); + contextMock.verify(() -> Context.call(B, "distributeRewardToFundManagers", expectedRewardPerManager)); + + contextMock.close(); + } + + private BigInteger getRemainingFund() { + return BigInteger.ZERO; + } + + private List
getCouncilManagers() { + return Arrays.asList(); + } + + private void rewardVote() { + BigInteger initialFund = getRemainingFund(); + BigInteger finalFund = BigInteger.valueOf(400).multiply(EXA); + + BigInteger rewardPool = finalFund.subtract(initialFund).multiply(BigInteger.valueOf(2)).divide(BigInteger.valueOf(100)); + List
councilManagers = getCouncilManagers(); + BigInteger rewardPerManager = rewardPool.divide(BigInteger.valueOf(councilManagers.size())); + + for (Address manager : councilManagers) { + Context.call(manager, "distributeRewardToFundManagers", rewardPerManager); + } + } +} + + public void expectErrorMessage(Executable contractCall, String errorMessage) { AssertionError e = Assertions.assertThrows(AssertionError.class, contractCall); @@ -746,7 +859,6 @@ public void expectErrorMessage(Executable contractCall, String errorMessage) { } void setCPSScoreMethod(Address scoreAddress) { - VarDB
cpsScore = mock(VarDB.class); try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true); tokenScore.invoke(owner, "setCpsScore", scoreAddress); @@ -754,7 +866,6 @@ void setCPSScoreMethod(Address scoreAddress) { } void setCPSTreasuryScoreMetod(Address scoreAddress) { - VarDB
cpsScore = mock(VarDB.class); try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true); tokenScore.invoke(owner, "setCpsTreasuryScore", scoreAddress); @@ -762,7 +873,6 @@ void setCPSTreasuryScoreMetod(Address scoreAddress) { } void setBNUSDScoreMethod(Address scoreAddress) { - VarDB
cpsScore = mock(VarDB.class); try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true); tokenScore.invoke(owner, "setBnUSDScore", scoreAddress); @@ -770,7 +880,6 @@ void setBNUSDScoreMethod(Address scoreAddress) { } void setOracleAddressMethod(Address scoreAddress) { - VarDB
cpsScore = mock(VarDB.class); try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true); tokenScore.invoke(owner, "setOracleAddress", scoreAddress); @@ -778,7 +887,6 @@ void setOracleAddressMethod(Address scoreAddress) { } void setSICXScoreMethod(Address scoreAddress) { - VarDB
cpsScore = mock(VarDB.class); try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true); tokenScore.invoke(owner, "setSicxScore", scoreAddress); @@ -786,7 +894,6 @@ void setSICXScoreMethod(Address scoreAddress) { } void setDEXScoreMethod(Address scoreAddress) { - VarDB
cpsScore = mock(VarDB.class); try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true); tokenScore.invoke(owner, "setDexScore", scoreAddress); @@ -794,7 +901,6 @@ void setDEXScoreMethod(Address scoreAddress) { } void setRouterScoreMethod(Address scoreAddress) { - VarDB
cpsScore = mock(VarDB.class); try (MockedStatic theMock = Mockito.mockStatic(Context.class)) { theMock.when(() -> Context.call(cpsScore.get(), "isAdmin", Context.getCaller())).thenReturn(true); tokenScore.invoke(owner, "setRouterScore", score_address); diff --git a/CPSCore/build.gradle b/CPSCore/build.gradle index d09e2b15..bcacd745 100644 --- a/CPSCore/build.gradle +++ b/CPSCore/build.gradle @@ -1,21 +1,25 @@ -version = '1.3.9' +version = '1.5.5' dependencies { - compileOnly 'foundation.icon:javaee-api:0.9.2' - implementation 'com.github.sink772:minimal-json:0.9.7' - implementation 'foundation.icon:javaee-scorex:0.5.3' + + +// compileOnly 'foundation.icon:javaee-api:0.9.2' +// implementation 'com.github.sink772:minimal-json:0.9.7' +// implementation 'foundation.icon:javaee-scorex:0.5.3' implementation project(':score-lib') testImplementation project(':test-lib') - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.0' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0' testImplementation('org.mockito:mockito-inline:4.8.0') - testImplementation 'foundation.icon:javaee-unittest:0.9.7' - intTestImplementation 'foundation.icon:icon-sdk:2.2.0' - intTestImplementation project(":score-client") - intTestAnnotationProcessor project(":score-client") - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0' + +// testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.0' +// testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0' +// testImplementation('org.mockito:mockito-inline:4.8.0') +// testImplementation 'foundation.icon:javaee-unittest:0.9.7' +// intTestImplementation 'foundation.icon:icon-sdk:2.2.0' +//// intTestImplementation project(":score-client") +//// intTestAnnotationProcessor project(":score-client") +// testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0' } optimizedJar { @@ -23,6 +27,7 @@ optimizedJar { from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } } + enableDebug = false } deployJar { @@ -30,31 +35,25 @@ deployJar { lisbon { uri = 'https://lisbon.net.solidwallet.io/api/v3' nid = 0x2 - to = 'cx8e21d3b7a70aeeaca45d4a70c31a6b959f5823bd' - } - local { - uri = 'http://localhost:9082/api/v3' - nid = 0x3 - } - berlin { - uri = 'https://berlin.net.solidwallet.io/api/v3' - nid = 0x7 - } - sejong { - uri = 'https://sejong.net.solidwallet.io/api/v3' - nid = 0x53 - to = 'cx2b214d56805531b9c878c4d4ff0e53d961c60834' + to = "cx1a7a9bde78fe14e2aeea03966c6d7260575627f5" } mainnet { uri = 'https://ctz.solidwallet.io/api/v3' nid = 0x1 to = 'cx9f4ab72f854d3ccdc59aa6f2c3e2215dd62e879f' } - + devnet{ + uri = "https://tt.net.solidwallet.io/api/v3" + nid = 0x3 + to = "cx5100c8b221cc373939d8a720ecfbd90440c75ed3" + } } keystore = rootProject.hasProperty('keystoreName') ? "$keystoreName" : '' password = rootProject.hasProperty('keystorePass') ? "$keystorePass" : '' parameters { + arg("applicationPeriod", "15") + arg("bondValue", "15") + } } @@ -65,3 +64,24 @@ test { repositories { mavenCentral() } + +task integrationTest(type: Test) { + useJUnitPlatform() + + + rootProject.allprojects { + if (it.getTasks().findByName('optimizedJar')) { + dependsOn(it.getTasks().getByName('optimizedJar')) + } + } + + options { + testLogging.showStandardStreams = true + description = 'Runs integration tests.' + group = 'verification' + + testClassesDirs = sourceSets.intTest.output.classesDirs + classpath = sourceSets.intTest.runtimeClasspath + } + +} diff --git a/CPSCore/src/intTest/java/community/icon/cps/integration/CPSCoreIntegration.java b/CPSCore/src/intTest/java/community/icon/cps/integration/CPSCoreIntegration.java new file mode 100644 index 00000000..98993b3c --- /dev/null +++ b/CPSCore/src/intTest/java/community/icon/cps/integration/CPSCoreIntegration.java @@ -0,0 +1,1784 @@ +package community.icon.cps.integration; + +import com.eclipsesource.json.JsonObject; +import community.icon.cps.score.lib.interfaces.CPSCoreInterface; +import community.icon.cps.score.lib.interfaces.CPSCoreInterface.MilestonesAttributes; +import community.icon.cps.score.lib.interfaces.CPSCoreInterface.MilestoneVoteAttributes; +import community.icon.cps.score.lib.interfaces.CPSCoreInterface.ProposalAttributes; +import community.icon.cps.score.lib.interfaces.CPSCoreInterface.ProgressReportAttributes; +import community.icon.cps.score.test.integration.scores.CPSCoreInterfaceScoreClient; +import community.icon.cps.score.test.integration.CPS; +import community.icon.cps.score.test.integration.CPSClient; +import community.icon.cps.score.test.integration.ScoreIntegrationTest; +import community.icon.cps.score.test.integration.config.BaseConfig; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import score.Address; + +import static community.icon.cps.score.cpscore.utils.Constants.*; +import static community.icon.cps.score.test.AssertRevertedException.assertUserRevert; +import static community.icon.cps.score.test.integration.Environment.godClient; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static community.icon.cps.score.test.integration.Environment.preps; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import community.icon.cps.score.test.integration.scores.SystemInterfaceScoreClient; +import score.UserRevertException; +import score.annotation.Optional; + +public class CPSCoreIntegration implements ScoreIntegrationTest { + + private static CPSClient ownerClient; + private static CPSClient testClient; + private static CPSClient readerClient; + static Set> prepSet = preps.entrySet(); + + private final BigInteger ICX = BigInteger.valueOf(10).pow(18); + + private static Map addressMap; + public static Map cpsClients = new HashMap<>(); + + @BeforeAll + public static void setup() throws Exception { + String contracts = "conf/contracts.json"; + CPS cps = new CPS(contracts); + + cps.setupCPS(); + addressMap = cps.getAddresses(); + ownerClient = cps.defaultClient(); + readerClient = cps.newClient(BigInteger.TEN.pow(24)); + testClient = cps.testClient(); + BaseConfig config = new BaseConfig(ownerClient); + config.call(); + + for (int i = 0; i < 7; i++) { + String privKey = prepSet.toArray()[i].toString().substring(43); + cpsClients.put(i, cps.customClient(privKey)); + + } + // ICX swap purpose + godClient._transfer(addressMap.get("dex"),BigInteger.valueOf(200).multiply(EXA),"transferICX to dex"); + + } + + @Test + @Order(1) + public void name() { + ownerClient.cpsCore.name(); + } + + + @DisplayName("register all preps") + @Test + @Order(1) + public void registerPrep() { + + // expected Prep address + List expectedPrepAddress = new ArrayList<>(cpsClients.size()); + for (CPSClient prepClient : cpsClients.values()) { + prepClient.cpsCore.registerPrep(); + expectedPrepAddress.add(prepClient.getAddress().toString()); + + } + + // actual prep address + List> preps = ownerClient.cpsCore.getPReps(); + List actualPrepAddress = new ArrayList<>(preps.size()); + for (Map prep : preps) { + actualPrepAddress.add((String) prep.get("address")); + } + + assertEquals(expectedPrepAddress, actualPrepAddress); +// SYSTEM_INTERFACE = new SystemInterfaceScoreClient(godClient); +// System.out.println(SYSTEM_INTERFACE.getPRepTerm()); + } + + @Test + @Order(2) + public void registerPrepExceptions() { + + // readerClient tries to be registered as prep + assertUserRevert(new UserRevertException(TAG + ": Not a P-Rep"), + () -> readerClient.cpsCore.registerPrep(), null); + + // registered prep registers again + CPSClient registeredPrep = cpsClients.get(0); + + assertUserRevert(new UserRevertException(TAG + ": P-Rep is already registered."), + () -> registeredPrep.cpsCore.registerPrep(), null); + + + } + + @DisplayName("unregister prep") + @Test + @Order(2) + public void unregisterPrep() { + CPSClient prep1 = cpsClients.get(0); + prep1.cpsCore.unregisterPrep(); + + // expected unregistered prep status + Map expectedPrepData = unregisteredPrepData(); + + Map actualPrepData = loginPrep(prep1.getAddress()); + assertEquals(expectedPrepData, actualPrepData); + + prep1.cpsCore.registerPrep(); + } + + + @DisplayName("check prep data") + @Test + @Order(3) + public void loginAsPrep() { + // query period status + Map periodStatus = getPeriodStatus(); + assertEquals(periodStatus.get(PERIOD_NAME), "Application Period"); + + CPSClient prep1 = cpsClients.get(0); + // expected prep1 status + Map expectedPrepData = votingPrepData(); + + Map actualPrepData = loginPrep(prep1.getAddress()); + assertEquals(expectedPrepData, actualPrepData); + } + + @DisplayName("submit proposal 1") + @Test + @Order(4) + public void submitProposal() { + CPSClient prep1 = cpsClients.get(0); + ProposalAttributes proposalAttributes = new ProposalAttributes(); + + proposalAttributes.ipfs_hash = "Test_Proposal_1"; + proposalAttributes.project_title = "Proposal_1"; + proposalAttributes.project_duration = 3; + proposalAttributes.total_budget = BigInteger.valueOf(100); + proposalAttributes.token = bnUSD; + proposalAttributes.sponsor_address = prep1.getAddress(); + proposalAttributes.ipfs_link = "https://proposal_1"; + proposalAttributes.milestoneCount = 3; + proposalAttributes.isMilestone = true; + + CPSCoreInterface.MilestonesAttributes milestonesAttributes1 = new CPSCoreInterface.MilestonesAttributes(); + milestonesAttributes1.completionPeriod = 1; + milestonesAttributes1.budget = BigInteger.valueOf(30).multiply(ICX); + milestonesAttributes1.id = 1; + + CPSCoreInterface.MilestonesAttributes milestonesAttributes2 = new CPSCoreInterface.MilestonesAttributes(); + milestonesAttributes2.completionPeriod = 2; + milestonesAttributes2.budget = BigInteger.valueOf(40).multiply(ICX); + milestonesAttributes2.id = 2; + + CPSCoreInterface.MilestonesAttributes milestonesAttributes3 = new CPSCoreInterface.MilestonesAttributes(); + milestonesAttributes3.completionPeriod = 3; + milestonesAttributes3.budget = BigInteger.valueOf(20).multiply(ICX); + milestonesAttributes3.id = 3; + + CPSCoreInterface.MilestonesAttributes[] milestonesAttributes = new CPSCoreInterface.MilestonesAttributes[] + {milestonesAttributes1, milestonesAttributes2, milestonesAttributes3}; + ((CPSCoreInterfaceScoreClient) testClient.cpsCore).submitProposal(BigInteger.valueOf(50).multiply(ICX), proposalAttributes, milestonesAttributes); + + List proposalsIpfs = readerClient.cpsCore.getProposalsKeysByStatus(SPONSOR_PENDING); + assertEquals(proposalsIpfs.size(), 1); + assertEquals(proposalsIpfs.get(0), proposalAttributes.ipfs_hash); + + verifyProposalDetails(proposalAttributes); + } + + private void verifyProposalDetails(ProposalAttributes expectedDetails) { + Map actualDetails = getProposalDetails(expectedDetails.ipfs_hash); + assertEquals(actualDetails.get("project_title"), expectedDetails.project_title); + assertEquals(actualDetails.get("sponsor_address"), expectedDetails.sponsor_address.toString()); + assertEquals(actualDetails.get("ipfs_hash"), expectedDetails.ipfs_hash); + assertEquals(toInt((String) actualDetails.get("project_duration")), expectedDetails.project_duration); + assertEquals(toInt((String) actualDetails.get("milestoneCount")), expectedDetails.milestoneCount); + assertEquals(toBigInt((String) actualDetails.get("total_budget")), expectedDetails.total_budget.multiply(ICX)); + + } + + + @DisplayName("submit sponsor vote on first proposal") + @Test + @Order(5) + public void submitSponsorVote() { + CPSClient sponsorPrep = cpsClients.get(0); + + bnUSDMint(sponsorPrep.getAddress(), BigInteger.valueOf(50).multiply(ICX)); + + byte[] data = createByteArray("sponsorVote", "Test_Proposal_1", ACCEPT, + "Proposal looks good"); + BigInteger sponsorBond = BigInteger.valueOf(15).multiply(ICX); + sponsorPrep.bnUSD.transfer(addressMap.get("cpsCore"), sponsorBond, data); + + List proposalsIpfs = readerClient.cpsCore.getProposalsKeysByStatus(PENDING); + assertEquals(proposalsIpfs.size(), 1); + assertEquals(proposalsIpfs.get(0), "Test_Proposal_1"); + + + Map proposalDetails = getProposalDetails("Test_Proposal_1"); + assertEquals(sponsorBond, toBigInt((String) proposalDetails.get(SPONSOR_DEPOSIT_AMOUNT))); + assertEquals(BOND_RECEIVED, proposalDetails.get(SPONSOR_DEPOSIT_STATUS)); + + assertEquals(BigInteger.valueOf(35).multiply(ICX), readerClient.bnUSD.balanceOf(sponsorPrep.getAddress())); + } + + @DisplayName("vote on first proposal") + @Test() + @Order(6) + public void voteProposal() throws InterruptedException { + // update Period + updateNextBlock(); + ownerClient.cpsCore.updatePeriod(); + + Map periodStatus = getPeriodStatus(); + assertEquals(periodStatus.get(PERIOD_NAME), "Voting Period"); + + Map proposalVote = getProposalVote("Test_Proposal_1"); + assertEquals(toInt((String) proposalVote.get("total_voters")), 0); + assertEquals(toInt((String) proposalVote.get("approve_voters")), 0); + assertEquals(toInt((String) proposalVote.get("reject_voters")), 0); + + for (CPSClient prepClient : cpsClients.values()) { + voteByPrep(prepClient, "Test_Proposal_1", APPROVE, "Seems fruitful", false); + prepClient.cpsCore.votePriority(new String[]{"Test_Proposal_1"}); + + } + proposalVote = getProposalVote("Test_Proposal_1"); + + assertEquals(toInt((String) proposalVote.get("total_voters")), 7); + assertEquals(toInt((String) proposalVote.get("approve_voters")), 7); + assertEquals(toInt((String) proposalVote.get("reject_voters")), 0); + + } + + @DisplayName("pass proposal 1 and send the initial payement") + @Test + @Order(7) + public void transferFundsToProposal() throws InterruptedException { + updateToApplicationPeriod(); + Map periodStatus = getPeriodStatus(); + assertEquals(periodStatus.get(PERIOD_NAME), "Application Period"); + + Map contributorProject = getContributorFunds(testClient.getAddress()); + List> contributorData = (List>) contributorProject.get("data"); + + assertEquals(toBigInt((String) contributorData.get(0).get("installment_amount")), BigInteger.valueOf(30).multiply(ICX)); + assertEquals(toBigInt((String) contributorData.get(0).get("total_budget")), BigInteger.valueOf(100).multiply(ICX)); + assertEquals(contributorData.get(0).get("total_installment_count"), "0x3"); + assertEquals(toBigInt((String) contributorData.get(0).get("total_installment_paid")), BigInteger.valueOf(10).multiply(ICX)); + assertEquals(contributorProject.get("project_count"), "0x1"); + + + Map sponsorProject = getSponsorFunds(cpsClients.get(0).getAddress()); + + List> sponsorData = (List>) sponsorProject.get("data"); + assertEquals(toBigInt((String) sponsorData.get(0).get("installment_amount")), BigInteger.valueOf(6).multiply(ICX).divide(BigInteger.TEN)); + assertEquals(toBigInt((String) sponsorData.get(0).get("sponsor_bond_amount")), BigInteger.valueOf(15).multiply(ICX)); + assertEquals(sponsorData.get(0).get("total_installment_count"), "0x3"); + assertEquals(toBigInt((String) sponsorData.get(0).get("total_installment_paid")), BigInteger.valueOf(2).multiply(ICX).divide(BigInteger.TEN)); + assertEquals(toBigInt((String) sponsorProject.get("withdraw_amount_bnUSD")), BigInteger.valueOf(2).multiply(ICX).divide(BigInteger.TEN)); + } + + + private Map getContributorFunds(Address contributorAddr) { + return readerClient.cpsTreasury.getContributorProjectedFund(contributorAddr); + } + + private Map getSponsorFunds(Address sponsorAddr) { + return readerClient.cpsTreasury.getSponsorProjectedFund(sponsorAddr); + } + + @DisplayName("submit first milestone") + @Test + @Order(8) + public void submitMilestoneReport() { + + List proposalsIpfs = readerClient.cpsCore.getProposalsKeysByStatus(ACTIVE); + assertEquals(proposalsIpfs.size(), 1); + assertEquals(proposalsIpfs.get(0), "Test_Proposal_1"); + + List> activeProposal = readerClient.cpsCore.getActiveProposals(testClient.getAddress()); + assertEquals("0x0", activeProposal.get(0).get("new_progress_report")); + + CPSCoreInterface.ProgressReportAttributes progressReportAttributes = createProgressReport("1", "Test_Proposal_1"); + + CPSCoreInterface.MilestoneSubmission submission = new CPSCoreInterface.MilestoneSubmission(); + submission.id = 1; + submission.status = true; + CPSCoreInterface.MilestoneSubmission[] milestoneSubmissions = new CPSCoreInterface.MilestoneSubmission[]{submission}; + + testClient.cpsCore.submitProgressReport(progressReportAttributes, milestoneSubmissions); + + activeProposal = readerClient.cpsCore.getActiveProposals(testClient.getAddress()); + assertEquals("0x1", activeProposal.get(0).get("new_progress_report")); + + + Map progressReportDetails = getProgressReportDetails("Test_Proposal_1_Report_Proposal_1"); + assertEquals(1,toInt((String) progressReportDetails.get(MILESTONE_SUBMITTED_COUNT))); + assertEquals(WAITING,progressReportDetails.get(STATUS)); + assertEquals("Test_Proposal_1_Report_1",progressReportDetails.get(PROGRESS_REPORT_TITLE)); + assertEquals("Test_Proposal_1_Report_Proposal_1",progressReportDetails.get(REPORT_HASH)); + + + int milestoneStatus = getMilestoneStatus("Test_Proposal_1", 1); + assertEquals(MILESTONE_REPORT_COMPLETED, milestoneStatus); + } + + private ProgressReportAttributes createProgressReport(String no, String ipfsHash) { + ProgressReportAttributes progressReportAttributes = new ProgressReportAttributes(); + progressReportAttributes.ipfs_hash = ipfsHash; + progressReportAttributes.progress_report_title = ipfsHash + "_Report_" + no; + progressReportAttributes.report_hash = ipfsHash + "_Report_Proposal_" + no; + progressReportAttributes.ipfs_link = "https://proposal_" + no; + progressReportAttributes.budget_adjustment = false; + progressReportAttributes.additional_budget = BigInteger.ZERO; + progressReportAttributes.additional_month = 0; + + return progressReportAttributes; + + } + + + @DisplayName("vote on first progress report") + @Test + @Order(9) + public void voteOnMilestone() throws InterruptedException { + updateNextBlock(); + ownerClient.cpsCore.updatePeriod(); + + Thread.sleep(2000); + Map periodStatus = getPeriodStatus(); + assertEquals(periodStatus.get(PERIOD_NAME), "Voting Period"); + + MilestoneVoteAttributes[] voteAttributes = new MilestoneVoteAttributes[]{vote(1, APPROVE)}; + + List> expectedMilestoneData = new ArrayList<>(7); + for (int i = 0; i < cpsClients.size(); i++) { + + cpsClients.get(i).cpsCore.voteProgressReport("Test_Proposal_1_Report_Proposal_1", "Working well " + i, + voteAttributes, null, false); + + expectedMilestoneData.add(Map.of( + ADDRESS, cpsClients.get(i).getAddress(), + PREP_NAME, cpsClients.get(i).getAddress(), + VOTE_REASON, "Working well " + i, + VOTE, APPROVE)); + } + + + Map progressReportVote = getProgressReportVote("Test_Proposal_1_Report_Proposal_1"); + assertEquals(toInt((String) progressReportVote.get("total_voters")),7); + + Map milestoneVoteResult = getMilestoneReport("Test_Proposal_1_Report_Proposal_1", 1); + assertEquals(toInt((String) milestoneVoteResult.get(APPROVE_VOTERS)),7); + assertEquals(toInt((String) milestoneVoteResult.get(REJECT_VOTERS)),0); + + + + List> actualMilestoneData = (List>) milestoneVoteResult.get(DATA); + + + for (int i = 0; i < 7; i++) { + assertEquals(expectedMilestoneData.get(0).get(ADDRESS).toString(), actualMilestoneData.get(0).get(ADDRESS)); + } + + int milestoneStatus = getMilestoneStatus("Test_Proposal_1", 1); + assertEquals(MILESTONE_REPORT_COMPLETED, milestoneStatus); + + + } + + private int getMilestoneStatus(String ipfsHash, int milestoneId) { + return readerClient.cpsCore.getMileststoneStatusOf(ipfsHash, milestoneId); + } + + private Map getMilestoneReport(String reportHash, int milestoneId) { + return readerClient.cpsCore.getMilestoneVoteResult(reportHash, milestoneId); + } + + private Map getProgressReportDetails(String reportHash) { + return readerClient.cpsCore.getProgressReportsByHash(reportHash); + } + + private Map getProgressReportVote(String reportHash) { + return readerClient.cpsCore.getProgressReportResult(reportHash); + } + + @DisplayName("submitting all remaining milestones") + @Test + @Order(10) + public void submitAllMilestoneReport() throws InterruptedException { + updateToApplicationPeriod(); + Map periodStatus = getPeriodStatus(); + assertEquals(periodStatus.get(PERIOD_NAME), "Application Period"); + + int milestoneStatus = getMilestoneStatus("Test_Proposal_1", 1); + assertEquals(MILESTONE_REPORT_APPROVED, milestoneStatus); + + + // verifying installment count and funds record + Map contributorProject = getContributorFunds(testClient.getAddress()); + List> contributorData = (List>) contributorProject.get("data"); + assertEquals(toBigInt((String) contributorData.get(0).get("installment_amount")), BigInteger.valueOf(40).multiply(ICX)); + assertEquals(toBigInt((String) contributorData.get(0).get("total_installment_paid")), BigInteger.valueOf(40).multiply(ICX)); + assertEquals(contributorData.get(0).get("total_times_installment_paid"), "0x1"); + assertEquals(contributorProject.get("project_count"), "0x1"); + assertEquals(toBigInt((String) contributorProject.get("withdraw_amount_bnUSD")), BigInteger.valueOf(40).multiply(ICX)); + + + Map sponsorProject = getSponsorFunds(cpsClients.get(0).getAddress()); + List> sponsorData = (List>) sponsorProject.get("data"); + assertEquals(toBigInt((String) sponsorData.get(0).get("installment_amount")), BigInteger.valueOf(6).multiply(ICX).divide(BigInteger.TEN)); + assertEquals(toBigInt((String) sponsorData.get(0).get("total_installment_paid")), BigInteger.valueOf(8).multiply(ICX).divide(BigInteger.TEN)); + assertEquals(sponsorData.get(0).get("total_times_installment_paid"), "0x1"); + assertEquals(toBigInt((String) sponsorProject.get("withdraw_amount_bnUSD")), BigInteger.valueOf(8).multiply(ICX).divide(BigInteger.TEN)); + + + CPSCoreInterface.ProgressReportAttributes progressReportAttributes = createProgressReport("2", "Test_Proposal_1"); + + CPSCoreInterface.MilestoneSubmission submissionNo2 = new CPSCoreInterface.MilestoneSubmission(); + submissionNo2.id = 2; + submissionNo2.status = true; + + CPSCoreInterface.MilestoneSubmission submissionNo3 = new CPSCoreInterface.MilestoneSubmission(); + submissionNo3.id = 3; + submissionNo3.status = true; + + CPSCoreInterface.MilestoneSubmission[] milestoneSubmissions = new CPSCoreInterface.MilestoneSubmission[]{ + submissionNo2, submissionNo3}; + + testClient.cpsCore.submitProgressReport(progressReportAttributes, milestoneSubmissions); + + + + Map progressReportDetails = getProgressReportDetails("Test_Proposal_1_Report_Proposal_2"); + assertEquals(2,toInt((String) progressReportDetails.get(MILESTONE_SUBMITTED_COUNT))); +// assertEquals(new String[]{"0x2","0x3"},progressReportDetails.get("milestoneId")); + assertEquals(WAITING,progressReportDetails.get(STATUS)); + assertEquals("Test_Proposal_1_Report_2",progressReportDetails.get(PROGRESS_REPORT_TITLE)); + assertEquals("Test_Proposal_1_Report_Proposal_2",progressReportDetails.get(REPORT_HASH)); + + + } + + + @DisplayName("vote on progress report 2") + @Test + @Order(11) + public void voteOnAllMilestone() throws InterruptedException { + + updateNextBlock(); + ownerClient.cpsCore.updatePeriod(); + + Thread.sleep(2000); + Map periodStatus = getPeriodStatus(); + assertEquals(periodStatus.get(PERIOD_NAME), "Voting Period"); + + MilestoneVoteAttributes[] voteAttributes = new MilestoneVoteAttributes[]{vote(2, APPROVE), vote(3, APPROVE)}; + + List> expectedMilestoneData = new ArrayList<>(7); + for (int i = 0; i < cpsClients.size(); i++) { + + cpsClients.get(i).cpsCore.voteProgressReport("Test_Proposal_1_Report_Proposal_2","Project is completed " + i, + voteAttributes,null,false); + + expectedMilestoneData.add(Map.of( + ADDRESS, cpsClients.get(i).getAddress(), + PREP_NAME, cpsClients.get(i).getAddress(), + VOTE_REASON, "Project is completed " + i, + VOTE, APPROVE)); + } + + + Map progressReportVote = getProgressReportVote("Test_Proposal_1_Report_Proposal_2"); + assertEquals(toInt((String) progressReportVote.get("total_voters")),7); + + Map milestoneVoteResult = getMilestoneReport("Test_Proposal_1_Report_Proposal_2", 2); + assertEquals(toInt((String) milestoneVoteResult.get(APPROVE_VOTERS)),7); + assertEquals(toInt((String) milestoneVoteResult.get(REJECT_VOTERS)),0); + + +// assertEquals(milestoneVoteResult.get(DATA),expectedMilestoneData); + List> actualMilestoneData = (List>) milestoneVoteResult.get(DATA); + + + for (int i = 0; i < 7; i++) { + assertEquals(expectedMilestoneData.get(0).get(ADDRESS).toString(), actualMilestoneData.get(0).get(ADDRESS)); + assertEquals(expectedMilestoneData.get(0).get(PREP_NAME).toString(), actualMilestoneData.get(0).get(PREP_NAME)); + assertEquals(expectedMilestoneData.get(0).get(VOTE_REASON), actualMilestoneData.get(0).get(VOTE_REASON)); + assertEquals(expectedMilestoneData.get(0).get(VOTE), actualMilestoneData.get(0).get(VOTE)); + + } + + int milestoneStatus = getMilestoneStatus("Test_Proposal_1", 2); + assertEquals(MILESTONE_REPORT_COMPLETED, milestoneStatus); + + } + + @DisplayName("proposal 1 is completed and user claims reward") + @Test + @Order(12) + public void completeProposal1() throws InterruptedException { + updateToApplicationPeriod(); + + int milestoneStatus = getMilestoneStatus("Test_Proposal_1", 3); + assertEquals(MILESTONE_REPORT_APPROVED, milestoneStatus); + + milestoneStatus = getMilestoneStatus("Test_Proposal_1", 2); + assertEquals(MILESTONE_REPORT_APPROVED, milestoneStatus); + + List proposalsIpfs = readerClient.cpsCore.getProposalsKeysByStatus(COMPLETED); + assertEquals(proposalsIpfs.size(), 1); + assertEquals(proposalsIpfs.get(0), "Test_Proposal_1"); + + + assertEquals(BigInteger.ZERO, readerClient.bnUSD.balanceOf(testClient.getAddress())); + testClient.cpsTreasury.claimReward(); + assertEquals(BigInteger.valueOf(100).multiply(ICX), readerClient.bnUSD.balanceOf(testClient.getAddress())); + + CPSClient sponsorClient = cpsClients.get(0); + assertEquals(BigInteger.valueOf(35).multiply(ICX), readerClient.bnUSD.balanceOf(sponsorClient.getAddress())); + sponsorClient.cpsTreasury.claimReward(); + assertEquals(BigInteger.valueOf(37).multiply(ICX), readerClient.bnUSD.balanceOf(sponsorClient.getAddress())); + + // sponsor bond is returned after completion of project + sponsorClient.cpsCore.claimSponsorBond(); + assertEquals(BigInteger.valueOf(52).multiply(ICX), readerClient.bnUSD.balanceOf(sponsorClient.getAddress())); + + + } + + // @DisplayName("proposal with greater milestone than project duration") + @DisplayName("submit proposal in different conditions") + @Nested + @TestMethodOrder(MethodOrderer.OrderAnnotation.class) + class submitProposal { + CPSClient sponsorPrep = cpsClients.get(0); + + @DisplayName("proposal with zero milestone") + @Test + @Order(1) + public void zeroMilestoneProposal() { + CPSClient sponsorPrep = cpsClients.get(0); + + ProposalAttributes proposalAttributes = new ProposalAttributes(); + + proposalAttributes.ipfs_hash = "Test_Proposal_2"; + proposalAttributes.project_title = "Proposal_2"; + proposalAttributes.project_duration = 3; + proposalAttributes.total_budget = BigInteger.valueOf(100); + proposalAttributes.token = bnUSD; + proposalAttributes.sponsor_address = sponsorPrep.getAddress(); + proposalAttributes.ipfs_link = "https://proposal_1"; + proposalAttributes.milestoneCount = 3; + proposalAttributes.isMilestone = true; + ; + + CPSCoreInterface.MilestonesAttributes[] milestonesAttributes = new MilestonesAttributes[] + {}; + + assertUserRevert(new UserRevertException(TAG + ": Milestone count mismatch"), + () -> ((CPSCoreInterfaceScoreClient) testClient.cpsCore).submitProposal(BigInteger.valueOf(50).multiply(ICX), proposalAttributes, milestonesAttributes), + null); + } + + @DisplayName("submit proposal when maintenance is on") + @Test + @Order(1) + public void maintenanceModeOff() { + + ownerClient.cpsCore.toggleMaintenance(); + + CPSClient sponsorPrep = cpsClients.get(0); + + ProposalAttributes proposalAttributes = new ProposalAttributes(); + + proposalAttributes.ipfs_hash = "Test_Proposal_2"; + proposalAttributes.project_title = "Proposal_2"; + proposalAttributes.project_duration = 1; + proposalAttributes.total_budget = BigInteger.valueOf(50); + proposalAttributes.token = bnUSD; + proposalAttributes.sponsor_address = sponsorPrep.getAddress(); + proposalAttributes.ipfs_link = "https://proposal_1"; + proposalAttributes.milestoneCount = 1; + proposalAttributes.isMilestone = true; + + CPSCoreInterface.MilestonesAttributes milestonesAttributes1 = new CPSCoreInterface.MilestonesAttributes(); + milestonesAttributes1.completionPeriod = 1; + milestonesAttributes1.budget = BigInteger.valueOf(50).multiply(ICX); + milestonesAttributes1.id = 1; + + CPSCoreInterface.MilestonesAttributes[] milestonesAttributes = new MilestonesAttributes[] + {milestonesAttributes1}; + + assertUserRevert(new UserRevertException(TAG + ": Maintenance mode is on. Will resume soon."), + () -> ((CPSCoreInterfaceScoreClient) testClient.cpsCore).submitProposal(BigInteger.valueOf(50).multiply(ICX), proposalAttributes, milestonesAttributes), + null); + + } + + @DisplayName("submit proposal when same milestone id") + @Test + @Order(1) + public void milestoneWithSameId() { + + ownerClient.cpsCore.toggleMaintenance(); + + CPSClient sponsorPrep = cpsClients.get(0); + + ProposalAttributes proposalAttributes = new ProposalAttributes(); + + proposalAttributes.ipfs_hash = "Test_Proposal_2"; + proposalAttributes.project_title = "Proposal_2"; + proposalAttributes.project_duration = 2; + proposalAttributes.total_budget = BigInteger.valueOf(50); + proposalAttributes.token = bnUSD; + proposalAttributes.sponsor_address = sponsorPrep.getAddress(); + proposalAttributes.ipfs_link = "https://proposal_1"; + proposalAttributes.milestoneCount = 2; + proposalAttributes.isMilestone = true; + + CPSCoreInterface.MilestonesAttributes milestonesAttributes1 = new CPSCoreInterface.MilestonesAttributes(); + milestonesAttributes1.completionPeriod = 1; + milestonesAttributes1.budget = BigInteger.valueOf(50).multiply(ICX); + milestonesAttributes1.id = 1; + + CPSCoreInterface.MilestonesAttributes milestonesAttributes2 = new CPSCoreInterface.MilestonesAttributes(); + milestonesAttributes2.completionPeriod = 2; + milestonesAttributes2.budget = BigInteger.valueOf(40).multiply(ICX); + milestonesAttributes2.id = 1; + + CPSCoreInterface.MilestonesAttributes[] milestonesAttributes = new MilestonesAttributes[] + {milestonesAttributes1, milestonesAttributes2}; + + assertUserRevert(new UserRevertException(TAG + ":: Total milestone budget and project budget is not equal"), + () -> ((CPSCoreInterfaceScoreClient) testClient.cpsCore).submitProposal(BigInteger.valueOf(50).multiply(ICX), proposalAttributes, milestonesAttributes), + null); + + } + + @DisplayName("submit proposal when with higher milestone count than project duration") + @Test + @Order(2) + public void proposalWithMoreMilestone() { + +// ownerClient.cpsCore.toggleMaintenance(); + + CPSClient sponsorPrep = cpsClients.get(0); + + ProposalAttributes proposalAttributes = new ProposalAttributes(); + + proposalAttributes.ipfs_hash = "Test_Proposal_2"; + proposalAttributes.project_title = "Proposal_2"; + proposalAttributes.project_duration = 2; + proposalAttributes.total_budget = BigInteger.valueOf(100); + proposalAttributes.token = bnUSD; + proposalAttributes.sponsor_address = sponsorPrep.getAddress(); + proposalAttributes.ipfs_link = "https://proposal_1"; + proposalAttributes.milestoneCount = 3; + proposalAttributes.isMilestone = true; + + CPSCoreInterface.MilestonesAttributes milestonesAttributes1 = new CPSCoreInterface.MilestonesAttributes(); + milestonesAttributes1.completionPeriod = 1; + milestonesAttributes1.budget = BigInteger.valueOf(30).multiply(ICX); + milestonesAttributes1.id = 1; + + CPSCoreInterface.MilestonesAttributes milestonesAttributes2 = new CPSCoreInterface.MilestonesAttributes(); + milestonesAttributes2.completionPeriod = 2; + milestonesAttributes2.budget = BigInteger.valueOf(40).multiply(ICX); + milestonesAttributes2.id = 2; + + CPSCoreInterface.MilestonesAttributes milestonesAttributes3 = new CPSCoreInterface.MilestonesAttributes(); + milestonesAttributes3.completionPeriod = 3; + milestonesAttributes3.budget = BigInteger.valueOf(20).multiply(ICX); + milestonesAttributes3.id = 3; + + + CPSCoreInterface.MilestonesAttributes[] milestonesAttributes = new MilestonesAttributes[] + {milestonesAttributes1, milestonesAttributes2, milestonesAttributes3}; + + ((CPSCoreInterfaceScoreClient) testClient.cpsCore).submitProposal(BigInteger.valueOf(50).multiply(ICX), + proposalAttributes, milestonesAttributes); + } + + @DisplayName("proposal with higher fund than in treasury") + @Test + @Order(2) + public void proposalWithHighBudget() { + + + BigInteger treasuryBalance = readerClient.bnUSD.balanceOf(addressMap.get("cpfTreasury")); + BigInteger totalBudget = BigInteger.valueOf(6000); + + assertTrue(treasuryBalance.compareTo(totalBudget.multiply(ICX)) < 0); + + ProposalAttributes proposalAttributes = new ProposalAttributes(); + + proposalAttributes.ipfs_hash = "Test_Proposal_3"; + proposalAttributes.project_title = "Proposal_3"; + proposalAttributes.project_duration = 3; + proposalAttributes.total_budget = totalBudget; + proposalAttributes.token = bnUSD; + proposalAttributes.sponsor_address = sponsorPrep.getAddress(); + proposalAttributes.ipfs_link = "https://proposal_1"; + proposalAttributes.milestoneCount = 3; + proposalAttributes.isMilestone = true; + + CPSCoreInterface.MilestonesAttributes milestonesAttributes1 = new CPSCoreInterface.MilestonesAttributes(); + milestonesAttributes1.completionPeriod = 1; + milestonesAttributes1.budget = BigInteger.valueOf(3000).multiply(ICX); + milestonesAttributes1.id = 1; + + CPSCoreInterface.MilestonesAttributes milestonesAttributes2 = new CPSCoreInterface.MilestonesAttributes(); + milestonesAttributes2.completionPeriod = 2; + milestonesAttributes2.budget = BigInteger.valueOf(2000).multiply(ICX); + milestonesAttributes2.id = 2; + + CPSCoreInterface.MilestonesAttributes milestonesAttributes3 = new CPSCoreInterface.MilestonesAttributes(); + milestonesAttributes3.completionPeriod = 3; + milestonesAttributes3.budget = BigInteger.valueOf(400).multiply(ICX); + milestonesAttributes3.id = 3; + + + CPSCoreInterface.MilestonesAttributes[] milestonesAttributes = new MilestonesAttributes[] + {milestonesAttributes1, milestonesAttributes2, milestonesAttributes3}; + + ((CPSCoreInterfaceScoreClient) testClient.cpsCore).submitProposal(BigInteger.valueOf(50).multiply(ICX), + proposalAttributes, milestonesAttributes); + } + + @DisplayName("proposal rejected by sponsor") + @Test + @Order(2) + public void proposalRejectedBySponsor() { + + + ProposalAttributes proposalAttributes = new ProposalAttributes(); + + proposalAttributes.ipfs_hash = "Test_Proposal_4"; + proposalAttributes.project_title = "Proposal_4"; + proposalAttributes.project_duration = 1; + proposalAttributes.total_budget = BigInteger.valueOf(100); + proposalAttributes.token = bnUSD; + proposalAttributes.sponsor_address = sponsorPrep.getAddress(); + proposalAttributes.ipfs_link = "https://proposal_1"; + proposalAttributes.milestoneCount = 1; + proposalAttributes.isMilestone = true; + + CPSCoreInterface.MilestonesAttributes milestonesAttributes1 = new CPSCoreInterface.MilestonesAttributes(); + milestonesAttributes1.completionPeriod = 1; + milestonesAttributes1.budget = BigInteger.valueOf(90).multiply(ICX); + milestonesAttributes1.id = 1; + + + CPSCoreInterface.MilestonesAttributes[] milestonesAttributes = new MilestonesAttributes[] + {milestonesAttributes1}; + + ((CPSCoreInterfaceScoreClient) testClient.cpsCore).submitProposal(BigInteger.valueOf(50).multiply(ICX), + proposalAttributes, milestonesAttributes); + } + + @DisplayName("proposal which is not sincere") + @Test + @Order(2) + public void proposalWillBeRejected() { + ProposalAttributes proposalAttributes = new ProposalAttributes(); + + proposalAttributes.ipfs_hash = "Test_Proposal_5"; + proposalAttributes.project_title = "Proposal_5"; + proposalAttributes.project_duration = 1; + proposalAttributes.total_budget = BigInteger.valueOf(100); + proposalAttributes.token = bnUSD; + proposalAttributes.sponsor_address = sponsorPrep.getAddress(); + proposalAttributes.ipfs_link = "https://proposal_1"; + proposalAttributes.milestoneCount = 1; + proposalAttributes.isMilestone = true; + + CPSCoreInterface.MilestonesAttributes milestonesAttributes1 = new CPSCoreInterface.MilestonesAttributes(); + milestonesAttributes1.completionPeriod = 1; + milestonesAttributes1.budget = BigInteger.valueOf(90).multiply(ICX); + milestonesAttributes1.id = 1; + + + CPSCoreInterface.MilestonesAttributes[] milestonesAttributes = new MilestonesAttributes[] + {milestonesAttributes1}; + + ((CPSCoreInterfaceScoreClient) testClient.cpsCore).submitProposal(BigInteger.valueOf(50).multiply(ICX), + proposalAttributes, milestonesAttributes); + } + + + @DisplayName("sponsor vote on the proposal") + @Test + @Order(3) + public void sponsorBondsWithProposals() { + + bnUSDMint(sponsorPrep.getAddress(), BigInteger.valueOf(1000).multiply(ICX)); + + BigInteger beforeBalance = readerClient.bnUSD.balanceOf(addressMap.get("cpsCore")); + + byte[] data = createByteArray("sponsorVote", "Test_Proposal_2", ACCEPT, + "Bonding with proposal 2"); + BigInteger sponsorBond = BigInteger.valueOf(15).multiply(ICX); + sponsorPrep.bnUSD.transfer(addressMap.get("cpsCore"), sponsorBond, data); + + BigInteger afterBalance = readerClient.bnUSD.balanceOf(addressMap.get("cpsCore")); + assertEquals(beforeBalance.add(sponsorBond), afterBalance); + + beforeBalance = afterBalance; + data = createByteArray("sponsorVote", "Test_Proposal_3", ACCEPT, + "Bonding with proposal 3"); + sponsorBond = BigInteger.valueOf(900).multiply(ICX); + sponsorPrep.bnUSD.transfer(addressMap.get("cpsCore"), sponsorBond, data); + + afterBalance = readerClient.bnUSD.balanceOf(addressMap.get("cpsCore")); + assertEquals(beforeBalance.add(sponsorBond), afterBalance); + + + beforeBalance = afterBalance; + data = createByteArray("sponsorVote", "Test_Proposal_4", REJECT, + "Rejecting proposal 4"); + sponsorBond = BigInteger.ZERO; + sponsorPrep.bnUSD.transfer(addressMap.get("cpsCore"), sponsorBond, data); + + afterBalance = readerClient.bnUSD.balanceOf(addressMap.get("cpsCore")); + assertEquals(beforeBalance.add(sponsorBond), afterBalance); + + beforeBalance = afterBalance; + data = createByteArray("sponsorVote", "Test_Proposal_5", ACCEPT, + "Bonding with proposal 5"); + sponsorBond = BigInteger.valueOf(15).multiply(ICX); + sponsorPrep.bnUSD.transfer(addressMap.get("cpsCore"), sponsorBond, data); + afterBalance = readerClient.bnUSD.balanceOf(addressMap.get("cpsCore")); + assertEquals(beforeBalance.add(sponsorBond), afterBalance); + + } + + + @DisplayName("voting on proposal conditions") + @Nested + @TestMethodOrder(MethodOrderer.OrderAnnotation.class) + class voteProposal { + + String[] votingProposal = new String[]{"Test_Proposal_2", "Test_Proposal_5", "Test_Proposal_3"}; + + @DisplayName("verify proposal which are active") + @Test + @Order(3) + public void verifyPendingProposal() { + + List proposalKey = getProposalByStatus(PENDING); + + for (String key : votingProposal) { + assertTrue(proposalKey.contains(key)); + } + + } + + @DisplayName("vote on proposal with higher milestone count than project duration") + @Test + @Order(3) + public void voteOnProposalWithMoreMilestone() throws InterruptedException { + updateNextBlock(); + ownerClient.cpsCore.updatePeriod(); + + Thread.sleep(2000); + verifyPeriod("Voting Period"); + + for (CPSClient prepClient : cpsClients.values()) { + voteByPrep(prepClient, "Test_Proposal_2", APPROVE, "Passing Proposal_2", false); + } + } + + @DisplayName("vote on proposal with higher fund than in treasury") + @Test + @Order(4) + public void voteOnProposalWithHighBudget() { + + for (CPSClient prepClient : cpsClients.values()) { + voteByPrep(prepClient, "Test_Proposal_3", APPROVE, "Passing Proposal_3", false); + } + } + + @DisplayName("reject proposal") + @Test + @Order(4) + public void rejectProposal() { + for (CPSClient prepClient : cpsClients.values()) { + + if (prepClient.equals(cpsClients.get(0))) { + voteByPrep(prepClient, "Test_Proposal_5", APPROVE, "Looks good", false); + continue; + } + voteByPrep(prepClient, "Test_Proposal_5", REJECT, "Rejecting Proposal_5", false); + + } + + Map proposalVote = getProposalVote("Test_Proposal_5"); + assertEquals(toInt((String) proposalVote.get(APPROVE_VOTERS)), 1); + assertEquals(toInt((String) proposalVote.get(REJECT_VOTERS)), 6); + assertEquals(toInt((String) proposalVote.get(TOTAL_VOTERS)), 7); + + // one of the prep change their vote to abstain + voteByPrep(cpsClients.get(4), "Test_Proposal_5", ABSTAIN, "Changing vote", true); + + proposalVote = getProposalVote("Test_Proposal_5"); + assertEquals(toInt((String) proposalVote.get(APPROVE_VOTERS)), 1); + assertEquals(toInt((String) proposalVote.get(REJECT_VOTERS)), 5); + assertEquals(toInt((String) proposalVote.get(ABSTAIN_VOTERS)), 1); + assertEquals(toInt((String) proposalVote.get(TOTAL_VOTERS)), 7); + + } + + @DisplayName("vote priority txn except one ") + @Test + @Order(4) + public void votePriority() { + for (CPSClient prepClient : cpsClients.values()) { + if (prepClient.equals(cpsClients.get(2))) { + continue; + } + prepClient.cpsCore.votePriority(votingProposal); + + } + + } + + + @DisplayName("updating to application period") + @Nested + @TestMethodOrder(MethodOrderer.OrderAnnotation.class) + class applicationChecks { + + /* Test_Proposal_2 is approved, Test_Proposal_5 is rejected, Test_Proposal_3 is still in pending + * */ + + @DisplayName("update to application period") + @Test + @Order(5) + public void checkAfterUpdatePeriod() throws InterruptedException { + + Map sponsorBalance = claimableSponsorBond(cpsClients.get(0).getAddress()); + assertEquals(BigInteger.ZERO, sponsorBalance.get(bnUSD)); + + + updateToApplicationPeriod(); + + Map activeProposal = readerClient.cpsCore.getActiveProposalsList(0); + + List> proposalData = (List>) activeProposal.get(DATA); + assertEquals(proposalData.get(0).get(IPFS_HASH), "Test_Proposal_2"); + + List pendingProposal = getProposalByStatus(PENDING); + assertTrue(pendingProposal.contains("Test_Proposal_3")); + + List activeProposals = getProposalByStatus(ACTIVE); + assertTrue(activeProposals.contains("Test_Proposal_2")); + + List rejectedProposals = getProposalByStatus(REJECTED); + assertTrue(rejectedProposals.contains("Test_Proposal_4")); + assertTrue(rejectedProposals.contains("Test_Proposal_5")); + + BigInteger sponsorBondOnProposal5 = BigInteger.valueOf(15).multiply(ICX); + sponsorBalance = claimableSponsorBond(cpsClients.get(0).getAddress()); + assertEquals(sponsorBondOnProposal5, sponsorBalance.get(bnUSD)); + + + List
denyList = readerClient.cpsCore.getDenylist(); + assertTrue(denyList.contains(cpsClients.get(2).getAddress())); + + Address prep = cpsClients.get(2).getAddress(); + Map prepData = loginPrep(prep); + assertEquals(prepData, denyPrepData()); + } + + @DisplayName("prep pays penalty and registers") + @Test + @Order(6) + public void prepPayPenalty() { + CPSClient prep = cpsClients.get(2); + BigInteger penaltyAmount = (BigInteger.TWO.multiply(ICX)).divide(BigInteger.valueOf(100)); + + bnUSDMint(prep.getAddress(), BigInteger.TWO.multiply(ICX)); + + byte[] data = penaltyByteArray("payPrepPenalty"); +// ownerClient.cpsCore.removeDenylistPreps(); + + prep.bnUSD.transfer(addressMap.get("cpsCore"),penaltyAmount,data); + + + Map prepData = loginPrep(prep.getAddress()); + assertEquals(prepData, votingPrepData()); + + +// prep.cpsCore.registerPrep(); +// Map prepData2 = loginPrep(prep.getAddress()); +// +// assertEquals(prepData2, votingPrepData()); + } + + + @DisplayName("submit progress reports") + @Nested + @TestMethodOrder(MethodOrderer.OrderAnnotation.class) + class submitProgressReport { + + @DisplayName("submit progress report with not completed status") + @Order(7) + @Test + public void progressReportNotCompleted() { + + CPSCoreInterface.ProgressReportAttributes progressReportAttributes = createProgressReport("1", + "Test_Proposal_2"); + + assertEquals(getMilestoneStatus("Test_Proposal_2", 1), 0); + + + CPSCoreInterface.MilestoneSubmission submission = new CPSCoreInterface.MilestoneSubmission(); + submission.id = 1; + submission.status = false; + CPSCoreInterface.MilestoneSubmission[] milestoneSubmissions = new CPSCoreInterface.MilestoneSubmission[]{submission}; + + testClient.cpsCore.submitProgressReport(progressReportAttributes, milestoneSubmissions); + + assertEquals(getMilestoneStatus("Test_Proposal_2", 1), MILESTONE_REPORT_NOT_COMPLETED); + + System.out.println("-----boom----" + readerClient.cpsCore.getMilestonesReport("Test_Proposal_2", 1)); + + } + + @DisplayName("vote progress reports and proposal") + @Nested + @TestMethodOrder(MethodOrderer.OrderAnnotation.class) + class voteOnProposalAndPR { + + @Test + @Order(8) + public void toVotingPeriod() throws InterruptedException { + // minting bnUSD on cpfTreasury to pass proposal 3 + bnUSDMint(addressMap.get("cpfTreasury"), BigInteger.valueOf(5000).multiply(ICX)); + + updateNextBlock(); + ownerClient.cpsCore.updatePeriod(); + } + + @DisplayName("vote on PR and proposal 3") + @Test + @Order(9) + public void votePRandProposal() { + for (CPSClient prepClient : cpsClients.values()) { + // proposal voting + voteByPrep(prepClient, "Test_Proposal_3", APPROVE, "Voting Again", false); + prepClient.cpsCore.votePriority(new String[]{"Test_Proposal_3"}); + + + MilestoneVoteAttributes[] voteAttributes = new MilestoneVoteAttributes[]{vote(1, APPROVE)}; + prepClient.cpsCore.voteProgressReport("Test_Proposal_2_Report_Proposal_1", + "Seems right ", + voteAttributes, null, false); + + } + + Map proposalVote = getProposalVote("Test_Proposal_3"); + assertEquals(toInt((String) proposalVote.get(APPROVE_VOTERS)), 7); + assertEquals(toInt((String) proposalVote.get(REJECT_VOTERS)), 0); + assertEquals(toInt((String) proposalVote.get(TOTAL_VOTERS)), 7); + + Map milestoneVoteResult = getMilestoneReport("Test_Proposal_2_Report_Proposal_1", 1); + assertEquals(toInt((String) milestoneVoteResult.get(APPROVE_VOTERS)), 7); + assertEquals(toInt((String) milestoneVoteResult.get(REJECT_VOTERS)), 0); + +// MilestoneVoteAttributes[] voteAttributes = new MilestoneVoteAttributes[]{vote(1,REJECT)}; + + // one of the prep changes their vote on the progress report +// cpsClients.get(0).cpsCore.voteProgressReport("Test_Proposal_2_Report_Proposal_1", +// "Changing vote ", +// voteAttributes,null,true); +// +// milestoneVoteResult = getMilestoneReport("Test_Proposal_2_Report_Proposal_1", 1); +// assertEquals(toInt((String) milestoneVoteResult.get(APPROVE_VOTERS)),6); +// assertEquals(toInt((String) milestoneVoteResult.get(REJECT_VOTERS)),1); + } + + + @DisplayName("submit progress report for proposal 2 and 3 ") + @Nested + @TestMethodOrder(MethodOrderer.OrderAnnotation.class) + class SecondProgressReport { + + @DisplayName("update to application period and assert values") + @Order(10) + @Test + public void checksInApplicationPeriod() throws InterruptedException { + + String proposal2 = "Test_Proposal_2"; + Map proposalDetails = getProposalDetails(proposal2); + assertEquals(toInt((String) proposalDetails.get(PROJECT_DURATION)), 2); + + Map milestoneDetails = getMilestonesReport(proposal2, 1); + assertEquals(milestoneDetails.get(EXTENSION_FLAG), "0x0"); + assertEquals(toInt((String) milestoneDetails.get(COMPLETION_PERIOD)), 1); + + + updateToApplicationPeriod(); + verifyPeriod(APPLICATION_PERIOD); + + // milestone completion period and project duration increases + milestoneDetails = getMilestonesReport(proposal2, 1); + assertEquals(milestoneDetails.get(EXTENSION_FLAG), "0x1"); + assertEquals(toInt((String) milestoneDetails.get(COMPLETION_PERIOD)), 2); + + proposalDetails = getProposalDetails(proposal2); + assertEquals(toInt((String) proposalDetails.get(PROJECT_DURATION)), 3); + + List activeProposals = getProposalByStatus(ACTIVE); + + assertTrue(activeProposals.contains("Test_Proposal_2")); + assertTrue(activeProposals.contains("Test_Proposal_3")); + + } + + @DisplayName("submit progress report with completed status ") + @Order(11) + @Test + public void progressReportCompleted() { + CPSCoreInterface.MilestoneSubmission submission = new CPSCoreInterface.MilestoneSubmission(); + submission.id = 1; + submission.status = true; + CPSCoreInterface.MilestoneSubmission[] milestoneSubmissions = new CPSCoreInterface.MilestoneSubmission[]{submission}; + + // for proposal 2 + String proposal2 = "Test_Proposal_2"; + assertEquals(getMilestoneStatus("Test_Proposal_2", 1), MILESTONE_REPORT_NOT_COMPLETED); + + CPSCoreInterface.ProgressReportAttributes progressReportAttributes = createProgressReport("2", proposal2); + + testClient.cpsCore.submitProgressReport(progressReportAttributes, milestoneSubmissions); + + assertEquals(getMilestoneStatus("Test_Proposal_2", 1), MILESTONE_REPORT_COMPLETED); + + // for proposal 3 + String proposal3 = "Test_Proposal_3"; + assertEquals(getMilestoneStatus("Test_Proposal_3", 1), 0); + + progressReportAttributes = createProgressReport("1", proposal3); + + testClient.cpsCore.submitProgressReport(progressReportAttributes, milestoneSubmissions); + + assertEquals(getMilestoneStatus("Test_Proposal_3", 1), MILESTONE_REPORT_COMPLETED); + + } + + @DisplayName("vote progress report for proposal 2 and 3. ") + @Nested + @TestMethodOrder(MethodOrderer.OrderAnnotation.class) + class voteSecondReport { + /* Progress report for proposal 2 will be accepted and proposal 3 will be rejected */ + @DisplayName("to voting period") + @Order(12) + @Test + public void updateToVotingPeriod() throws InterruptedException { + updateNextBlock(); + ownerClient.cpsCore.updatePeriod(); + verifyPeriod(VOTING_PERIOD); + // vote on progress report 2 with acceptance + } + + @DisplayName("vote on progress reports") + @Order(12) + @Test + public void voteProgressReport() { + String reportForPropsoal2 = "Test_Proposal_2_Report_Proposal_2"; + String reportForPropsoal3 = "Test_Proposal_3_Report_Proposal_1"; + + + MilestoneVoteAttributes[] voteAttributes = new MilestoneVoteAttributes[]{vote(1, APPROVE)}; + for (CPSClient prepClient : cpsClients.values()) { + prepClient.cpsCore.voteProgressReport(reportForPropsoal2, + "Seems right ", + voteAttributes, null, false); + + prepClient.cpsCore.voteProgressReport(reportForPropsoal3, + "Looks legit ", + voteAttributes, null, false); + } + + MilestoneVoteAttributes[] rejectVoteAttributes = new MilestoneVoteAttributes[]{vote(1, REJECT)}; + cpsClients.get(0).cpsCore.voteProgressReport(reportForPropsoal3, "I reject", + rejectVoteAttributes, null, true); + + // verify the votes + Map milestoneVoteResult = getMilestoneReport(reportForPropsoal2, 1); + assertEquals(toInt((String) milestoneVoteResult.get(APPROVE_VOTERS)), 7); + assertEquals(toInt((String) milestoneVoteResult.get(REJECT_VOTERS)), 0); + + milestoneVoteResult = getMilestoneReport(reportForPropsoal3, 1); + assertEquals(toInt((String) milestoneVoteResult.get(APPROVE_VOTERS)), 6); + assertEquals(toInt((String) milestoneVoteResult.get(REJECT_VOTERS)), 1); + + // vote on progress report 2 with acceptance + } + + @DisplayName("submit third progress report ") + @Nested + @TestMethodOrder(MethodOrderer.OrderAnnotation.class) + class thirdReport { + + @DisplayName("update to application period and assert values") + @Order(13) + @Test + public void checks() throws InterruptedException { + + Map contributorProject2 = getContributorFunds(testClient.getAddress()); + List> contributorData2 = (List>) contributorProject2.get("data"); + + BigInteger milestoneBudget = toBigInt((String) contributorData2.get(0).get("installment_amount")); + BigInteger installPaidTillDate = toBigInt((String) contributorData2.get(0).get("total_installment_paid")); + + + updateToApplicationPeriod(); + verifyPeriod(APPLICATION_PERIOD); + + String proposal2 = "Test_Proposal_2"; + int milestoneStatus = getMilestoneStatus(proposal2, 1); + assertEquals(milestoneStatus, MILESTONE_REPORT_APPROVED); + + Map milestoneDetails = getMilestonesReport(proposal2, 1); + System.out.println("milestone details " + milestoneDetails); + + + Map proposalDetails = getProposalDetails(proposal2); + assertEquals(toInt((String) proposalDetails.get(APPROVED_REPORTS)), 1); + + List activeProposals = getProposalByStatus(ACTIVE); + assertTrue(activeProposals.contains(proposal2)); + + // check contributor's fund + Map contributorProject = getContributorFunds(testClient.getAddress()); + List> contributorData = (List>) contributorProject.get("data"); + BigInteger installmentPaidNow = toBigInt((String) contributorData.get(0).get("total_installment_paid")); + assertEquals(installmentPaidNow, installPaidTillDate.add(milestoneBudget)); + + + String proposal3 = "Test_Proposal_3"; + milestoneStatus = getMilestoneStatus(proposal3, 1); + assertEquals(milestoneStatus, MILESTONE_REPORT_REJECTED); + + + proposalDetails = getProposalDetails(proposal3); + assertEquals(toInt((String) proposalDetails.get(APPROVED_REPORTS)), 0); + + List pausedProposal = getProposalByStatus(PAUSED); + + assertTrue(pausedProposal.contains("Test_Proposal_3")); + + } + + @DisplayName("one of the milestone is rejected on this progress report") + @Order(14) + @Test + public void submitProgressReport() { + + List> activeProposal = readerClient.cpsCore.getActiveProposals(testClient.getAddress()); + System.out.println("active proposal " + activeProposal); + assertEquals("Test_Proposal_2", activeProposal.get(1).get("ipfs_hash")); + assertEquals("0x0", activeProposal.get(1).get("new_progress_report")); + assertEquals("0x1", activeProposal.get(1).get("last_progress_report")); + + // submit progress report for proposal 2 + CPSCoreInterface.ProgressReportAttributes progressReportAttributes = createProgressReport("3", + "Test_Proposal_2"); + + assertEquals(getMilestoneStatus("Test_Proposal_2", 2), 0); + assertEquals(getMilestoneStatus("Test_Proposal_2", 3), 0); + + CPSCoreInterface.MilestoneSubmission submission2 = new CPSCoreInterface.MilestoneSubmission(); + submission2.id = 2; + submission2.status = true; + + CPSCoreInterface.MilestoneSubmission submission3 = new CPSCoreInterface.MilestoneSubmission(); + submission3.id = 3; + submission3.status = true; + CPSCoreInterface.MilestoneSubmission[] milestoneSubmissions = new CPSCoreInterface.MilestoneSubmission[]{ + submission2, submission3 + }; + + testClient.cpsCore.submitProgressReport(progressReportAttributes, milestoneSubmissions); + + + Map progressReport = getProgressReportDetails("Test_Proposal_2_Report_Proposal_3"); + assertEquals(progressReport.get("milestone_submitted_count"), "0x2"); + + assertEquals(getMilestoneStatus("Test_Proposal_2", 2), MILESTONE_REPORT_COMPLETED); + assertEquals(getMilestoneStatus("Test_Proposal_2", 3), MILESTONE_REPORT_COMPLETED); + + } + + @DisplayName("submit progress report with all milestones of a project") + @Order(14) + @Test + public void withAllMilestones() { + + CPSCoreInterface.ProgressReportAttributes progressReportAttributes = createProgressReport("2", + "Test_Proposal_3"); + + assertEquals(getMilestoneStatus("Test_Proposal_3", 2), 0); + + CPSCoreInterface.MilestoneSubmission submission2 = new CPSCoreInterface.MilestoneSubmission(); + submission2.id = 2; + submission2.status = true; + + CPSCoreInterface.MilestoneSubmission submission3 = new CPSCoreInterface.MilestoneSubmission(); + submission3.id = 3; + submission3.status = true; + CPSCoreInterface.MilestoneSubmission[] milestoneSubmissions = new CPSCoreInterface.MilestoneSubmission[]{ + submission2, submission3 + }; + + testClient.cpsCore.submitProgressReport(progressReportAttributes, milestoneSubmissions); + + + assertEquals(getMilestoneStatus("Test_Proposal_3", 2), MILESTONE_REPORT_COMPLETED); + + } + + @DisplayName("vote on third progress report. ") + @Nested + @TestMethodOrder(MethodOrderer.OrderAnnotation.class) + class voteReport { + @DisplayName("to voting period") + @Order(15) + @Test + public void updateToVotingPeriod() throws InterruptedException { + updateNextBlock(); + ownerClient.cpsCore.updatePeriod(); + verifyPeriod(VOTING_PERIOD); + // vote on progress report 2 with acceptance + } + + @DisplayName("vote on progress reports") + @Order(16) + @Test + public void voteProgressReport() { + + String reportForPropsoal2 = "Test_Proposal_2_Report_Proposal_3"; + String reportForPropsoal3 = "Test_Proposal_3_Report_Proposal_2"; + + + MilestoneVoteAttributes[] voteAttributes = new MilestoneVoteAttributes[]{ + vote(2, APPROVE), vote(3, REJECT)}; + for (CPSClient prepClient : cpsClients.values()) { + prepClient.cpsCore.voteProgressReport(reportForPropsoal2, + "Progress not satisfactory ", + voteAttributes, null, false); + + prepClient.cpsCore.voteProgressReport(reportForPropsoal3, + "no ", + voteAttributes, null, false); + } + + // verify the votes + Map milestoneVoteResult = getMilestoneReport(reportForPropsoal2, 2); + assertEquals(toInt((String) milestoneVoteResult.get(APPROVE_VOTERS)), 7); + assertEquals(toInt((String) milestoneVoteResult.get(REJECT_VOTERS)), 0); + + milestoneVoteResult = getMilestoneReport(reportForPropsoal2, 3); + assertEquals(toInt((String) milestoneVoteResult.get(APPROVE_VOTERS)), 0); + assertEquals(toInt((String) milestoneVoteResult.get(REJECT_VOTERS)), 7); + + milestoneVoteResult = getMilestoneReport(reportForPropsoal3, 2); + assertEquals(toInt((String) milestoneVoteResult.get(APPROVE_VOTERS)), 7); + assertEquals(toInt((String) milestoneVoteResult.get(REJECT_VOTERS)), 0); + + } + + + @DisplayName("submit final progress report of both proposals. ") + @Nested + @TestMethodOrder(MethodOrderer.OrderAnnotation.class) + class finalReports { + + @DisplayName("update to application period and assert values") + @Order(17) + @Test + public void checksInApplicationPeriod() throws InterruptedException { + + Map contributorProject2 = getContributorFunds(testClient.getAddress()); + List> contributorData2 = (List>) contributorProject2.get("data"); + + BigInteger installPaidTillDate = toBigInt((String) contributorData2.get(0).get("total_installment_paid")); + + + updateToApplicationPeriod(); + verifyPeriod(APPLICATION_PERIOD); + + String proposal2 = "Test_Proposal_2"; + int milestoneStatus = getMilestoneStatus(proposal2, 2); + assertEquals(milestoneStatus, MILESTONE_REPORT_APPROVED); + + milestoneStatus = getMilestoneStatus(proposal2, 3); + assertEquals(milestoneStatus, MILESTONE_REPORT_REJECTED); + + Map milestoneDetails = getMilestonesReport(proposal2, 2); + BigInteger milestoneBudget = toBigInt((String) milestoneDetails.get(BUDGET)); + + + Map proposalDetails = getProposalDetails(proposal2); + assertEquals(toInt((String) proposalDetails.get(APPROVED_REPORTS)), 2); + + // proposal 2 submitted the last progress report and the milestone got rejected + // so proposal 2 will be in paused state + List pausedProposal = getProposalByStatus(PAUSED); + assertTrue(pausedProposal.contains(proposal2)); + + // check contributor's fund + Map contributorProject = getContributorFunds(testClient.getAddress()); + List> contributorData = (List>) contributorProject.get("data"); + BigInteger installmentPaidNow = toBigInt((String) contributorData.get(0).get("total_installment_paid")); + assertEquals(installmentPaidNow, installPaidTillDate.add(milestoneBudget)); + + + String proposal3 = "Test_Proposal_3"; + + milestoneStatus = getMilestoneStatus(proposal3, 2); + assertEquals(milestoneStatus, MILESTONE_REPORT_APPROVED); + + milestoneStatus = getMilestoneStatus(proposal3, 3); + assertEquals(milestoneStatus, MILESTONE_REPORT_REJECTED); + + + proposalDetails = getProposalDetails(proposal3); + assertEquals(toInt((String) proposalDetails.get(APPROVED_REPORTS)), 1); + + + List activeProposals = getProposalByStatus(ACTIVE); + assertTrue(activeProposals.contains("Test_Proposal_3")); + + } + + @DisplayName("report for proposal 2 ") + @Order(18) + @Test + public void finalReport() { + // proposal 2 ko milestone 2 + // proposal 3 ko milestone 1 and 3 + + CPSCoreInterface.ProgressReportAttributes progressReportAttributes = createProgressReport("4", + "Test_Proposal_2"); + + assertEquals(getMilestoneStatus("Test_Proposal_2", 3), MILESTONE_REPORT_REJECTED); + + CPSCoreInterface.MilestoneSubmission submission3 = new CPSCoreInterface.MilestoneSubmission(); + submission3.id = 3; + submission3.status = true; + CPSCoreInterface.MilestoneSubmission[] milestoneSubmissions = new CPSCoreInterface.MilestoneSubmission[]{ + submission3 + }; + + testClient.cpsCore.submitProgressReport(progressReportAttributes, milestoneSubmissions); + + + Map progressReport = getProgressReportDetails("Test_Proposal_2_Report_Proposal_4"); + + + } + + @DisplayName("report for proposal 3 ") + @Order(18) + @Test + public void finalReport2() { + + List> activeProposal = readerClient.cpsCore.getActiveProposals(testClient.getAddress()); + System.out.println("the milestone deadlines are " + activeProposal.get(1).get("milestoneDeadlines")); + CPSCoreInterface.ProgressReportAttributes progressReportAttributes = createProgressReport("3", + "Test_Proposal_3"); + + assertEquals(getMilestoneStatus("Test_Proposal_3", 1), MILESTONE_REPORT_REJECTED); + assertEquals(getMilestoneStatus("Test_Proposal_3", 3), MILESTONE_REPORT_REJECTED); + + CPSCoreInterface.MilestoneSubmission submission1 = new CPSCoreInterface.MilestoneSubmission(); + submission1.id = 1; + submission1.status = true; + + CPSCoreInterface.MilestoneSubmission submission3 = new CPSCoreInterface.MilestoneSubmission(); + submission3.id = 3; + submission3.status = true; + CPSCoreInterface.MilestoneSubmission[] milestoneSubmissions = new CPSCoreInterface.MilestoneSubmission[]{ + submission1, submission3 + }; + + testClient.cpsCore.submitProgressReport(progressReportAttributes, milestoneSubmissions); + + + Map progressReport = getProgressReportDetails("Test_Proposal_3_Report_Proposal_3"); + + assertEquals(getMilestoneStatus("Test_Proposal_3", 1), MILESTONE_REPORT_COMPLETED); + + + } + + @DisplayName("vote on reports of proposals ") + @Nested + @TestMethodOrder(MethodOrderer.OrderAnnotation.class) + class voteFinalReport { + @DisplayName("update to voting period") + @Order(19) + @Test + public void updateToVotingPeriod() throws InterruptedException { + updateNextBlock(); + ownerClient.cpsCore.updatePeriod(); + verifyPeriod(VOTING_PERIOD); + } + + @DisplayName("vote on final report") + @Order(20) + @Test + public void voteFinalReports() { + // proposal 3 reject + + String reportForPropsoal2 = "Test_Proposal_2_Report_Proposal_4"; + String reportForPropsoal3 = "Test_Proposal_3_Report_Proposal_3"; + + + MilestoneVoteAttributes[] voteForProposal2 = new MilestoneVoteAttributes[]{ + vote(3, APPROVE)}; + + MilestoneVoteAttributes[] voteForProposal3 = new MilestoneVoteAttributes[]{ + vote(1, REJECT), vote(3, APPROVE)}; + for (CPSClient prepClient : cpsClients.values()) { + prepClient.cpsCore.voteProgressReport(reportForPropsoal2, + "Looks good ", + voteForProposal2, null, false); + + prepClient.cpsCore.voteProgressReport(reportForPropsoal3, + "can only approve one of them ", + voteForProposal3, null, false); + } + + // verify the votes + Map milestoneVoteResult = getMilestoneReport(reportForPropsoal2, 3); + assertEquals(toInt((String) milestoneVoteResult.get(APPROVE_VOTERS)), 7); + assertEquals(toInt((String) milestoneVoteResult.get(REJECT_VOTERS)), 0); + + milestoneVoteResult = getMilestoneReport(reportForPropsoal3, 1); + assertEquals(toInt((String) milestoneVoteResult.get(APPROVE_VOTERS)), 0); + assertEquals(toInt((String) milestoneVoteResult.get(REJECT_VOTERS)), 7); + + milestoneVoteResult = getMilestoneReport(reportForPropsoal3, 3); + assertEquals(toInt((String) milestoneVoteResult.get(APPROVE_VOTERS)), 7); + assertEquals(toInt((String) milestoneVoteResult.get(REJECT_VOTERS)), 0); + + } + + @DisplayName("completeAllProject") + @Order(21) + @Test + public void completionOfProjects() throws InterruptedException { + + Map claimableBond = claimableSponsorBond( + cpsClients.get(0).getAddress()); + BigInteger sponsorBondBefore = claimableBond.get(bnUSD); + System.out.println("sponsorBo" + sponsorBondBefore); + + updateToApplicationPeriod(); + + // check the contributors and sponsor's balance + + Map milestoneReport = getMilestonesReport("Test_Proposal_3", 1); + assertEquals(milestoneReport.get("extensionFlag"), "0x0"); + assertEquals(toInt((String) milestoneReport.get("status")), MILESTONE_REPORT_REJECTED); + + milestoneReport = getMilestonesReport("Test_Proposal_3", 3); + assertEquals(milestoneReport.get("extensionFlag"), "0x0"); + assertEquals(toInt((String) milestoneReport.get("status")), MILESTONE_REPORT_APPROVED); + + List activeProposals = getProposalByStatus(ACTIVE); + assertTrue(activeProposals.contains("Test_Proposal_3")); + + List completedProposals = getProposalByStatus(COMPLETED); + assertTrue(completedProposals.contains("Test_Proposal_2")); + + // check the sponsor bond is return + Map sponsorBondAfter = claimableSponsorBond( + cpsClients.get(0).getAddress()); + Map proposalDetail = getProposalDetails("Test_Proposal_2"); + BigInteger sponsorBondAmount = toBigInt((String) proposalDetail.get(SPONSOR_DEPOSIT_AMOUNT)); + assertEquals(sponsorBondAmount.add(sponsorBondBefore), sponsorBondAfter.get(bnUSD)); + } + } + + + } + } + + + } + } + + + } + + } + } + } + } + + + } + + private Map getMilestonesReport(String ipfsHash, int id) { + return readerClient.cpsCore.getMilestonesReport(ipfsHash, id); + } + + private Map claimableSponsorBond(Address prepAddress) { + return readerClient.cpsCore.checkClaimableSponsorBond(prepAddress); + } + + private List getProposalByStatus(String status) { + return readerClient.cpsCore.getProposalsKeysByStatus(status); + } + + + private void verifyPeriod(String period) { + Map periodStatus = getPeriodStatus(); + assertEquals(periodStatus.get(PERIOD_NAME), period); + } + + + private MilestoneVoteAttributes vote(int id, String vote) { + + MilestoneVoteAttributes milestoneVoteAttributes = new MilestoneVoteAttributes(); + milestoneVoteAttributes.id = id; + milestoneVoteAttributes.vote = vote; + return milestoneVoteAttributes; + } + + + private void updateToApplicationPeriod() throws InterruptedException { + updateNextBlock(); + ownerClient.cpsCore.updatePeriod(); + ownerClient.cpsCore.updatePeriod(); + ownerClient.cpsCore.updatePeriod(); + ownerClient.cpsCore.updatePeriod(); + } + + + private BigInteger toBigInt(String inputString) { + return new BigInteger(inputString.substring(2), 16); + } + + private Integer toInt(String inputString) { + return Integer.parseInt(inputString.substring(2)); + } + + + private void voteByPrep(CPSClient caller, String ipfsKey, String vote, String voteReason, + @Optional boolean voteChange) { + + caller.cpsCore.voteProposal(ipfsKey, vote, voteReason, voteChange); + } + + private Map getProposalDetails(String ipfsHash) { + return readerClient.cpsCore.getProposalDetailsByHash(ipfsHash); + } + + private Map getProposalVote(String ipfsHash) { + return readerClient.cpsCore.getVoteResult(ipfsHash); + } + + private void updateNextBlock() throws InterruptedException { + ownerClient.cpsCore.updateNextBlock(1); + Thread.sleep(2000); + } + + private byte[] createByteArray(String methodName, String ipfsHash, String vote, String voteReason) { + + JsonObject internalParameters = new JsonObject() + .add("ipfs_hash", String.valueOf(ipfsHash)) + .add("vote", String.valueOf(vote)) + .add("vote_reason", String.valueOf(voteReason)); + + + JsonObject jsonData = new JsonObject() + .add("method", methodName) + .add("params", internalParameters); + + return jsonData.toString().getBytes(); + } + + private byte[] penaltyByteArray(String methodName) { + + JsonObject jsonData = new JsonObject() + .add("method", methodName) + .add("params", new JsonObject()); + + + return jsonData.toString().getBytes(); + } + + private void bnUSDMint(Address to, BigInteger amount) { + ownerClient.bnUSD.mintTo(to, amount); + } + + + private Map getPeriodStatus() { + return readerClient.cpsCore.getPeriodStatus(); + } + + private Map loginPrep(Address prepAddress) { + return readerClient.cpsCore.loginPrep(prepAddress); + } + + private Map unregisteredPrepData() { + return Map.of(IS_PREP, BigInteger.ONE, + IS_REGISTERED, BigInteger.ZERO, + PAY_PENALTY, BigInteger.ZERO, + VOTING_PREP, BigInteger.ZERO); + } + + + private Map normalPrepData(){ + return Map.of(IS_PREP, BigInteger.ONE, + IS_REGISTERED, BigInteger.ZERO, + PAY_PENALTY, BigInteger.ZERO, + VOTING_PREP, BigInteger.ZERO); + } + + private Map votingPrepData(){ + return Map.of(IS_PREP, BigInteger.ONE, + IS_REGISTERED, BigInteger.ONE, + PAY_PENALTY, BigInteger.ZERO, + VOTING_PREP, BigInteger.ONE); + } + + private Map registerPrepData() { + return Map.of(IS_PREP, BigInteger.ONE, + IS_REGISTERED, BigInteger.ONE, + PAY_PENALTY, BigInteger.ZERO, + VOTING_PREP, BigInteger.ZERO); + } + + private Map denyPrepData() { + return Map.of(IS_PREP, BigInteger.ONE, + IS_REGISTERED, BigInteger.ZERO, + PAY_PENALTY, BigInteger.ONE, + PENALTY_AMOUNT1, (BigInteger.TWO.multiply(ICX)).divide(BigInteger.valueOf(100)), + VOTING_PREP, BigInteger.ZERO); + } + + +} 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 482c270f..6e5db456 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 @@ -62,33 +62,8 @@ public CPSCore(@Optional BigInteger bondValue, @Optional BigInteger applicationP sponsorBondPercentage.set(bondValue); this.period.set(APPLICATION_PERIOD, applicationPeriod); this.period.set(VOTING_PERIOD, TOTAL_PERIOD.subtract(applicationPeriod)); + admins.add(Context.getOwner()); } - - // Fix for ICON Dashboard Proposal not being able to submit progress report being rejected - - String progressReport = "bafybeic4jhoowlgeyewjqkcpgbm3fs7mgtxzhqd5kbguihoehm4cwwwzcq"; - String proposalKey = "bafybeidoxysex3jloigzi4pvdeqgy35a4nykd46w66pobxrkephpawyjoi"; - - String proposalPrefix = proposalPrefix(proposalKey); - String progressReportPrefix = progressReportPrefix(progressReport); - - ProposalDataDb.submitProgressReport.at(proposalPrefix).set(Boolean.FALSE); - - ProgressReportDataDb.status.at(progressReportPrefix).set(PROGRESS_REPORT_REJECTED); - ProgressReportDataDb.timestamp.at(progressReportPrefix).set(BigInteger.valueOf(1706244342109937L)); - Status status = new Status(); - status.progressReportStatus.get(PROGRESS_REPORT_REJECTED).add(progressReport); - - // End of fix - - // Migrate sponsor bond from Techiast- to Techiast - Address oldAddr = Address.fromString("hxdc4b3fb5b47d6c14c7f9a0bac8eea9f3f48d3288"); - Address address = Address.fromString("hxfe0256b41f1db0186f9e6cbebf8c71cf006d5d17"); - DictDB userAmounts = sponsorBondReturn.at(oldAddr.toString()); - - BigInteger bnUSDAmount = userAmounts.getOrDefault(bnUSD, BigInteger.ZERO); - sponsorBondReturn.at(address.toString()).set(bnUSD, bnUSDAmount); - } @Override @@ -225,7 +200,7 @@ public void toggleBudgetAdjustmentFeature() { @External(readonly = true) public boolean getBudgetAdjustmentFeature() { SetterGetter setterGetter = new SetterGetter(); - return setterGetter.budgetAdjustment.getOrDefault(true); + return setterGetter.budgetAdjustment.getOrDefault(false); } @External @@ -365,15 +340,29 @@ private List
getPrepsAddress() { } private String getPrepName(Address address) { - return (String) getPRepInfo(address).get("name"); + if (getCouncilFlag() && getCouncilManagers().contains(address)) { + int index = getCouncilManagers().indexOf(address); + return "Council Manager " + (index + 1); + } + else { + return (String) getPRepInfo(address).get("name"); + } } private BigInteger getStake(Address address) { - return (BigInteger) getPRepInfo(address).get("power"); + if (getCouncilFlag() && getCouncilManagers().contains(address)) { + return EXA.multiply(BigInteger.ONE); + } else { + return (BigInteger) getPRepInfo(address).get("power"); + } } private BigInteger getDelegation(Address address) { - return delegationSnapshot.get(address); + if (getCouncilFlag() && getCouncilManagers().contains(address)) { + return EXA.multiply(BigInteger.ONE); + } else { + return delegationSnapshot.get(address); + } } private void setPreps() { @@ -441,7 +430,8 @@ private BigInteger getPenaltyAmount(Address address) { @Override @External(readonly = true) public boolean checkPriorityVoting(Address _prep) { - int count = (int) getActiveProposalsList(0).get(COUNT); + Status status = new Status(); + int count = status.pending.size(); if (count > 0) { return ArrayDBUtils.containsInArrayDb(_prep, priorityVotedPreps); } @@ -484,7 +474,11 @@ public void votePriority(String[] _proposals) { Context.require(period.periodName.get().equals(VOTING_PERIOD), TAG + ": Voting can only be done in Voting Period."); Address caller = Context.getCaller(); PReps pReps = new PReps(); - Context.require(ArrayDBUtils.containsInArrayDb(caller, pReps.validPreps), "Voting can only be done by registered P-Reps"); + if (getCouncilFlag()) { + Context.require(getCouncilManagers().contains(caller), "Voting can only be done by Council Managers."); + } else { + Context.require(ArrayDBUtils.containsInArrayDb(caller, pReps.validPreps), "Voting can only be done by registered P-Reps"); + } Context.require(!checkPriorityVoting(caller), "Already voted for Priority Ranking."); priorityVotedPreps.add(caller); @@ -541,11 +535,17 @@ public Map loginPrep(Address address) { allPreps = ArrayDBUtils.arrayDBtoList(pReps.validPreps); } + loginData.put(IS_COUNCIL_MANAGER, BigInteger.ZERO); 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 (getCouncilFlag() && getCouncilManagers().contains(address)) { + loginData.put(IS_COUNCIL_MANAGER, BigInteger.ONE); + loginData.put(VOTING_PREP, BigInteger.ONE); + } + if (allPreps.contains(address)) { loginData.put(IS_PREP, BigInteger.ONE); if (ArrayDBUtils.containsInArrayDb(address, pReps.denylist)) { @@ -553,12 +553,10 @@ public Map loginPrep(Address address) { loginData.put(PENALTY_AMOUNT1, getPenaltyAmount(address)); } else if (ArrayDBUtils.containsInArrayDb(address, pReps.registeredPreps)) { loginData.put(IS_REGISTERED, BigInteger.ONE); - - if (ArrayDBUtils.containsInArrayDb(address, pReps.validPreps)) { + if (!getCouncilFlag() && ArrayDBUtils.containsInArrayDb(address, pReps.validPreps)) { loginData.put(VOTING_PREP, BigInteger.ONE); } } - } return loginData; } @@ -576,7 +574,6 @@ public List
getAdmins() { @External(readonly = true) public Map getRemainingFund() { SetterGetter setterGetter = new SetterGetter(); - //noinspection unchecked return callScore(Map.class, setterGetter.cpfScore.get(), "getTotalFunds"); } @@ -602,6 +599,7 @@ public List> getPReps() { public List
getDenylist() { List
denyList = new ArrayList<>(); PReps pReps = new PReps(); + for (int i = 0; i < pReps.denylist.size(); i++) { denyList.add(pReps.denylist.get(i)); } @@ -682,6 +680,7 @@ public void submitProposal(ProposalAttributes proposals, MilestonesAttributes[] String ipfsHashPrefix = proposalPrefix(ipfsHash); addDataToProposalDB(proposals, ipfsHashPrefix); + councilFlag.at(ipfsHashPrefix).set(getCouncilFlag()); BigInteger initialPaymentPercentage = callScore(BigInteger.class, getCpsTreasuryScore(), "getOnsetPayment"); BigInteger totalBudget = proposals.total_budget.multiply(EXA); @@ -723,7 +722,15 @@ public void voteProposal(String ipfsKey, String vote, String voteReason, @Option TAG + ": Proposals can be voted only on Voting Period."); Address caller = Context.getCaller(); PReps pReps = new PReps(); - Context.require(ArrayDBUtils.containsInArrayDb(caller, pReps.validPreps), + + List
callLocation; + if (getCouncilFlag()) { + callLocation = getCouncilManagers(); + } else { + callLocation = ArrayDBUtils.arrayDBtoList(pReps.validPreps); + } + + Context.require(ArrayDBUtils.containsInList(caller, callLocation), TAG + ": Voting can only be done by registered P-Reps."); Context.require(List.of(APPROVE, REJECT, ABSTAIN).contains(vote), TAG + ": Vote should be either _approve, _reject or _abstain"); @@ -751,12 +758,16 @@ public void voteProposal(String ipfsKey, String vote, String voteReason, @Option 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)); + if (getCouncilFlag()) { + ProposalDataDb.totalVotes.at(proposalPrefix).set(EXA.multiply(BigInteger.valueOf(getCouncilManagers().size()))); + ProposalDataDb.totalVoters.at(proposalPrefix).set(getCouncilManagers().size()); + } else { + ProposalDataDb.totalVotes.at(proposalPrefix).set(totalDelegationSnapshot.getOrDefault(BigInteger.ZERO)); + ProposalDataDb.totalVoters.at(proposalPrefix).set(pReps.validPreps.size()); + } } DictDB votersIndexDb = votersListIndex.at(proposalPrefix).at(caller); - if (!voteChange) { ProposalDataDb.votersList.at(proposalPrefix).add(caller); votersIndexDb.set(INDEX, ProposalDataDb.votersList.at(proposalPrefix).size()); @@ -803,20 +814,26 @@ public void voteProposal(String ipfsKey, String vote, String voteReason, @Option votersIndexDb.set(VOTE, ABSTAIN_); ProposalDataDb.abstainedVotes.at(proposalPrefix).set(abstainedVotes.add(voterStake)); } + + if (hasTwoThirdsMajority(ipfsKey, 0)) { + ProposalDataDb.majorityFlag.at(proposalPrefix).set(true); + } + + VotedSuccessfully(caller, "Proposal Vote for " + proposalDetails.get(PROJECT_TITLE) + " Successful."); swapBNUsdToken(); } private List getMilestoneDeadline(String ipfsHash) { - String ipfsHAshPRefix = proposalPrefix(ipfsHash); - ArrayDB milestoneIDs = milestoneIds.at(ipfsHAshPRefix); + String proposalPrefix = proposalPrefix(ipfsHash); + ArrayDB milestoneIDs = milestoneIds.at(proposalPrefix); 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 proposalTotalPeriod = proposalPeriod.at(proposalPrefix).getOrDefault(0); int completionPeriod = MilestoneDb.completionPeriod.at(milestonePrefix).getOrDefault(0); int computedCompletionPeriod = proposalTotalPeriod + completionPeriod; @@ -880,30 +897,45 @@ public void submitProgressReport(ProgressReportAttributes progressReport, Milest Context.revert(TAG + ":: Submit progress report for all milestones."); } - Context.require(milestoneSubmissions.length + approvedReports <= totalMilestoneCount, TAG + ":: Submitted milestone is greater than recorded on proposal."); - List milestoneDeadlineIDs = getMilestoneDeadline(ipfsHash); - if (!milestoneDeadlineIDs.isEmpty()) { - boolean isMilestoneSubmitted = checkContainsMilestone(milestoneSubmissions, milestoneDeadlineIDs); - Context.require(isMilestoneSubmitted, TAG + ": Submit milestone report for milestone id. " + milestoneDeadlineIDs); - } for (MilestoneSubmission milestoneAttr : milestoneSubmissions) { + String milestonePrefix = mileStonePrefix(ipfsHash, milestoneAttr.id); int milestoneStatus = getMileststoneStatusOf(ipfsHash, milestoneAttr.id); + int milestoneCompletionPeriod = MilestoneDb.completionPeriod.at(milestonePrefix).get(); + + for (int i = 0; i < getRemainingMilestones(ipfsHash).size(); i++) { + Map milestoneIdsMap = getRemainingMilestones(ipfsHash).get(i); + int milestoneId = (int) milestoneIdsMap.get(MILESTONE_ID); + + String milestonePrefix1 = mileStonePrefix(ipfsHash, milestoneId); + int milestoneCompletionPeriod1 = MilestoneDb.completionPeriod.at(milestonePrefix1).get(); + if (milestoneCompletionPeriod1 < milestoneCompletionPeriod) { + MilestoneDb.completionPeriod.at(milestonePrefix1).set(milestoneCompletionPeriod1 + 1); + MilestoneDb.completionPeriod.at(milestonePrefix).set(milestoneCompletionPeriod - 1); + } + } + 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); } + List milestoneDeadlineIDs = getMilestoneDeadline(ipfsHash); + if (!milestoneDeadlineIDs.isEmpty()) { + boolean isMilestoneSubmitted = checkContainsMilestone(milestoneSubmissions, milestoneDeadlineIDs); + Context.require(isMilestoneSubmitted, TAG + ": Submit milestone report for milestone id. " + milestoneDeadlineIDs); + } + } if (progressReport.budget_adjustment) { @@ -976,10 +1008,18 @@ public void voteProgressReport(String reportKey, String voteReason, MilestoneVot TAG + ": Progress Reports can be voted only on Voting Period."); Address caller = Context.getCaller(); PReps pReps = new PReps(); + + List
callLocation; + if (getCouncilFlag()) { + callLocation = getCouncilManagers(); + } else { + callLocation = ArrayDBUtils.arrayDBtoList(pReps.validPreps); + } + Context.require(!ArrayDBUtils.containsInArrayDb(caller, blockAddresses), TAG + ": You are blocked from CPS."); - Context.require(ArrayDBUtils.containsInArrayDb(caller, pReps.validPreps), - TAG + ": Voting can only be done by registered P-Reps."); + Context.require(ArrayDBUtils.containsInList(caller, callLocation), + TAG + ": Voting can only be done by registered P-Reps or Council Managers."); String progressReportPrefix = progressReportPrefix(reportKey); ArrayDB submittedMilestones = milestoneSubmitted.at(progressReportPrefix);// CAN TAKE FROM READONLY METHOD for (MilestoneVoteAttributes milestoneVote : votes) { @@ -1011,8 +1051,13 @@ public void voteProgressReport(String reportKey, String voteReason, MilestoneVot 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)); + if (getCouncilFlag()) { + ProgressReportDataDb.totalVotes.at(progressReportPrefix).set(EXA.multiply(BigInteger.valueOf(getCouncilManagers().size()))); + ProgressReportDataDb.totalVoters.at(progressReportPrefix).set(getCouncilManagers().size()); + } else { + ProgressReportDataDb.totalVotes.at(progressReportPrefix).set(this.totalDelegationSnapshot.getOrDefault(BigInteger.ZERO)); + ProgressReportDataDb.totalVoters.at(progressReportPrefix).set(pReps.validPreps.size()); + } } DictDB voteChanged = ProgressReportDataDb.voteChange.at(progressReportPrefix); @@ -1057,6 +1102,7 @@ public void voteProgressReport(String reportKey, String voteReason, MilestoneVot } } + boolean budgetAdjustment = (boolean) progressReportDetails.get(BUDGET_ADJUSTMENT); if (budgetAdjustment && getBudgetAdjustmentFeature()) { // budgetAdjustment(reportKey, budgetAdjustmentVote, voteChange); @@ -1078,6 +1124,10 @@ public void voteProgressReport(String reportKey, String voteReason, MilestoneVot budgetAdjustment(reportKey, budgetAdjustmentVote, voteChange); } + + if (hasTwoThirdsMajority(proposalKey, milestoneVote.id)) { + MilestoneDb.majorityFlag.at(milestonePrefix).set(true); + } VotedSuccessfully(caller, "Progress Report Vote for " + progressReportDetails.get(PROGRESS_REPORT_TITLE) + " Successful."); swapBNUsdToken(); } @@ -1244,8 +1294,8 @@ public void updatePeriod() { period.periodName.set(TRANSITION_PERIOD); period.previousPeriodName.set(APPLICATION_PERIOD); period.updatePeriodIndex.set(updateIndex + 1); + callScore(getCpfTreasuryScore(), "setRewardPool", "finalFund"); updateProposalsResult(); - PeriodUpdate("Period Update State 1/4. Period Updated to Transition Period. " + "After all the calculations are completed, " + "Period will change to " + APPLICATION_PERIOD); @@ -1276,6 +1326,8 @@ public void updatePeriod() { period.periodCount.set(period.periodCount.getOrDefault(0) + 1); burn(proposalFees.get(), null); proposalFees.set(BigInteger.ZERO); + + callScore(getCpfTreasuryScore(), "distributeRewardToFundManagers"); } } @@ -1311,6 +1363,7 @@ private void updateMilestoneDB(String milestonePrefix) { DictDB prepVote = MilestoneDb.votersListIndices.at(milestonePrefix).at(prep); prepVote.set(INDEX, 0); prepVote.set(VOTE, 0); + MilestoneDb.majorityFlag.at(milestonePrefix).set(false); } clearArrayDb(MilestoneDb.votersList.at(milestonePrefix)); } @@ -1337,7 +1390,6 @@ private void updateProgressReportResult() { 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); @@ -1351,8 +1403,6 @@ private void updateProgressReportResult() { BigInteger _sponsor_deposit_amount = (BigInteger) _proposal_details.get(SPONSOR_DEPOSIT_AMOUNT); String flag = (String) _proposal_details.get(TOKEN); - List
_main_preps_list = arrayDBtoList(pReps.validPreps); - ArrayDB milestoneSubmitted = ProgressReportDataDb.milestoneSubmitted.at(progressPrefix); int milestonePassed = 0; @@ -1368,20 +1418,27 @@ private void updateProgressReportResult() { 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); + boolean majorityFlag = (boolean) _milestone_details.get(MAJORITY_FLAG); 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) { + int votersCount; + int minimumVoters; + + if (getCouncilFlag()) { + minimumVoters = 3; + votersCount = getCouncilManagers().size(); + } else { + minimumVoters = 7; + votersCount = pReps.validPreps.size(); + } + + if (_total_voters == 0 || _total_votes.equals(BigInteger.ZERO) || votersCount < minimumVoters) { 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) { + if (majorityFlag) { _approved_reports_count += 1; - if (milestoneStatus == MILESTONE_REPORT_COMPLETED) { milestonePassed += 1; milestoneBudget = milestoneBudget.add(MilestoneDb.budget.at(milestonePrefix).getOrDefault(BigInteger.ZERO)); @@ -1413,22 +1470,19 @@ private void updateProgressReportResult() { 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); - } + int finalPeriodToSubmit = proposalPeriod + completionPeriod; + if (getPeriodCount() < finalPeriodToSubmit) { + milestonePassed += 1; + } else if (getPeriodCount() >= finalPeriodToSubmit && !extended) { + milestonePassed += 1; + String proposalPrefix = proposalPrefix(_ipfs_hash); + int project_duration = (int) _proposal_details.get(PROJECT_DURATION); + MilestoneDb.extensionFlag.at(milestonePrefix).set(true); + ProposalDataDb.projectDuration.at(proposalPrefix).set(project_duration + 1); + MilestoneDb.completionPeriod.at(milestonePrefix).set(completionPeriod + 1); } updateMilestoneDB(milestonePrefix); - } - } else { MilestoneDb.status.at(milestonePrefix).set(MILESTONE_REPORT_REJECTED); updateMilestoneDB(milestonePrefix); @@ -1458,7 +1512,6 @@ private void updateProgressReportResult() { } } } - } @@ -1556,7 +1609,19 @@ private void updateBudgetAdjustments(String _budget_key) { BigInteger _total_votes = (BigInteger) _vote_result.get(TOTAL_VOTES); PReps pReps = new PReps(); double votersRatio = (double) _approve_voters / _total_voters; - if (_total_voters == 0 || _total_votes.equals(BigInteger.ZERO) || pReps.validPreps.size() < MINIMUM_PREPS) { + + int votersCount; + int minimumVoters; + + if (getCouncilFlag()) { + minimumVoters = 3; + votersCount = getCouncilManagers().size(); + } else { + minimumVoters = 7; + votersCount = pReps.validPreps.size(); + } + + if (_total_votes.equals(BigInteger.ZERO) || votersCount < minimumVoters) { budgetAdjustmentStatus.at(_prefix).set(REJECTED); } else if (votersRatio >= MAJORITY && (_approved_votes.doubleValue() / _total_votes.doubleValue()) >= MAJORITY) { String _ipfs_hash = (String) _report_result.get(IPFS_HASH); @@ -1572,7 +1637,6 @@ private void updateBudgetAdjustments(String _budget_key) { totalBudget.at(proposal_prefix).set(_total_budget.add(_additional_budget)); budgetAdjustmentStatus.at(_prefix).set(APPROVED); - // After the budget adjustment is approved, Request new added fund to CPF callScore(getCpfTreasuryScore(), "updateProposalFund", _ipfs_hash, token_flag, _additional_budget, _additional_duration); } else { @@ -1593,8 +1657,6 @@ private void updateProposalsResult() { BigInteger totalBudget = (BigInteger) proposalDetails.get(TOTAL_BUDGET); int projectDuration = (int) proposalDetails.get(MILESTONE_COUNT); BigInteger sponsorDepositAmount = (BigInteger) proposalDetails.get(SPONSOR_DEPOSIT_AMOUNT); - 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); @@ -1603,15 +1665,22 @@ private void updateProposalsResult() { checkInactivePreps(ProposalDataDb.votersList.at(proposalPrefix)); - double voters_ratio = 0; - if (totalVoters != 0) { - voters_ratio = (double) approvedVoters / totalVoters; + int votersCount; + int minimumVoters; + + if (getCouncilFlag()) { + minimumVoters = 3; + votersCount = getCouncilManagers().size(); + } else { + minimumVoters = 7; + votersCount = pReps.validPreps.size(); } - if (totalVoters == 0 || totalVotes.equals(BigInteger.ZERO) || pReps.validPreps.size() < MINIMUM_PREPS) { + + + if (totalVoters == 0 || totalVotes.equals(BigInteger.ZERO) || votersCount < minimumVoters) { updateProposalStatus(proposal, REJECTED); updatedStatus = REJECTED; - } else if ((voters_ratio) >= MAJORITY && - (approvedVotes.doubleValue() / totalVotes.doubleValue()) >= MAJORITY) { + } else if (majorityFlag.at(proposalPrefix).getOrDefault(false)) { if (totalBudget.multiply(BigInteger.valueOf(102)).divide(BigInteger.valueOf(100)). // total budget + 2% of sponsor compareTo(distributionAmount) < 0) { updateProposalStatus(proposal, ACTIVE); @@ -1696,10 +1765,16 @@ private void updateProgressReportStatus(String progressHash, String progressStat private void checkInactivePreps(ArrayDB
prepList) { PReps pReps = new PReps(); - for (int i = 0; i < pReps.validPreps.size(); i++) { - Address prep = pReps.validPreps.get(i); - if (!containsInArrayDb(prep, prepList) && !containsInArrayDb(prep, pReps.inactivePreps)) { - pReps.inactivePreps.add(prep); + List
voters; + if (getCouncilFlag()) { + voters = getCouncilManagers(); + } else { + voters = ArrayDBUtils.arrayDBtoList(pReps.validPreps); + } + + for (Address voter : voters) { + if (!containsInArrayDb(voter, prepList) && !containsInArrayDb(voter, pReps.inactivePreps)) { + pReps.inactivePreps.add(voter); } } } @@ -1873,17 +1948,6 @@ public Map getProgressReportsByHash(String reportKey) { return Map.of(); } - 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) { @@ -1996,8 +2060,8 @@ public List> getRemainingProject(String projectType, Address String ipfsHash = ProgressReportDataDb.ipfsHash.at(prefix).get(); ArrayDB milestoneSubmittedOf = milestoneSubmitted.at(prefix); - for (int j = 0; j < milestoneSubmittedOf.size(); j++) { - int milestoneID = milestoneSubmittedOf.get(j); + if (milestoneSubmittedOf.size() > 0) { + int milestoneID = milestoneSubmittedOf.get(0); String milestonePrefix = mileStonePrefix(ipfsHash, milestoneID); ArrayDB
voterList = MilestoneDb.votersList.at(milestonePrefix); @@ -2007,6 +2071,7 @@ public List> getRemainingProject(String projectType, Address _remaining_progress_report.add(progressReportDetails); } } + } return _remaining_progress_report; } @@ -2299,7 +2364,19 @@ private void updateApplicationResult() { PReps pReps = new PReps(); Status status = new Status(); PeriodController period = new PeriodController(); - if (pReps.validPreps.size() < MINIMUM_PREPS) { + + int votersCount; + int minimumVoters; + + if (getCouncilFlag()) { + minimumVoters = 3; + votersCount = getCouncilManagers().size(); + } else { + minimumVoters = 7; + votersCount = pReps.validPreps.size(); + } + + if (votersCount < minimumVoters) { period.periodName.set(APPLICATION_PERIOD); PeriodUpdate("Period Updated back to Application Period due to less Registered P-Reps Count"); @@ -2377,8 +2454,6 @@ public void tokenFallback(Address from, BigInteger value, byte[] data) { } else { Context.revert(TAG + " Not supported method. Token transfer fails."); } - - } private void sponsorVote(String ipfsKey, String vote, String voteReason, Address from, BigInteger value) { @@ -2656,6 +2731,47 @@ public Map getProposalsHistory(@Optional int startIndex) { return milestoneIdList; } + private boolean hasTwoThirdsMajority(String ipfsHash, int milestoneId) { + String ipfsHashPrefix = proposalPrefix(ipfsHash); + boolean isMilestone = milestoneId > 0; + BigInteger totalVotes; + BigInteger approvedVotes; + int approvedVoters; + int totalVoters; + + if (isMilestone) { + String milestonePrefix = mileStonePrefix(ipfsHash, milestoneId); + Map dataFromMilestoneDB = getDataFromMilestoneDB(milestonePrefix); + totalVotes = (BigInteger) dataFromMilestoneDB.get(TOTAL_VOTES); + totalVoters = (Integer) dataFromMilestoneDB.get(TOTAL_VOTERS); + approvedVotes = MilestoneDb.approvedVotes.at(milestonePrefix).getOrDefault(BigInteger.ZERO); + approvedVoters = MilestoneDb.approveVoters.at(milestonePrefix).size(); + + } else { + totalVotes = ProposalDataDb.totalVotes.at(ipfsHashPrefix).getOrDefault(BigInteger.ZERO); + totalVoters = ProposalDataDb.totalVoters.at(ipfsHashPrefix).getOrDefault(0); + approvedVotes = ProposalDataDb.approvedVotes.at(ipfsHashPrefix).getOrDefault(BigInteger.ZERO); + approvedVoters = ProposalDataDb.approveVoters.at(ipfsHashPrefix).size(); + } + + double voteWeight = approvedVotes.doubleValue() / totalVotes.doubleValue(); + double voters_ratio = (double) approvedVoters / totalVoters; + + return voters_ratio >= MAJORITY && voteWeight > MAJORITY; + } + + + @External(readonly = true) + public List
getCouncilManagers() { + return callScore(List.class, getCpfTreasuryScore(), "getCouncilManagers"); + } + + + @External(readonly = true) + public boolean getCouncilFlag() { + return callScore(boolean.class, getCpfTreasuryScore(), "getCouncilFlag"); + } + // =====================================TEMPORARY MIGRATIONS METHODS=============================================== @External @@ -2851,7 +2967,6 @@ public void callScore(BigInteger amount, Address address, String method, Object. public void validateAdmins() { Context.require(isAdmin(Context.getCaller()), TAG + ": Only Admins can call this method"); - } public void validateAdminScore(Address scoreAddress) { 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 index 4fe94274..b6698f87 100644 --- 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 @@ -23,6 +23,8 @@ public class MilestoneDb { public static final BranchDB>> votersListIndices = Context.newBranchDB(VOTERS_LIST_INDEXES, Integer.class); + public static final BranchDB> majorityFlag = Context.newBranchDB(MAJORITY_FLAG, Boolean.class); + public static void addDataToMilestoneDb(CPSCoreInterface.MilestonesAttributes milestoneData, String prefix) { id.at(prefix).set(milestoneData.id); approvedVotes.at(prefix).set(BigInteger.ZERO); @@ -30,6 +32,8 @@ public static void addDataToMilestoneDb(CPSCoreInterface.MilestonesAttributes mi completionPeriod.at(prefix).set(milestoneData.completionPeriod); budget.at(prefix).set(milestoneData.budget); + majorityFlag.at(prefix).set(false); + } public static Map getDataFromMilestoneDB(String prefix) { @@ -46,7 +50,10 @@ public static Map getDataFromMilestoneDB(String prefix) { 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))); + Map.entry(EXTENSION_FLAG, extensionFlag.at(prefix).getOrDefault(false)), + + Map.entry(MAJORITY_FLAG, majorityFlag.at(prefix).getOrDefault(false))); + } public static String progressReportPrefix(String progressHash) { 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 c0fa6cbe..78a26017 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 @@ -1,5 +1,6 @@ package community.icon.cps.score.cpscore.db; +import community.icon.cps.score.lib.interfaces.CPSCoreInterface.ProposalAttributes; import score.*; import java.math.BigInteger; @@ -7,7 +8,6 @@ import static community.icon.cps.score.cpscore.utils.ArrayDBUtils.recordTxHash; import static community.icon.cps.score.cpscore.utils.Constants.*; -import static community.icon.cps.score.lib.interfaces.CPSCoreInterface.ProposalAttributes; public class ProposalDataDb { public static final BranchDB> ipfsHash = Context.newBranchDB(IPFS_HASH, String.class); @@ -46,6 +46,9 @@ public class ProposalDataDb { public static final BranchDB> proposalPeriod = Context.newBranchDB(PROPOSAL_PERIOD, Integer.class); public static final BranchDB> milestoneIds = Context.newBranchDB("milestoneIds", Integer.class); + public static final BranchDB> majorityFlag = Context.newBranchDB(MAJORITY_FLAG, Boolean.class); + public static final BranchDB> councilFlag = Context.newBranchDB(COUNCIL_FLAG, Boolean.class); + public static void addDataToProposalDB(ProposalAttributes proposalData, String prefix) { ipfsHash.at(prefix).set(proposalData.ipfs_hash); projectTitle.at(prefix).set(proposalData.project_title); @@ -68,7 +71,7 @@ public static void addDataToProposalDB(ProposalAttributes proposalData, String p token.at(prefix).set(proposalData.token); milestoneCount.at(prefix).set(proposalData.milestoneCount); isMilestone.at(prefix).set(true); - + majorityFlag.at(prefix).set(false); } public static void updatePercentageCompleted(String prefix, int percentage) { @@ -96,7 +99,11 @@ public static Map getDataFromProposalDB(String prefix) { 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.entry(PROPOSAL_PERIOD,proposalPeriod.at(prefix).getOrDefault(0)), + + Map.entry(MAJORITY_FLAG, majorityFlag.at(prefix).getOrDefault(false)), + Map.entry(COUNCIL_FLAG, councilFlag.at(prefix).getOrDefault(false))); + } public static int getMilestoneCount(String prefix) { 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 6643dc30..b68308ff 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 @@ -10,10 +10,9 @@ public class Constants { public static final BigInteger EXA = BigInteger.valueOf(1000000000000000000L); - public static final Integer MINIMUM_PREPS = 7; public static final Integer MAX_PROJECT_PERIOD = 12; - public static final double MAJORITY = 0.67; + public static final double MAJORITY = 0.66; public static final BigInteger DAY_COUNT = BigInteger.valueOf(15); public static final BigInteger BLOCKS_DAY_COUNT = BigInteger.valueOf(43120); @@ -140,6 +139,7 @@ public class Constants { 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 IS_COUNCIL_MANAGER = "isCouncilManager"; public static final String PENALTY_AMOUNT1 = "penaltyAmount"; public static final String TRANSFER = "transfer"; public static final String METHOD = "method"; @@ -209,6 +209,10 @@ public class Constants { public static final Integer MILESTONE_REPORT_APPROVED = 3; public static final Integer MILESTONE_REPORT_NOT_COMPLETED = 4; + // new flags + + public static final String MAJORITY_FLAG = "majority_flag"; + public static final String COUNCIL_FLAG = "council_flag"; 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 fa2dcf69..21ff95bb 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 @@ -5,12 +5,18 @@ import com.iconloop.score.test.Score; import com.iconloop.score.test.ServiceManager; import com.iconloop.score.test.TestBase; + +import community.icon.cps.score.cpscore.db.MilestoneDb; import community.icon.cps.score.cpscore.utils.Constants; import community.icon.cps.score.lib.interfaces.CPSCoreInterface; +import community.icon.cps.score.lib.interfaces.CPSCoreInterface.ProgressReportAttributes; +import community.icon.cps.score.lib.interfaces.CPSCoreInterface.ProposalAttributes; + import org.junit.jupiter.api.*; import org.junit.jupiter.api.function.Executable; import org.mockito.MockedStatic; import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; import org.mockito.stubbing.Answer; import score.Address; import score.ArrayDB; @@ -20,12 +26,17 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import scorex.util.HashMap; + import static community.icon.cps.score.cpscore.utils.Constants.*; import static community.icon.cps.score.lib.interfaces.CPSCoreInterface.ProgressReportAttributes; import static community.icon.cps.score.lib.interfaces.CPSCoreInterface.ProposalAttributes; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.*; @@ -90,7 +101,7 @@ void addAdmin() { @Test void addAdminNotOwner() { Executable addAdminNotOwner = () -> cpsScore.invoke(testingAccount, "addAdmin", testingAccount.getAddress()); - expectErrorMessage(addAdminNotOwner, "Reverted(0): SenderNotScoreOwner: Sender=" + testingAccount.getAddress() + " Owner=" + owner.getAddress()); + expectErrorMessage(addAdminNotOwner, "SenderNotScoreOwner: Sender=" + testingAccount.getAddress() + " Owner=" + owner.getAddress()); } @Test @@ -106,7 +117,7 @@ void removeAdminNotOwner() { cpsScore.invoke(owner, "addAdmin", testingAccount.getAddress()); assertEquals(List.of(testingAccount.getAddress()), cpsScore.call("getAdmins")); Executable removeAdminNotOwner = () -> cpsScore.invoke(testingAccount, "removeAdmin", testingAccount.getAddress()); - expectErrorMessage(removeAdminNotOwner, "Reverted(0): SenderNotScoreOwner: Sender=" + testingAccount.getAddress() + " Owner=" + owner.getAddress()); + expectErrorMessage(removeAdminNotOwner, "SenderNotScoreOwner: Sender=" + testingAccount.getAddress() + " Owner=" + owner.getAddress()); } @Test @@ -114,7 +125,7 @@ void removeAdminAddressNotAdmin() { cpsScore.invoke(owner, "addAdmin", testingAccount.getAddress()); assertEquals(List.of(testingAccount.getAddress()), cpsScore.call("getAdmins")); Executable removeAdminNotOwner = () -> cpsScore.invoke(owner, "removeAdmin", testingAccount1.getAddress()); - expectErrorMessage(removeAdminNotOwner, "Reverted(0): CPS Score: Address not registered as admin."); + expectErrorMessage(removeAdminNotOwner, "CPS Score: Address not registered as admin."); } void addAdminMethod() { @@ -150,7 +161,7 @@ void registerPrepAlreadyRegistered() { cpsScore.invoke(owner, "setInitialBlock"); cpsScore.invoke(owner, "registerPrep"); Executable register = () -> cpsScore.invoke(owner, "registerPrep"); - expectErrorMessage(register, "Reverted(0): CPS Score: P-Rep is already registered."); + expectErrorMessage(register, "CPS Score: P-Rep is already registered."); } @Test @@ -175,7 +186,7 @@ void registerPrepNotAPrep() { cpsScore.invoke(owner, "toggleMaintenance"); cpsScore.invoke(owner, "setInitialBlock"); Executable register = () -> cpsScore.invoke(testingAccount9, "registerPrep"); - expectErrorMessage(register, "Reverted(0): CPS Score: Not a P-Rep."); + expectErrorMessage(register, "CPS Score: Not a P-Rep."); } @Test @@ -267,7 +278,7 @@ void unregisterPrepNotInValidPrep() { cpsScore.invoke(owner, "registerPrep"); Executable unregister = () -> cpsScore.invoke(testingAccount1, "unregisterPrep"); - expectErrorMessage(unregister, "Reverted(0): P-Rep is not registered yet."); + expectErrorMessage(unregister, "P-Rep is not registered yet."); } @Test @@ -406,7 +417,7 @@ void submitProposal() { assertEquals(owner.getAddress(), proposalDetails.get("contributor_address")); assertEquals("_sponsor_pending", proposalDetails.get("status")); assertEquals(BigInteger.valueOf(100).multiply(MULTIPLIER), proposalDetails.get("total_budget")); - Map proposalDetailsOfStatus = (Map) cpsScore.call("getProposalDetails", SPONSOR_PENDING, owner.getAddress(), 0, 10); + Map proposalDetailsOfStatus = (Map) cpsScore.call("getProposalDetails", SPONSOR_PENDING, owner.getAddress(), 0); assertEquals(1, proposalDetailsOfStatus.get(COUNT)); @@ -493,12 +504,15 @@ void sponsorVote() { "count", 1); assertEquals(amount, (projectAmounts.get(PENDING))); - Map sponosrsRequest = (Map) cpsScore.call("getSponsorsRequests", APPROVED, testingAccount.getAddress(), 0, 10); + Map sponosrsRequest = (Map) cpsScore.call("getSponsorsRequests", APPROVED, testingAccount.getAddress(), 0); System.out.println("Sponsors request" + sponosrsRequest); } void submitAndSponsorVote() { submitProposalMethod(); + + doReturn(false).when(scoreSpy).getCouncilFlag(); + contextMock.when(caller()).thenReturn(bnUSDScore); JsonObject sponsorVoteParams = new JsonObject(); sponsorVoteParams.add("method", "sponsorVote"); @@ -604,6 +618,14 @@ void voteProposal2() { } void voteProposalMethod() { + + // doReturn(List.of(cpfTreasury)).when(scoreSpy).callScore(cpfTreasury, "getCouncilManagers"); + + doReturn(List.of(cpfTreasury)).when(scoreSpy).callScore(List.class, cpfTreasury, "getCouncilManagers"); + doReturn(false).when(scoreSpy).getCouncilFlag(); + + //mockito void method cannot be stubbed. + submitAndSponsorVote(); contextMock.when(caller()).thenReturn(owner.getAddress()); updateNextBlock(); @@ -720,6 +742,9 @@ void voteMultipleProposals() { String[] proposal = new String[]{"Proposal 0", "Proposal 1", "Proposal 2", "Proposal 3", "Proposal 4", "Proposal 5", "Proposal 6", "Proposal 7", "Proposal 8", "Proposal 9"}; + + doReturn(false).when(scoreSpy).getCouncilFlag(); + for (int i = 0; i < 10; i++) { contextMock.when(caller()).thenReturn(owner.getAddress()); cpsScore.invoke(owner, "voteProposal", "Proposal " + i, APPROVE, "reason", false); @@ -768,6 +793,9 @@ void voteMultipleProposals() { void voteProposalMethodReject() { submitAndSponsorVote(); + + doReturn(false).when(scoreSpy).getCouncilFlag(); + contextMock.when(caller()).thenReturn(owner.getAddress()); updateNextBlock(); doReturn(BigInteger.valueOf(15)).when(scoreSpy).getApplicationPeriod(); @@ -806,6 +834,8 @@ void voteProposalMethodReject() { } void updatePeriods() { + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("distributeRewardToFundManagers")); + doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("setRewardPool"), any()); // 1/4 cpsScore.invoke(owner, "updatePeriod"); // 2/4 @@ -836,6 +866,7 @@ void updatePeriodAfterProposalVoting() { doNothing().when(scoreSpy).callScore(eq(cpfTreasury), eq("resetSwapState")); doReturn(BigInteger.valueOf(15)).when(scoreSpy).getVotingPeriod(); + updatePeriods(); Map proposalDetails = getProposalDetailsByHash("Proposal 1"); @@ -844,7 +875,7 @@ void updatePeriodAfterProposalVoting() { List> activeProposalList = (List>) activeProposals.get(DATA); assertEquals(List.of(proposalDetails).size(), activeProposalList.size()); - Map sponosrsRequest = (Map) cpsScore.call("getSponsorsRequests", APPROVED, testingAccount.getAddress(), 0, 10); + Map sponosrsRequest = (Map) cpsScore.call("getSponsorsRequests", APPROVED, testingAccount.getAddress(), 0); System.out.println("Sponsors request" + sponosrsRequest); Map sponsorsRecord = (Map) cpsScore.call("getSponsorsRecord"); @@ -936,7 +967,7 @@ void submitProgressReport() { List progressKeys = (List) cpsScore.call("getProgressKeys"); assertEquals(List.of("Report 1"), progressKeys); - Map progressReports = (Map) cpsScore.call("getProgressReports", WAITING, 0, 10); + Map progressReports = (Map) cpsScore.call("getProgressReports", WAITING, 0); System.out.println("Progerss reports: " + progressReports); // assertEquals(List.of(progressReportDetails), progressReports.get(DATA)); assertEquals(1, progressReports.get(COUNT)); @@ -965,7 +996,7 @@ void voteProgressReportExceptions() { 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 " + + expectErrorMessage(call, "CPS Score: Voting can only be done for milestone " + "submitted in this progress report"); } @@ -1000,7 +1031,7 @@ void voteProgressReportException() { 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"); + expectErrorMessage(call2, "You should submit votes for all milestones of the progress report"); } @@ -1540,7 +1571,7 @@ void disqualifyProposal() { Map proposalDetails = getProposalDetailsByHash("Proposal 1"); assertEquals(PAUSED, proposalDetails.get(STATUS)); - Map sponosrsRequest = (Map) cpsScore.call("getSponsorsRequests", APPROVED, testingAccount.getAddress(), 0, 10); + Map sponosrsRequest = (Map) cpsScore.call("getSponsorsRequests", APPROVED, testingAccount.getAddress(), 0); System.out.println("Sponsors request::" + sponosrsRequest); Map sponsorsRecord = (Map) cpsScore.call("getSponsorsRecord"); @@ -1792,7 +1823,7 @@ void sponsorDepositsLessThanBondPercentage() { 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."); + expectErrorMessage(bondPercentageRevert, "CPS Score: Deposit 15% of the total budget of the project."); } @@ -1839,7 +1870,7 @@ void progressReportWithNotCompletedStatus() { List progressKeys = (List) cpsScore.call("getProgressKeys"); assertEquals(List.of("Report 1"), progressKeys); - Map progressReports = (Map) cpsScore.call("getProgressReports", WAITING, 0, 10); + Map progressReports = (Map) cpsScore.call("getProgressReports", WAITING, 0); System.out.println("Progerss reports: " + progressReports); assertEquals(1, progressReports.get(COUNT)); @@ -2046,6 +2077,61 @@ void submitProgressReportBeforeDeadline() { } + //begin + + public class VotingTest { + + private void commonSetup() { + + // Mock methods and setup initial conditions + doReturn(BigInteger.valueOf(3)).when(scoreSpy).callScore(eq(BigInteger.class), any(), eq("getTotalVotes"), any()); + doReturn(BigInteger.ZERO).when(scoreSpy).callScore(eq(BigInteger.class), any(), eq("getApprovedVotes"), any()); + doReturn(3).when(scoreSpy).callScore(eq(Integer.class), any(), eq("getTotalVoters"), any()); + } + + @Test + public void testVotingProcess() { + // Setup required for this specific test + commonSetup(); + + // Simulate the first voter + CPSCoreInterface.MilestoneVoteAttributes firstVote = new CPSCoreInterface.MilestoneVoteAttributes(); + firstVote.vote = APPROVE; + firstVote.id = 1; + + // Invoke the voting method for the first voter + cpsScore.invoke(owner, "voteProposal", "Proposal 1", firstVote, false); + + // Check if the majority is met after the first vote + boolean isMajorityAfterFirstVote = (Boolean)cpsScore.call("hasTwoThirdsMajority","Proposal 1", true); + assertFalse(isMajorityAfterFirstVote); // Expecting false + + // Simulate the second voter + CPSCoreInterface.MilestoneVoteAttributes secondVote = new CPSCoreInterface.MilestoneVoteAttributes(); + secondVote.vote = REJECT; + secondVote.id = 2; + + // Invoke the voting method for the second voter + cpsScore.invoke(owner, "voteProposal", "Proposal 1", secondVote, false); + + // Check if the majority is met after the second vote + boolean isMajorityAfterSecondVote = (Boolean)cpsScore.call("hasTwoThirdsMajority","Proposal 1", true); + assertFalse(isMajorityAfterSecondVote); // Expecting false + + // Simulate the third voter + CPSCoreInterface.MilestoneVoteAttributes thirdVote = new CPSCoreInterface.MilestoneVoteAttributes(); + thirdVote.vote = APPROVE; + thirdVote.id = 3; + + // Invoke the voting method for the third voter + cpsScore.invoke(owner, "voteProposal", "Proposal 1", thirdVote, false); + + // Check if the majority is met after the third vote + Boolean isMajorityAfterThirdVote = (Boolean)cpsScore.call("hasTwoThirdsMajority","Proposal 1", true); + assertTrue(isMajorityAfterThirdVote); // Expecting true + } +} + //end @Test void setSwapCount() { @@ -2057,22 +2143,22 @@ void setSwapCount() { @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"); + expectErrorMessage(percentageNotAdmin, "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%"); + expectErrorMessage(percentageLessTwelve, "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"); + expectErrorMessage(setPeriodNotAdmin, "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"); + expectErrorMessage(periodis15, "CPS Score: Voting period must be more than or equal to 10 days"); } @@ -2137,7 +2223,7 @@ void updateContributorAddress() { milestoneSubmission1}; Executable call = () -> cpsScore.invoke(owner, "submitProgressReport", progressReport, milestoneSubmission); - expectErrorMessage(call, "Reverted(0): CPS Score: Sorry, You are not the contributor for this project."); + expectErrorMessage(call, "CPS Score: Sorry, You are not the contributor for this project."); contextMock.when(caller()).thenReturn(testingAccount1.getAddress()); cpsScore.invoke(testingAccount1, "submitProgressReport", progressReport, milestoneSubmission); diff --git a/CPSTreasury/build.gradle b/CPSTreasury/build.gradle index fec63b41..669f7650 100644 --- a/CPSTreasury/build.gradle +++ b/CPSTreasury/build.gradle @@ -1,19 +1,22 @@ -version = '1.3.5' +version = '1.4' dependencies { - compileOnly 'foundation.icon:javaee-api:0.9.2' +// compileOnly 'foundation.icon:javaee-api:0.9.2' + +// implementation project(':score-lib') +// implementation 'com.github.sink772:minimal-json:0.9.7' +// implementation 'foundation.icon:javaee-scorex:0.5.3' +// testImplementation project(':test-lib') +// testImplementation 'foundation.icon:javaee-unittest:0.9.7' +// testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.0' +// testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0' + testImplementation('org.mockito:mockito-inline:4.8.0') +// intTestImplementation 'foundation.icon:icon-sdk:2.2.0' +// intTestImplementation project(":score-client") +// intTestAnnotationProcessor project(":score-client") implementation project(':score-lib') - implementation 'com.github.sink772:minimal-json:0.9.7' - implementation 'foundation.icon:javaee-scorex:0.5.3' testImplementation project(':test-lib') - testImplementation 'foundation.icon:javaee-unittest:0.9.7' - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.0' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0' - testImplementation('org.mockito:mockito-inline:4.8.0') - intTestImplementation 'foundation.icon:icon-sdk:2.2.0' - intTestImplementation project(":score-client") - intTestAnnotationProcessor project(":score-client") } optimizedJar { @@ -28,31 +31,22 @@ deployJar { lisbon { uri = 'https://lisbon.net.solidwallet.io/api/v3' nid = 0x2 - to = 'cxabc97ed26cb147eeef55b1728102aea25af8f62f' - } - local { - uri = 'http://localhost:9082/api/v3' - nid = 0x3 - } - sejong{ - uri = 'https://sejong.net.solidwallet.io/api/v3' - nid = 0x53 - to = 'cxb33f0187a22a41c3ecb05a9756af320e98badb7d' - } - berlin{ - uri = 'https://berlin.net.solidwallet.io/api/v3' - nid = 0x7 - to = 'cx3e2a9648e4365added55bfa6a84e515d99f1bb67' + to = "cxe2179d6409a4920ac6e6ee272d79a3bcfea969df" } mainnet { uri = 'https://ctz.solidwallet.io/api/v3' nid = 0x1 to = 'cxd965531d1cce5daad1d1d3ee1efb39ce68f442fc' } + devnet{ + uri = "https://tt.net.solidwallet.io/api/v3" + nid = 0x3 + } } keystore = rootProject.hasProperty('keystoreName') ? "$keystoreName" : '' password = rootProject.hasProperty('keystorePass') ? "$keystorePass" : '' parameters { + arg("cpsScore", "cx5100c8b221cc373939d8a720ecfbd90440c75ed3") } } 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 5df88454..c58c20a4 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 @@ -55,9 +55,10 @@ public class CPSTreasury extends ProposalData implements CPSTreasuryInterface { private static final BigInteger HUNDRED = BigInteger.valueOf(100); public static final BigInteger MAX_ONSET_PAYMENT = BigInteger.valueOf(20); - public CPSTreasury() { + public CPSTreasury(@Optional Address cpsScore) { if (onsetPaymentPercentage.get() == null) { onsetPaymentPercentage.set(BigInteger.TEN); + this.cpsScore.set(cpsScore); } } 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 140467b3..46efae32 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 @@ -51,7 +51,7 @@ public class CPSTreasuryTest extends TestBase { @BeforeEach public void setup() throws Exception { - tokenScore = sm.deploy(owner, CPSTreasury.class); + tokenScore = sm.deploy(owner, CPSTreasury.class, score_address); CPSTreasury instance = (CPSTreasury) tokenScore.getInstance(); scoreSpy = spy(instance); tokenScore.setInstance(scoreSpy); @@ -167,39 +167,39 @@ void setBnUSDScoreExceptions(Boolean isAdmin, Address score_address) { void setCpsScoreNotAdmin() { setScoresMethod(); Executable setCpsScoreNotAdmin = () -> setCpsScoreExceptions(false, score_address); - expectErrorMessage(setCpsScoreNotAdmin, "Reverted(0): " + TAG + ": Only admins can call this method"); + expectErrorMessage(setCpsScoreNotAdmin, 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"); + expectErrorMessage(setCpfTreasuryScoreNotAdmin, 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"); + expectErrorMessage(setBnUSDScoreNotAdmin, TAG + ": Only admins can call this method"); } @Test void setCPSScoreNotContract() { Executable setCpsScoreNotAdmin = () -> setCpsScoreExceptions(true, testing_account.getAddress()); - expectErrorMessage(setCpsScoreNotAdmin, "Reverted(0): " + TAG + "Target " + testing_account.getAddress() + " is not a score."); + expectErrorMessage(setCpsScoreNotAdmin, TAG + "Target " + testing_account.getAddress() + " is not a score."); } @Test void setCPFTreasuryScoreNotContract() { Executable setCpfTreasuryScoreNotContract = () -> setCpfTreasuryScoreExceptions(true, testing_account.getAddress()); - expectErrorMessage(setCpfTreasuryScoreNotContract, "Reverted(0): " + TAG + "Target " + testing_account.getAddress() + " is not a score."); + expectErrorMessage(setCpfTreasuryScoreNotContract, TAG + "Target " + testing_account.getAddress() + " is not a score."); } @Test void setBnUSDScoreNotContract() { Executable setBnUSDScoreContract = () -> setBnUSDScoreExceptions(true, testing_account.getAddress()); - expectErrorMessage(setBnUSDScoreContract, "Reverted(0): " + TAG + "Target " + testing_account.getAddress() + " is not a score."); + expectErrorMessage(setBnUSDScoreContract, TAG + "Target " + testing_account.getAddress() + " is not a score."); } @Test @@ -268,7 +268,7 @@ void depositProposalFundProposalAlreadyExists(){ setOnsetPayment(); depositProposalFundMethod(); Executable depositProposalFundProposalAlreadyExists = () -> depositProposalFundExceptions(); - expectErrorMessage(depositProposalFundProposalAlreadyExists, "Reverted(0): " + "CPS_TREASURY: Already have this project"); + expectErrorMessage(depositProposalFundProposalAlreadyExists, "CPS_TREASURY: Already have this project"); } @Test @@ -342,7 +342,7 @@ void updateProposalFundProposalException(){ @Test void updateProposalFundProposalDoesnotExist(){ Executable updateProposalFundProposalDoesnotExist = () -> updateProposalFundProposalException(); - expectErrorMessage(updateProposalFundProposalDoesnotExist, "Reverted(0): " + "CPS_TREASURY: Invalid IPFS hash."); + expectErrorMessage(updateProposalFundProposalDoesnotExist, "CPS_TREASURY: Invalid IPFS hash."); } private void depositProposalFund_MilestoneCheck() { @@ -569,4 +569,47 @@ void claimReward(){ } + + @Test + void updateAddress(){ + setOnsetPayment(); + setCpsScoreMethod(); + + contextMock.when(caller()).thenReturn(score_address); + depositProposalFundMethod(); + + Address newContributorAddress = sm.createAccount().getAddress(); + Address newSponsorAddress = sm.createAccount().getAddress(); + + contextMock.when(caller()).thenReturn(score_address); + tokenScore.invoke(testing_account,"updateContributorSponsorAddress", "Proposal 1", + newContributorAddress,newSponsorAddress); + + + Map oldContributorData = (Map) tokenScore.call("getContributorProjectedFund", testing_account2.getAddress()); + System.out.println("The data is empty: "+oldContributorData.get(DATA)); + + Map oldSponsorData = (Map) tokenScore.call("getSponsorProjectedFund", testing_account.getAddress()); + System.out.println("The data is empty: "+oldSponsorData.get(DATA)); + + doReturn(List.of(Map.of( + BUDGET,BigInteger.valueOf(50).multiply(ICX) + ))).when(scoreSpy).callScore(List.class,score_address,"getRemainingMilestones","Proposal 1"); + Map newContributorData = (Map) tokenScore.call("getContributorProjectedFund", newContributorAddress); + + List> data = (List>) newContributorData.get(DATA); + assertEquals(data.get(0).get("ipfs_hash"),"Proposal 1"); + assertEquals(data.get(0).get("total_installment_paid"), new BigInteger("10000000000000000000")); + + + Map newSponsorData = (Map) tokenScore.call("getSponsorProjectedFund", newSponsorAddress); + System.out.println(newSponsorData); + data = (List>) newSponsorData.get(DATA); + assertEquals(data.get(0).get("ipfs_hash"),"Proposal 1"); + assertEquals(data.get(0).get("total_installment_paid"), new BigInteger("200000000000000000")); + assertEquals(data.get(0).get("sponsor_bond_amount"), new BigInteger("15000000000000000000")); + + + } + } \ No newline at end of file diff --git a/README.md b/README.md index c6928651..fdfc9f7b 100644 --- a/README.md +++ b/README.md @@ -1 +1,32 @@ -# cps_java_contracts \ No newline at end of file +# CPS JAVA CONTRACTS + +This repository contains the smart contracts for CPS in Java. + +### Requirement +- JDK 11+ + +### Setting up Local Environment + +- Clone submodule + +```git submodule update --init``` + +- Run unit tests + +```./gradlew clean build optimizedJar``` + +### Run integration tests + +- Install [docker](https://docs.docker.com/engine/install/) and [docker compose](https://docs.docker.com/compose/install/) +- Start local blockchain + +```docker compose up -d``` + + +- execute following command + +```./gradlew intTestClasses``` + +```./gradlew assemble``` + +```./gradlew integrationTest``` \ No newline at end of file diff --git a/build.gradle b/build.gradle index 1e59de7f..400d42b1 100644 --- a/build.gradle +++ b/build.gradle @@ -17,10 +17,14 @@ task buildContracts(type: Exec) { subprojects { repositories { mavenCentral() + flatDir { + dirs "$rootProject.projectDir/jars" + } } - apply plugin: 'java' - apply plugin: 'jacoco' + +// apply plugin: 'java' +// apply plugin: 'jacoco' apply plugin: 'foundation.icon.javaee' sourceSets { @@ -38,6 +42,46 @@ subprojects { intTestRuntimeOnly.extendsFrom testRuntimeOnly } + ext { + env = has("network") ? getProperty("network") : 'dev' + javaeeVersion = findProperty("javaee.version") ?: '0.9.0' + scorexVersion = findProperty("scorex.version") ?: '0.5.2' + javaeeUnittestVersion = findProperty("javaee-unittest.version") ?: '0.9.2' + scoreClientVersion = findProperty("score-client.version") ?: '0.9.0' + iconsdkVersion = findProperty("iconsdk.version") ?: '2.0.0' + jacksonVersion = findProperty("jackson.version") ?: '2.13.2' + mockitoVersion = findProperty("mockito.version") ?: '4.3.1' + junitVersion = findProperty("junit.version") ?: '5.8.1' + javafakerVersion = findProperty("javafaker.version") ?: '1.0.2' + commonIOVersion = findProperty("common-io.version") ?: '2.11.0' + + } + + dependencies{ + compileOnly "foundation.icon:javaee-api:$javaeeVersion" + implementation ("foundation.icon:javaee-annotation-processor:$javaeeVersion") + + implementation "foundation.icon:javaee-scorex:$scorexVersion" + implementation "com.github.sink772:minimal-json:0.9.6" + compileOnly name: "score-client-$scoreClientVersion" + annotationProcessor "foundation.icon:javaee-score-client:$scoreClientVersion" + + testImplementation name: "score-client-$scoreClientVersion" + testAnnotationProcessor "foundation.icon:javaee-score-client:$scoreClientVersion" + + implementation ("com.fasterxml.jackson.core:jackson-core:$jacksonVersion") + implementation ("com.fasterxml.jackson.core:jackson-annotations:$jacksonVersion") + testImplementation("com.fasterxml.jackson.core:jackson-databind:$jacksonVersion") + + testImplementation "foundation.icon:javaee-unittest:$javaeeUnittestVersion" + testImplementation "org.junit.jupiter:junit-jupiter:$junitVersion" + testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitVersion" + testImplementation "org.mockito:mockito-core:$mockitoVersion" + + + + } + java { sourceCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11 @@ -48,28 +92,58 @@ subprojects { options.compilerArgs += ['-parameters'] } - tasks.named('test') { - // Use JUnit Platform for unit tests. - useJUnitPlatform() + def loadProperties = { + def prefix = 'score-test.' + def props = project.getProperties() + def scoreTest = new HashMap() + + scoreTest.put('keystoreName', props.getOrDefault(prefix + 'keystoreName', "$rootDir/gochain-local/data/godWallet.json")) + scoreTest.put('keystorePass', props.getOrDefault(prefix + 'keystorePass', "gochain")) + scoreTest.put('url', props.getOrDefault(prefix + 'url', 'http://localhost:9082/api/v3')) + scoreTest.put('nid', props.getOrDefault(prefix + 'nid', 3)) + + ext['scoreTest'] = scoreTest } + loadProperties() - scoreIntegrationTest.put('env.props', new File(project(':test-lib').projectDir, 'conf/env.props')) +// tasks.named('test') { +// // Use JUnit Platform for unit tests. +// useJUnitPlatform() +// } + +// scoreIntegrationTest.put('bnUSD', "https://raw.githubusercontent.com/naneey/cps-scores/main/dummy/IRC2Token.jar") + scoreIntegrationTest.put('bnUSD', "$rootProject.projectDir/dummyJarFiles/bnUSD-0.9.1-optimized.jar") +// scoreIntegrationTest.put('DEX', "$rootProject.projectDir/dummyJarFiles/Dex-0.9.1-optimized.jar") +// scoreIntegrationTest.put('ROUTER', "$rootProject.projectDir/dummyJarFiles/Router-0.9.1-optimized.jar") +// scoreIntegrationTest.put('ORACLE', "$rootProject.projectDir/dummyJarFiles/oracle-0.9.1-optimized.jar") +// scoreIntegrationTest.put('sICX', "$rootProject.projectDir/dummyJarFiles/Sicx-0.0.1-optimized.jar") afterEvaluate { project -> scoreIntegrationTest.put(project.name, project.getTasks().getByName("optimizedJar").outputJarName) } - tasks.named("assemble") { - if (project.tasks.findByName("compileIntTestJava")) { - finalizedBy(project.tasks.getByName("compileIntTestJava")) +// tasks.named("assemble") { +// if (project.tasks.findByName("compileIntTestJava")) { +// finalizedBy(project.tasks.getByName("compileIntTestJava")) +// } +// } + + gradle.taskGraph.beforeTask { Task task -> + if (task.name == 'integrationTest') { + scoreIntegrationTest.each { key, val -> + task.systemProperty key, val + } + task.systemProperty "DEBUG_ENABLED", true + task.systemProperty "BLOCK_INTERVAL", 50 + task.systemProperty "DEFAULT_RESULT_RETRY_WAIT", 100 } } gradle.taskGraph.whenReady { taskGraph -> - taskGraph.getAllTasks().eachWithIndex { task, n -> - if (task.name == 'integrationTest') { - scoreIntegrationTest.each { key, val -> task.systemProperty key, val } - } - } +// taskGraph.getAllTasks().eachWithIndex { task, n -> +// if (task.name == 'integrationTest') { +// scoreIntegrationTest.each { key, val -> task.systemProperty key, val } +// } +// } } } diff --git a/cps-gochain-local b/cps-gochain-local new file mode 160000 index 00000000..fc7b5425 --- /dev/null +++ b/cps-gochain-local @@ -0,0 +1 @@ +Subproject commit fc7b5425dd9e0e51b2f5355e0a8a00143a29b725 diff --git a/docker-compose.yml b/docker-compose.yml index 9375516f..309edaf9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,10 +4,10 @@ services: container_name: gochain-iconee image: public.ecr.aws/f5d2t1f5/goloop-gochain-icon:latest env_file: - - ./gochain-local/data/single/iconee.env + - ./cps-gochain-local/data/single/iconee.env volumes: - - ./gochain-local/data/single:/goloop/data - - ./gochain-local/data/governance:/goloop/data/gov - - ./gochain-local/chain:/testsuite/chain + - ./cps-gochain-local/data/single:/goloop/data + - ./cps-gochain-local/data/governance:/goloop/data/gov + - ./cps-gochain-local/chain:/testsuite/chain ports: - "9082:9082" \ No newline at end of file diff --git a/dummy/Dex/build.gradle b/dummy/Dex/build.gradle index bed00959..7c3d12e6 100644 --- a/dummy/Dex/build.gradle +++ b/dummy/Dex/build.gradle @@ -1,18 +1,9 @@ version = '0.9.1' dependencies { - compileOnly 'foundation.icon:javaee-api:0.9.1' - implementation project(':score-lib') - - implementation 'com.github.sink772:javaee-tokens:0.6.1' - implementation 'com.github.sink772:minimal-json:0.9.6' - testImplementation 'foundation.icon:javaee-unittest:0.9.2' - implementation 'org.mockito:mockito-core:4.3.1' - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' - testImplementation('org.mockito:mockito-inline:4.3.1') - implementation 'foundation.icon:javaee-scorex:0.5.2' + implementation project(':score-lib') + testImplementation project(':test-lib') } @@ -33,16 +24,11 @@ deployJar { uri = 'http://localhost:9082/api/v3' nid = 0x3 } - sejong { - uri = 'https://sejong.net.solidwallet.io/api/v3' - nid = 0x53 - - } - berlin { - uri = 'https://berlin.net.solidwallet.io/api/v3' - nid = 0x7 - to = 'cx28ae7ed3b07ed5247a3d2f97680f8555ce7c0a92' + devnet{ + uri = "https://tt.net.solidwallet.io/api/v3" + nid = 0x3 } + } keystore = rootProject.hasProperty('keystoreName') ? "$keystoreName" : '' password = rootProject.hasProperty('keystorePass') ? "$keystorePass" : '' diff --git a/dummy/Dex/src/main/java/dummy/contract/dex/Dex.java b/dummy/Dex/src/main/java/dummy/contract/dex/Dex.java index 439f8006..aade21f1 100644 --- a/dummy/Dex/src/main/java/dummy/contract/dex/Dex.java +++ b/dummy/Dex/src/main/java/dummy/contract/dex/Dex.java @@ -2,39 +2,40 @@ import com.eclipsesource.json.Json; import com.eclipsesource.json.JsonObject; +import community.icon.cps.score.lib.interfaces.DexInterface; import score.Address; import score.Context; -import score.DictDB; import score.VarDB; import score.annotation.EventLog; import score.annotation.External; -import scorex.util.ArrayList; +import score.annotation.Payable; import java.math.BigInteger; import java.util.Arrays; -import java.util.List; -public class Dex implements community.icon.cps.score.lib.interfaces.DexInterface { +public class Dex implements DexInterface { private static final String TAG = "Balanced DEX"; private final VarDB
sicx = Context.newVarDB("sicx", Address.class); public static final BigInteger EXA = BigInteger.valueOf(1_000_000_000_000_000_000L); - public Dex(){} + public Dex() { + } @Override @External - public void setSicxScore(Address _score){ + public void setSicxScore(Address _score) { this.sicx.set(_score); } @External(readonly = true) - public BigInteger getPrice(int poolId){ + public BigInteger getPrice(int _id) { return BigInteger.ONE; } @Override @EventLog - public void Deposit(Address from_token, Address from, BigInteger value){} + public void Deposit(Address from_token, Address from, BigInteger value) { + } @Override @EventLog(indexed = 2) @@ -44,13 +45,19 @@ public void Swap(BigInteger _id, Address _baseToken, Address _fromToken, Address BigInteger _poolQuote, BigInteger _endingPrice, BigInteger _effectiveFillPrice) { } + + @Payable + public void fallback(){ + + } + @Override @External public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { // Parse the transaction data submitted by the user String unpackedData = new String(_data); Context.require(!unpackedData.equals(""), "Token Fallback: Data can't be empty"); - if (Arrays.equals(_data, "None".getBytes())){ + if (Arrays.equals(_data, "None".getBytes())) { return; } JsonObject json = Json.parse(unpackedData).asObject(); @@ -94,10 +101,14 @@ public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { Address toToken = Address.fromString(params.get("toToken").asString()); // Perform the swap + exchange(fromToken, toToken, _from, receiver, _value, minimumReceive); break; } + case "_dex":{ + break; + } default: // If no supported method was sent, revert the transaction Context.revert(100, TAG + ": Unsupported method supplied"); @@ -117,6 +128,7 @@ void exchange(Address fromToken, Address toToken, Address sender, } // Send the trader their funds + Context.call(toToken, "transfer", receiver, value); Swap(BigInteger.valueOf(0), fromToken, fromToken, toToken, sender, receiver, value, value, diff --git a/dummy/Router/build.gradle b/dummy/Router/build.gradle index 3a5641d7..7c596974 100644 --- a/dummy/Router/build.gradle +++ b/dummy/Router/build.gradle @@ -1,19 +1,8 @@ version = '0.9.1' dependencies { - compileOnly 'foundation.icon:javaee-api:0.9.1' implementation project(':score-lib') - - implementation 'com.github.sink772:javaee-tokens:0.6.1' - implementation 'com.github.sink772:minimal-json:0.9.6' - - testImplementation 'foundation.icon:javaee-unittest:0.9.2' - implementation 'org.mockito:mockito-core:4.3.1' - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' - testImplementation('org.mockito:mockito-inline:4.3.1') - implementation 'foundation.icon:javaee-scorex:0.5.2' - + testImplementation project(':test-lib') } optimizedJar { @@ -33,16 +22,11 @@ deployJar { uri = 'http://localhost:9082/api/v3' nid = 0x3 } - sejong { - uri = 'https://sejong.net.solidwallet.io/api/v3' - nid = 0x53 - - } - berlin { - uri = 'https://berlin.net.solidwallet.io/api/v3' - nid = 0x7 - to = 'cx28ae7ed3b07ed5247a3d2f97680f8555ce7c0a92' + devnet{ + uri = "https://tt.net.solidwallet.io/api/v3" + nid = 0x3 } + } keystore = rootProject.hasProperty('keystoreName') ? "$keystoreName" : '' password = rootProject.hasProperty('keystorePass') ? "$keystorePass" : '' diff --git a/dummy/Router/src/main/java/dummy/contract/router/Router.java b/dummy/Router/src/main/java/dummy/contract/router/Router.java index a8bcd4f7..0a53dd66 100644 --- a/dummy/Router/src/main/java/dummy/contract/router/Router.java +++ b/dummy/Router/src/main/java/dummy/contract/router/Router.java @@ -7,40 +7,47 @@ import score.annotation.Payable; import java.math.BigInteger; + import community.icon.cps.score.lib.interfaces.RouterInterface; public class Router implements RouterInterface { private static final String TAG = "Router"; - public Router(){} - private void route(Address from, Address startToken, Address[] _path, BigInteger _minReceive) { + public Router() { + } + + private void route(String from, Address startToken, Address[] _path, BigInteger _minReceive) { Address currentToken = _path[1]; BigInteger balance = (BigInteger) Context.call(currentToken, "balanceOf", Context.getAddress()); Context.require(balance.compareTo(_minReceive) >= 0, TAG + ": Below minimum receive amount of " + _minReceive); - Context.call(currentToken, "transfer", from, _minReceive); + Context.call(currentToken, "transfer", Address.fromString(from), _minReceive); } @Override @Payable @External - public void route(Address[] _path, @Optional BigInteger _minReceive) { + public void route(Address[] _path, @Optional BigInteger _minReceive, @Optional String _receiver) { if (_minReceive == null) { _minReceive = BigInteger.ZERO; } + if (_receiver == null || _receiver.equals("")) { + _receiver = Context.getCaller().toString(); + } + Context.require(_minReceive.signum() >= 0, TAG + ": Must specify a positive number for minimum to receive"); Context.require(_path.length <= 2, TAG + ": Passed max swaps of " + 2); - route(Context.getCaller(), null, _path, Context.getValue()); + route(_receiver, null, _path, Context.getValue()); } @External - public void tokenFallback(Address _from, BigInteger _value, byte[] _data){ + public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { } } diff --git a/dummy/bnUSD/build.gradle b/dummy/bnUSD/build.gradle index f752b4aa..5063bd83 100644 --- a/dummy/bnUSD/build.gradle +++ b/dummy/bnUSD/build.gradle @@ -1,13 +1,9 @@ -version = '0.9.1' +version = '0.0.1' dependencies { - compileOnly 'foundation.icon:javaee-api:0.9.2' - implementation 'com.github.sink772:javaee-tokens:0.6.1' + implementation project(':score-lib') - testImplementation 'foundation.icon:javaee-unittest:0.9.4' - testImplementation 'org.mockito:mockito-core:4.6.1' - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' + testImplementation project(':test-lib') } optimizedJar { @@ -27,6 +23,10 @@ deployJar { uri = 'http://localhost:9082/api/v3' nid = 0x3 } + devnet{ + uri = "https://tt.net.solidwallet.io/api/v3" + nid = 0x3 + } } keystore = rootProject.hasProperty('keystoreName') ? "$keystoreName" : '' password = rootProject.hasProperty('keystorePass') ? "$keystorePass" : '' @@ -34,7 +34,7 @@ deployJar { arg('_name', 'Balanced Dollar') arg('_symbol', 'bnUSD') arg('_decimals', '0x12') - arg('_initialSupply', '0x989680') + arg('_initialSupply', '0x152D02C7E14AF6800000') } } diff --git a/dummy/bnUSD/src/main/java/dummy/contract/bnusd/bnUSD.java b/dummy/bnUSD/src/main/java/dummy/contract/bnusd/bnUSD.java index 0c1560d2..e30aab2d 100644 --- a/dummy/bnUSD/src/main/java/dummy/contract/bnusd/bnUSD.java +++ b/dummy/bnUSD/src/main/java/dummy/contract/bnusd/bnUSD.java @@ -2,7 +2,9 @@ import community.icon.cps.score.lib.interfaces.bnUSDInterface; import community.icon.cps.score.lib.tokens.IRC2Base; +import score.Address; import score.Context; +import score.annotation.External; import java.math.BigInteger; @@ -12,7 +14,12 @@ public bnUSD(String _name, String _symbol, int _decimals, BigInteger _initialSup // mint the initial token supply here Context.require(_initialSupply.compareTo(BigInteger.ZERO) >= 0); - mint(Context.getCaller(), _initialSupply.multiply(pow10(_decimals))); + mint(Context.getCaller(), _initialSupply); + } + + @External + public void mintTo(Address to, BigInteger amount) { + mint(to, amount); } private static BigInteger pow10(int exponent) { diff --git a/dummy/oracle/build.gradle b/dummy/oracle/build.gradle index 9fde13bc..9a451779 100644 --- a/dummy/oracle/build.gradle +++ b/dummy/oracle/build.gradle @@ -1,18 +1,21 @@ version = '0.9.1' dependencies { - compileOnly 'foundation.icon:javaee-api:0.9.1' - implementation project(':score-lib') - - implementation 'com.github.sink772:javaee-tokens:0.6.1' - implementation 'com.github.sink772:minimal-json:0.9.6' +// compileOnly 'foundation.icon:javaee-api:0.9.1' +// implementation project(':score-lib') +// +// implementation 'com.github.sink772:javaee-tokens:0.6.1' +// implementation 'com.github.sink772:minimal-json:0.9.6' +// +// testImplementation 'foundation.icon:javaee-unittest:0.9.2' +// implementation 'org.mockito:mockito-core:4.3.1' +// testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2' +// testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' +// testImplementation('org.mockito:mockito-inline:4.3.1') +// implementation 'foundation.icon:javaee-scorex:0.5.2' - testImplementation 'foundation.icon:javaee-unittest:0.9.2' - implementation 'org.mockito:mockito-core:4.3.1' - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' - testImplementation('org.mockito:mockito-inline:4.3.1') - implementation 'foundation.icon:javaee-scorex:0.5.2' + implementation project(':score-lib') + testImplementation project(':test-lib') } @@ -33,14 +36,9 @@ deployJar { uri = 'http://localhost:9082/api/v3' nid = 0x3 } - sejong { - uri = 'https://sejong.net.solidwallet.io/api/v3' - nid = 0x53 - - } - berlin { - uri = 'https://berlin.net.solidwallet.io/api/v3' - nid = 0x7 + devnet{ + uri = "https://tt.net.solidwallet.io/api/v3" + nid = 0x3 } } keystore = rootProject.hasProperty('keystoreName') ? "$keystoreName" : '' diff --git a/dummy/oracle/src/main/java/dummy/contract/oracle/Oracle.java b/dummy/oracle/src/main/java/dummy/contract/oracle/Oracle.java index 5b86f2e0..028449d4 100644 --- a/dummy/oracle/src/main/java/dummy/contract/oracle/Oracle.java +++ b/dummy/oracle/src/main/java/dummy/contract/oracle/Oracle.java @@ -3,12 +3,13 @@ import score.annotation.External; import java.math.BigInteger; +import java.util.Map; public class Oracle { @External(readonly = true) - public BigInteger getReferenceData(String _base, String _quote) { - return BigInteger.ONE; + public Map get_reference_data(String _base, String _quote) { + return Map.of("rate",BigInteger.ONE); } diff --git a/dummy/sICX/build.gradle b/dummy/sICX/build.gradle index 4f993073..2b021494 100644 --- a/dummy/sICX/build.gradle +++ b/dummy/sICX/build.gradle @@ -1,13 +1,8 @@ version = '0.9.1' dependencies { - compileOnly 'foundation.icon:javaee-api:0.9.2' - implementation 'com.github.sink772:javaee-tokens:0.6.1' implementation project(':score-lib') - testImplementation 'foundation.icon:javaee-unittest:0.9.4' - testImplementation 'org.mockito:mockito-core:4.6.1' - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' + testImplementation project(':test-lib') } optimizedJar { @@ -27,14 +22,15 @@ deployJar { uri = 'http://localhost:9082/api/v3' nid = 0x3 } + devnet{ + uri = "https://tt.net.solidwallet.io/api/v3" + nid = 0x3 + } } keystore = rootProject.hasProperty('keystoreName') ? "$keystoreName" : '' password = rootProject.hasProperty('keystorePass') ? "$keystorePass" : '' parameters { - arg('_name', 'Staked ICX') - arg('_symbol', 'sICX') - arg('_decimals', '0x12') - arg('_initialSupply', '0x989680') + arg('_admin', 'hx2eec32d4469cbdc24fac4ea0c3859b7c3f2729ee') } } diff --git a/dummy/sICX/src/main/java/dummy/contract/sicx/sICX.java b/dummy/sICX/src/main/java/dummy/contract/sicx/sICX.java index 993e5c54..9511215b 100644 --- a/dummy/sICX/src/main/java/dummy/contract/sicx/sICX.java +++ b/dummy/sICX/src/main/java/dummy/contract/sicx/sICX.java @@ -1,26 +1,123 @@ package dummy.contract.sicx; -import com.iconloop.score.token.irc2.IRC2Basic; import community.icon.cps.score.lib.tokens.IRC2Base; +import score.annotation.External; +import score.Address; import score.Context; +import community.icon.cps.score.lib.interfaces.sICXInterface; +import score.VarDB; +import score.annotation.Optional; + import java.math.BigInteger; -public class sICX extends IRC2Base implements community.icon.cps.score.lib.interfaces.sICXInterface { - public sICX(String _name, String _symbol, int _decimals, BigInteger _initialSupply) { - super(_name, _symbol, BigInteger.valueOf(_decimals)); +public class sICX extends IRC2Base implements sICXInterface { + + private static final String TAG = "sICX"; + private static final String TOKEN_NAME = "Staked ICX"; + private static final String SYMBOL_NAME = "sICX"; + private static final BigInteger DECIMALS = BigInteger.valueOf(18); + private static final String STAKING = "staking"; + public static final String STATUS_MANAGER = "status_manager"; + private static final String VERSION = "version"; + private static final String SICX_VERSION = "v0.0.1"; + + static final Address ZERO_ADDRESS = new Address(new byte[Address.LENGTH]); + + private static final VarDB
stakingAddress = Context.newVarDB(STAKING, Address.class); + private final VarDB
statusManager = Context.newVarDB(STATUS_MANAGER, Address.class); + + private final VarDB currentVersion = Context.newVarDB(VERSION, String.class); + + public sICX(Address _admin) { + super(TOKEN_NAME, SYMBOL_NAME, DECIMALS); + if (stakingAddress.get() == null) { + stakingAddress.set(_admin); + } + + if (currentVersion.getOrDefault("").equals(SICX_VERSION)) { + Context.revert("Can't Update same version of code"); + } + currentVersion.set(SICX_VERSION); + } + + @External(readonly = true) + public String version() { + return currentVersion.getOrDefault(""); + } + + @External(readonly = true) + public String getPeg() { + return TAG; + } + + @External + public void setStaking(Address _address) { + onlyOwner(); + stakingAddress.set(_address); + } + + @External(readonly = true) + public Address getStaking() { + return stakingAddress.get(); + } + + @External + public void setEmergencyManager(Address _address) { + onlyOwner(); + statusManager.set(_address); + } + + @External(readonly = true) + public Address getEmergencyManager() { + return statusManager.get(); + } + + @External(readonly = true) + public BigInteger priceInLoop() { + return (BigInteger) Context.call(stakingAddress.get(), "getTodayRate"); + } + + @External(readonly = true) + public BigInteger lastPriceInLoop() { + return priceInLoop(); + } + + @External + public void govTransfer(Address _from, Address _to, BigInteger _value, @Optional byte[] _data) { + onlyOwner(); + _transfer(_from, _to, _value, _data); + } + + @Override + @External + public void transfer(Address _to, BigInteger _value, @Optional byte[] _data) { + _transfer(Context.getCaller(), _to, _value, _data); + } + + private void _transfer(Address _from, Address _to, BigInteger _value, @Optional byte[] _data) { + Address _stakingAddress = stakingAddress.get(); + +// if (!_to.equals(_stakingAddress)) { +// Context.call(_stakingAddress, "transferUpdateDelegations", _from, _to, _value); +// } + transfer(_from, _to, _value, _data); + } - // mint the initial token supply here - Context.require(_initialSupply.compareTo(BigInteger.ZERO) >= 0); - mint(Context.getCaller(), _initialSupply.multiply(pow10(_decimals))); + public static void onlyOwner() { + Address caller = Context.getCaller(); + Address owner = Context.getOwner(); + Context.require(caller.equals(owner), "SenderNotScoreOwner: Sender=" + caller + "Owner=" + owner); } - private static BigInteger pow10(int exponent) { - BigInteger result = BigInteger.ONE; - for (int i = 0; i < exponent; i++) { - result = result.multiply(BigInteger.TEN); + @External + public void mintWithTokenFallBack(Address _to, BigInteger _amount, byte[] _data){ + onlyOwner(); + mint(_to,_amount); + byte[] data = (_data == null) ? new byte[0] : _data; + if (_to.isContract()) { + Context.call(_to, "tokenFallback", ZERO_ADDRESS, _amount, data); } - return result; } } diff --git a/dummyJarFiles/Dex-0.9.1-optimized.jar b/dummyJarFiles/Dex-0.9.1-optimized.jar new file mode 100644 index 00000000..45befdee Binary files /dev/null and b/dummyJarFiles/Dex-0.9.1-optimized.jar differ diff --git a/dummyJarFiles/Router-0.9.1-optimized.jar b/dummyJarFiles/Router-0.9.1-optimized.jar new file mode 100644 index 00000000..7c4c1232 Binary files /dev/null and b/dummyJarFiles/Router-0.9.1-optimized.jar differ diff --git a/dummyJarFiles/Sicx-0.0.1-optimized.jar b/dummyJarFiles/Sicx-0.0.1-optimized.jar new file mode 100644 index 00000000..6e220f03 Binary files /dev/null and b/dummyJarFiles/Sicx-0.0.1-optimized.jar differ diff --git a/dummyJarFiles/bnUSD-0.9.1-optimized.jar b/dummyJarFiles/bnUSD-0.9.1-optimized.jar new file mode 100644 index 00000000..b0e7041f Binary files /dev/null and b/dummyJarFiles/bnUSD-0.9.1-optimized.jar differ diff --git a/dummyJarFiles/oracle-0.9.1-optimized.jar b/dummyJarFiles/oracle-0.9.1-optimized.jar new file mode 100644 index 00000000..1fcd2412 Binary files /dev/null and b/dummyJarFiles/oracle-0.9.1-optimized.jar differ diff --git a/jars/score-client-0.9.0.jar b/jars/score-client-0.9.0.jar new file mode 100644 index 00000000..e65a271c Binary files /dev/null and b/jars/score-client-0.9.0.jar differ diff --git a/score-client/build.gradle b/score-client/build.gradle deleted file mode 100644 index edbc0eda..00000000 --- a/score-client/build.gradle +++ /dev/null @@ -1,22 +0,0 @@ -apply plugin: 'java-library' - -optimizedJar.enabled = false - - -dependencies { - implementation("foundation.icon:javaee-annotation-processor:0.9.0") - implementation("com.squareup:javapoet:1.12.1") - implementation("foundation.icon:javaee-api:0.9.0") - implementation("foundation.icon:icon-sdk:2.0.0") - implementation("com.fasterxml.jackson.core:jackson-databind:2.9.6") - implementation("com.squareup.okhttp3:okhttp:3.11.0") - implementation("org.bouncycastle:bcprov-jdk15on:1.60") - - testImplementation("org.junit.jupiter:junit-jupiter-api:5.7.2") - testImplementation("org.junit.jupiter:junit-jupiter-params:5.7.2") - testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.7.2") -} - -test { - useJUnitPlatform() -} \ No newline at end of file diff --git a/score-client/src/main/java/foundation/icon/jsonrpc/Address.java b/score-client/src/main/java/foundation/icon/jsonrpc/Address.java deleted file mode 100644 index 48bea738..00000000 --- a/score-client/src/main/java/foundation/icon/jsonrpc/Address.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright 2021 ICON Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package foundation.icon.jsonrpc; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonValue; -import foundation.icon.icx.Wallet; - -import java.util.Arrays; - -public class Address extends score.Address { - public enum Type { - EOA("hx", 0x0), - CONTRACT("cx", 0x1); - String str; - byte value; - Type(String str, int value) { - this.str = str; - this.value = (byte)value; - } - String str() { - return str; - } - byte value() { - return value; - } - static Type of(byte value) { - for(Type type : values()) { - if (type.value == value) { - return type; - } - } - throw new IllegalArgumentException(); - } - static Type of(String str) { - for(Type type : values()) { - if (type.str.equals(str)) { - return type; - } - } - throw new IllegalArgumentException(); - } - } - public static final int LENGTH = 21; - public static final int BODY_LENGTH = LENGTH - 1; - private final Type type; - private final String str; - private final byte[] bytes; - - @JsonCreator - public Address(String str) { - this(parse(str)); - } - - public Address(byte[] bytes) throws IllegalArgumentException { - super(bytes); - if (bytes == null) { - throw new IllegalArgumentException("raw could not be null"); - } - if (bytes.length != LENGTH) { - throw new IllegalArgumentException("invalid length"); - } - type = Type.of(bytes[0]); - this.bytes = bytes; - this.str = type.str() + IconJsonModule.bytesToHex(bytes).substring(2); - } - - public Address(Type type, byte[] body) throws IllegalArgumentException { - this(concat(type.value(), body)); - } - - public boolean isContract() { - return Type.CONTRACT.equals(type); - } - - public static byte[] concat(byte type, byte[] body) { - byte[] copy = new byte[LENGTH]; - copy[0] = type; - System.arraycopy(body, 0, copy, 1, BODY_LENGTH); - return copy; - } - - public byte[] toByteArray() { - return Arrays.copyOf(bytes, LENGTH); - } - - @Override - public boolean equals(Object obj) { - return this == obj || - (obj instanceof score.Address && toString().equals(obj.toString())); - } - - @JsonValue - @Override - public String toString() { - return str; - } - - public static byte[] parse(String str) { - if (str == null) { - throw new IllegalArgumentException("string could not be null"); - } - if (str.length() != LENGTH * 2) { - throw new IllegalArgumentException("invalid length"); - } - byte[] bytes = new byte[LENGTH]; - bytes[0] = Type.of(str.substring(0, 2)).value(); - System.arraycopy(IconJsonModule.hexToBytes(str.substring(2)), 0, bytes, 1, BODY_LENGTH); - return bytes; - } - - public static Address of(Wallet wallet) { - return of(wallet.getAddress()); - } - - private static Address of(foundation.icon.icx.data.Address address) { - return new Address(address.toString()); - } - -} diff --git a/score-client/src/main/java/foundation/icon/jsonrpc/IconJsonModule.java b/score-client/src/main/java/foundation/icon/jsonrpc/IconJsonModule.java deleted file mode 100644 index fc81edc8..00000000 --- a/score-client/src/main/java/foundation/icon/jsonrpc/IconJsonModule.java +++ /dev/null @@ -1,454 +0,0 @@ -/* - * Copyright 2021 ICON Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package foundation.icon.jsonrpc; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.Version; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.core.util.VersionUtil; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JavaType; -import com.fasterxml.jackson.databind.JsonDeserializer; -import com.fasterxml.jackson.databind.JsonSerializer; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.module.SimpleModule; -import com.fasterxml.jackson.databind.type.TypeFactory; -import com.fasterxml.jackson.databind.util.Converter; - -import java.io.IOException; -import java.math.BigInteger; -import java.util.function.Function; - -public class IconJsonModule extends SimpleModule { - public final static Version VERSION = VersionUtil.parseVersion( - "0.1.0", "foundation.icon", "javaee-score-client" - ); - - public static final String BOOLEAN_TRUE = "0x1"; - public static final String BOOLEAN_FALSE = "0x0"; - public static final String HEX_PREFIX = "0x"; - public static final String NEG_HEX_PREFIX = "-0x"; - private final boolean isIncludeNonNull; - - public static final char[] HEX_CODES = "0123456789abcdef".toCharArray(); - - public static String bytesToHex(byte[] bytes) { - if (bytes == null) { - return ""; - } - StringBuilder r = new StringBuilder(bytes.length * 2); - for (byte b : bytes) { - r.append(HEX_CODES[(b >> 4) & 0xF]); - r.append(HEX_CODES[(b & 0xF)]); - } - return r.toString(); - } - - public static byte[] hexToBytes(String hexString) { - if (hexString == null) { - return null; - } - if (hexString.length() % 2 > 0) { - throw new IllegalArgumentException("hex cannot has odd length"); - } - int l = hexString.length()/2; - int j = 0; - byte[] bytes = new byte[l]; - for (int i = 0; i < l; i++) { - bytes[i] = (byte)((Character.digit(hexString.charAt(j++), 16) << 4) | - Character.digit(hexString.charAt(j++), 16) & 0xFF); - } - return bytes; - } - - public IconJsonModule() { - super(VERSION); - this.isIncludeNonNull = true; - init(); - } - - public IconJsonModule(boolean isIncludeNonNull) { - super(VERSION); - this.isIncludeNonNull = isIncludeNonNull; - init(); - } - - private void init() { - addSerializer(char.class, CharSerializer.CHAR); - addSerializer(Character.class, CharSerializer.CHAR); - addSerializer(byte.class, NumberSerializer.BYTE); - addSerializer(Byte.class, NumberSerializer.BYTE); - addSerializer(long.class, NumberSerializer.LONG); - addSerializer(Long.class, NumberSerializer.LONG); - addSerializer(int.class, NumberSerializer.INTEGER); - addSerializer(Integer.class, NumberSerializer.INTEGER); - addSerializer(short.class, NumberSerializer.SHORT); - addSerializer(Short.class, NumberSerializer.SHORT); - addSerializer(BigInteger.class, NumberSerializer.BIG_INTEGER); - addSerializer(boolean.class, BooleanSerializer.BOOLEAN); - addSerializer(Boolean.class, BooleanSerializer.BOOLEAN); - addSerializer(byte[].class, ByteArraySerializer.BYTE_ARRAY); - addSerializer(score.Address.class, AddressSerializer.SCORE_ADDRESS); -// addSerializer(foundation.icon.icx.data.Address.class, AddressSerializer.SDK_ADDRESS); - - addDeserializer(char.class, CharDeserializer.CHAR); - addDeserializer(Character.class, CharDeserializer.CHAR); - addDeserializer(byte.class, NumberDeserializer.BYTE); - addDeserializer(Byte.class, NumberDeserializer.BYTE); - addDeserializer(long.class, NumberDeserializer.LONG); - addDeserializer(Long.class, NumberDeserializer.LONG); - addDeserializer(int.class, NumberDeserializer.INTEGER); - addDeserializer(Integer.class, NumberDeserializer.INTEGER); - addDeserializer(short.class, NumberDeserializer.SHORT); - addDeserializer(Short.class, NumberDeserializer.SHORT); - addDeserializer(BigInteger.class, NumberDeserializer.BIG_INTEGER); - addDeserializer(boolean.class, BooleanDeserializer.BOOLEAN); - addDeserializer(Boolean.class, BooleanDeserializer.BOOLEAN); - addDeserializer(byte[].class, ByteArrayDeserializer.BYTE_ARRAY); - addDeserializer(score.Address.class, AddressDeserializer.SCORE_ADDRESS); -// addDeserializer(foundation.icon.icx.data.Address.class, AddressDeserializer.SDK_ADDRESS); - } - - @Override - public void setupModule(SetupContext context) { - super.setupModule(context); - if (isIncludeNonNull) { - JsonInclude.Value value = JsonInclude.Value.construct(JsonInclude.Include.NON_NULL, JsonInclude.Include.NON_NULL); - context.configOverride(Long.class).setInclude(value); - context.configOverride(Integer.class).setInclude(value); - context.configOverride(Short.class).setInclude(value); - context.configOverride(BigInteger.class).setInclude(value); - context.configOverride(Boolean.class).setInclude(value); - context.configOverride(byte[].class).setInclude(value); - } - } - - public static class NumberSerializer extends JsonSerializer implements Converter { - public static final NumberSerializer BYTE = new NumberSerializer<>(); - public static final NumberSerializer SHORT = new NumberSerializer<>(); - public static final NumberSerializer INTEGER = new NumberSerializer<>(); - public static final NumberSerializer LONG = new NumberSerializer<>(); - public static final NumberSerializer BIG_INTEGER = new NumberSerializer<>(); - - @Override - public String convert(T t) { - BigInteger bi; - if (t instanceof BigInteger) { - bi = (BigInteger) t; - } else { - bi = BigInteger.valueOf(t.longValue()); - } - String prefix = (bi.signum() == -1) ? NEG_HEX_PREFIX : HEX_PREFIX; - return prefix + bi.abs().toString(16); - } - - @Override - public JavaType getInputType(TypeFactory typeFactory) { - return typeFactory.constructType(new TypeReference(){}); - } - - @Override - public JavaType getOutputType(TypeFactory typeFactory) { - return typeFactory.constructType(String.class); - } - - @Override - public void serialize(T value, JsonGenerator gen, SerializerProvider serializers) throws IOException { - gen.writeString(convert(value)); - } - } - - public static class CharSerializer extends JsonSerializer implements Converter { - public static final CharSerializer CHAR = new CharSerializer(); - - @Override - public String convert(Character value) { - return NumberSerializer.INTEGER.convert((int)value); - } - - @Override - public JavaType getInputType(TypeFactory typeFactory) { - return typeFactory.constructType(Character.class); - } - - @Override - public JavaType getOutputType(TypeFactory typeFactory) { - return typeFactory.constructType(String.class); - } - - @Override - public void serialize(Character value, JsonGenerator gen, SerializerProvider serializers) throws IOException { - gen.writeString(convert(value)); - } - } - - public static class BooleanSerializer extends JsonSerializer implements Converter { - public static final BooleanSerializer BOOLEAN = new BooleanSerializer(); - - @Override - public String convert(Boolean value) { - return value ? BOOLEAN_TRUE : BOOLEAN_FALSE; - } - - @Override - public JavaType getInputType(TypeFactory typeFactory) { - return typeFactory.constructType(Boolean.class); - } - - @Override - public JavaType getOutputType(TypeFactory typeFactory) { - return typeFactory.constructType(String.class); - } - - @Override - public void serialize(Boolean value, JsonGenerator gen, SerializerProvider serializers) throws IOException { - if (value != null) { - gen.writeString(convert(value)); - } - } - } - - public static class ByteArraySerializer extends JsonSerializer implements Converter { - public static final ByteArraySerializer BYTE_ARRAY = new ByteArraySerializer(); - - @Override - public void serialize(byte[] value, JsonGenerator gen, SerializerProvider serializers) throws IOException { - gen.writeString(convert(value)); - } - - @Override - public String convert(byte[] value) { - return HEX_PREFIX + bytesToHex(value); - } - - @Override - public JavaType getInputType(TypeFactory typeFactory) { - return typeFactory.constructArrayType(byte.class); - } - - @Override - public JavaType getOutputType(TypeFactory typeFactory) { - return typeFactory.constructType(String.class); - } - } - - public static class AddressSerializer extends JsonSerializer implements Converter { - public static final AddressSerializer SCORE_ADDRESS = new AddressSerializer<>(); - public static final AddressSerializer SDK_ADDRESS = new AddressSerializer<>(); - - @Override - public String convert(T value) { - return value.toString(); - } - - @Override - public JavaType getInputType(TypeFactory typeFactory) { - return typeFactory.constructType(new TypeReference(){}); - } - - @Override - public JavaType getOutputType(TypeFactory typeFactory) { - return typeFactory.constructType(String.class); - } - - @Override - public void serialize(T address, JsonGenerator gen, SerializerProvider serializers) throws IOException { - gen.writeString(convert(address)); - } - } - - public static class NumberDeserializer extends JsonDeserializer implements Converter{ - public static final NumberDeserializer BYTE = new NumberDeserializer<>(BigInteger::byteValue); - public static final NumberDeserializer SHORT = new NumberDeserializer<>(BigInteger::shortValue); - public static final NumberDeserializer INTEGER = new NumberDeserializer<>(BigInteger::intValue); - public static final NumberDeserializer LONG = new NumberDeserializer<>(BigInteger::longValue); - public static final NumberDeserializer BIG_INTEGER = new NumberDeserializer<>(bi -> bi); - - private final Function parseFunc; - - public NumberDeserializer(Function parseFunc) { - this.parseFunc = parseFunc; - } - - @Override - public T convert(String s) { - if (s.startsWith(HEX_PREFIX)) { - return parseFunc.apply(new BigInteger(s.substring(2), 16)); - } else if (s.startsWith(NEG_HEX_PREFIX)) { - return parseFunc.apply(new BigInteger(s.substring(3), 16).negate()); - } else { -// throw new IllegalArgumentException(String.format("invalid prefix loc:%s", p.getCurrentLocation().toString())); - return parseFunc.apply(new BigInteger(s, 16)); - } - } - - @Override - public JavaType getInputType(TypeFactory typeFactory) { - return typeFactory.constructType(String.class); - } - - @Override - public JavaType getOutputType(TypeFactory typeFactory) { - return typeFactory.constructType(new TypeReference(){}); - } - - @SuppressWarnings("unchecked") - @Override - public T deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { - if (p.currentToken().isNumeric()) { - return parseFunc.apply(p.getBigIntegerValue()); - } else { - return convert(p.getValueAsString()); - } - } - } - - public static class CharDeserializer extends JsonDeserializer implements Converter { - public static final CharDeserializer CHAR = new CharDeserializer(); - - @Override - public Character convert(String value) { - return (char) NumberDeserializer.INTEGER.convert(value).intValue(); - } - - @Override - public JavaType getInputType(TypeFactory typeFactory) { - return typeFactory.constructType(Boolean.class); - } - - @Override - public JavaType getOutputType(TypeFactory typeFactory) { - return typeFactory.constructType(String.class); - } - - @Override - public Character deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { - if (p.currentToken().isNumeric()) { - return (char)p.getIntValue(); - } else { - return convert(p.getValueAsString()); - } - } - } - - public static class BooleanDeserializer extends JsonDeserializer implements Converter { - public static final BooleanDeserializer BOOLEAN = new BooleanDeserializer(); - - @Override - public Boolean convert(String value) { - if (BOOLEAN_TRUE.equals(value)) { - return Boolean.TRUE; - } else if (BOOLEAN_FALSE.equals(value)) { - return Boolean.FALSE; - } - throw new IllegalArgumentException("invalid value:"+value); - } - - @Override - public JavaType getInputType(TypeFactory typeFactory) { - return typeFactory.constructType(Boolean.class); - } - - @Override - public JavaType getOutputType(TypeFactory typeFactory) { - return typeFactory.constructType(String.class); - } - - @Override - public Boolean deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { - try{ - return convert(p.getValueAsString()); - } catch (IllegalArgumentException e) { - throw new IllegalArgumentException( - String.format("fail to deserialize loc:%s err:%s", - p.getCurrentLocation().toString(), e.getMessage()),e); - } - } - } - - public static class ByteArrayDeserializer extends JsonDeserializer implements Converter{ - public static final ByteArrayDeserializer BYTE_ARRAY = new ByteArrayDeserializer(); - - @Override - public byte[] deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { - try{ - return convert(p.getValueAsString()); - } catch (IllegalArgumentException e) { - throw new IllegalArgumentException( - String.format("fail to deserialize loc:%s err:%s", - p.getCurrentLocation().toString(), e.getMessage()),e); - } - } - - @Override - public byte[] convert(String s) { - if (s.length() % 2 == 0) { - if (s.startsWith(HEX_PREFIX)) { - s = s.substring(2); - } - return hexToBytes(s); - } else { - throw new IllegalArgumentException("hex string length must be even"); - } - } - - @Override - public JavaType getInputType(TypeFactory typeFactory) { - return typeFactory.constructType(String.class); - } - - @Override - public JavaType getOutputType(TypeFactory typeFactory) { - return typeFactory.constructArrayType(byte.class); - } - } - - public static class AddressDeserializer extends JsonDeserializer implements Converter { - public static final AddressDeserializer SCORE_ADDRESS = new AddressDeserializer<>(Address::new); - public static final AddressDeserializer SDK_ADDRESS = new AddressDeserializer<>(foundation.icon.icx.data.Address::new); - - private final Function parseFunc; - - public AddressDeserializer(Function parseFunc) { - this.parseFunc = parseFunc; - } - - @Override - public T convert(String value) { - return parseFunc.apply(value); - } - - @Override - public JavaType getInputType(TypeFactory typeFactory) { - return typeFactory.constructType(String.class); - } - - @Override - public JavaType getOutputType(TypeFactory typeFactory) { - return typeFactory.constructType(new TypeReference(){}); - } - - @Override - public T deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { - return convert(p.getValueAsString()); - } - } - -} diff --git a/score-client/src/main/java/foundation/icon/jsonrpc/JsonrpcClient.java b/score-client/src/main/java/foundation/icon/jsonrpc/JsonrpcClient.java deleted file mode 100644 index 4975e581..00000000 --- a/score-client/src/main/java/foundation/icon/jsonrpc/JsonrpcClient.java +++ /dev/null @@ -1,271 +0,0 @@ -/* - * Copyright 2021 ICON Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package foundation.icon.jsonrpc; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.JavaType; -import com.fasterxml.jackson.databind.JsonSerializer; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.fasterxml.jackson.databind.deser.std.NumberDeserializers; -import okhttp3.Headers; -import okhttp3.MediaType; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; -import okhttp3.ResponseBody; -import okio.BufferedSink; - -import java.io.IOException; - -public class JsonrpcClient { - public static MediaType APPLICATION_JSON = MediaType.parse("application/json"); - - protected final String endpoint; - protected final OkHttpClient httpClient; - protected final ObjectMapper mapper; - protected Headers customHeaders; - protected boolean dumpJson; - - public JsonrpcClient(String endpoint) { - this(endpoint, new OkHttpClient.Builder().build()); - } - - public JsonrpcClient(String endpoint, OkHttpClient httpClient) { - this(endpoint, httpClient, new ObjectMapper()); - } - - public JsonrpcClient(String endpoint, ObjectMapper mapper) { - this(endpoint, new OkHttpClient.Builder().build(), mapper); - } - - public JsonrpcClient(String endpoint, OkHttpClient httpClient, ObjectMapper mapper) { - this.endpoint = endpoint; - this.httpClient = httpClient; - this.mapper = mapper; - } - - public String endpoint() { - return endpoint; - } - - public OkHttpClient httpClient() { - return httpClient; - } - - public ObjectMapper mapper() { - return mapper; - } - - public boolean isDumpJson() { - return dumpJson; - } - - public void setDumpJson(boolean dumpJson) { - this.dumpJson = dumpJson; - } - - public Headers getCustomHeaders() { - return customHeaders; - } - - public void setCustomHeaders(Headers customHeaders) { - this.customHeaders = customHeaders; - } - - private Headers.Builder customHeadersBuilder() { - return customHeaders == null ? new Headers.Builder() : customHeaders.newBuilder(); - } - - public void addCustomHeader(String name) { - customHeaders = customHeadersBuilder().add(name).build(); - } - - public void addCustomHeader(String name, String value) { - customHeaders = customHeadersBuilder().add(name, value).build(); - } - - public void setCustomHeader(String name, String value) { - customHeaders = customHeadersBuilder().set(name, value).build(); - } - - public Object request(String method, Object param) { - return request(Object.class, method, param); - } - - public T request(Class resultType, String method, Object params) { - return request(mapper.getTypeFactory().constructType(resultType), method, params); - } - - public T request(TypeReference resultType, String method, Object params) { - return request(mapper.getTypeFactory().constructType(resultType), method, params); - } - - public T request(JavaType resultType, String method, Object params) { - Request.Builder builder = new Request.Builder() - .url(endpoint) - .post(new JsonrpcRequest(method, params, mapper, dumpJson)); - if (customHeaders != null) { - builder.headers(customHeaders); - } - return request(builder.build(), resultType); - } - - protected T request(Request request, JavaType resultType) { - Response response = null; - try { - response = httpClient.newCall(request).execute(); - } catch (IOException e) { - throw new RuntimeException(e); - } - ResponseBody responseBody = response.body(); - if (responseBody != null) { - JsonrpcResponse jsonrpcResponse = null; - try { - String json = responseBody.string(); - if (dumpJson) { - System.out.println(json); - } - jsonrpcResponse = mapper.readValue(json, - mapper.getTypeFactory().constructParametricType(JsonrpcResponse.class, resultType)); - } catch (IOException e) { - throw new RuntimeException(e); - } - JsonrpcError error = jsonrpcResponse.getError(); - if (error != null) { - throw error; - } - return jsonrpcResponse.result; - } else { - throw new RuntimeException("empty body"); - } - } - - public static class JsonrpcRequest extends RequestBody { - @JsonIgnore - ObjectMapper mapper; - @JsonIgnore - boolean dumpJson; - String jsonrpc = "2.0"; - @JsonSerialize(using = LongLikeSerializer.class) - @JsonDeserialize(using = NumberDeserializers.NumberDeserializer.class) - long id; - String method; - @JsonInclude(JsonInclude.Include.NON_NULL) - Object params; - - JsonrpcRequest(String method, Object params, ObjectMapper mapper, boolean dumpJson) { - this.id = System.currentTimeMillis(); - this.method = method; - this.params = params; - this.mapper = mapper; - this.dumpJson = dumpJson; - } - - @Override - public MediaType contentType() { - return APPLICATION_JSON; - } - - @Override - public void writeTo(BufferedSink bufferedSink) throws IOException { - if (dumpJson) { - byte[] bytes = mapper.writeValueAsBytes(this); - bufferedSink.write(bytes); - System.out.println(new String(bytes)); - } else { - mapper.writeValue(bufferedSink.outputStream(), this); - } - } - - public String getJsonrpc() { - return jsonrpc; - } - - public long getId() { - return id; - } - - public String getMethod() { - return method; - } - - public Object getParams() { - return params; - } - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static class JsonrpcResponse { - String jsonrpc = "2.0"; - @JsonSerialize(using = LongLikeSerializer.class) - @JsonDeserialize(using = NumberDeserializers.NumberDeserializer.class) - long id; - T result; - JsonrpcError error; - - public String getJsonrpc() { - return jsonrpc; - } - - public long getId() { - return id; - } - - public T getResult() { - return result; - } - - public JsonrpcError getError() { - return error; - } - } - - public static class JsonrpcError extends RuntimeException { - @JsonSerialize(using = LongLikeSerializer.class) - @JsonDeserialize(using = NumberDeserializers.NumberDeserializer.class) - private long code; - private String message; - private byte[] data; - - public long getCode() { - return code; - } - - public String getMessage() { - return message; - } - - public byte[] getData() { - return data; - } - } - - public static class LongLikeSerializer extends JsonSerializer { - @Override - public void serialize(Long aLong, JsonGenerator gen, SerializerProvider serializers) throws IOException { - gen.writeNumber(((Number) aLong).intValue()); - } - } -} diff --git a/score-client/src/main/java/foundation/icon/jsonrpc/SendTransactionParamSerializer.java b/score-client/src/main/java/foundation/icon/jsonrpc/SendTransactionParamSerializer.java deleted file mode 100644 index 898ea823..00000000 --- a/score-client/src/main/java/foundation/icon/jsonrpc/SendTransactionParamSerializer.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2021 ICON Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package foundation.icon.jsonrpc; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; -import foundation.icon.jsonrpc.model.SendTransactionParam; - -import java.io.IOException; -import java.util.Collection; -import java.util.Map; -import java.util.StringJoiner; -import java.util.TreeSet; - -public class SendTransactionParamSerializer { - static final String PREFIX = "icx_sendTransaction."; - - static ObjectMapper iconMapper = new ObjectMapper(); - static { - iconMapper.registerModule(new IconJsonModule()); - iconMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); - } - static ObjectMapper mapper = new ObjectMapper(); - - public static String serialize(SendTransactionParam sendTransactionParam) throws IOException { - return serialize(sendTransactionParam, null); - } - - public static String serialize(SendTransactionParam sendTransactionParam, Map buffer) throws IOException { - String json = iconMapper.writeValueAsString(sendTransactionParam); - Map params = mapper.readValue(json, new TypeReference>() {}); - if (buffer != null) { - buffer.putAll(params); - } - return PREFIX + serializeMap(params); - } - - public static String serializeObject(Object object) { - if (object == null) { - return "\\0"; - } else if (object instanceof Map) { - // noinspection unchecked - return "{" + serializeMap((Map) object) + "}"; - } else if (object instanceof Collection) { - return "[" + serializeArray(object) + "]"; - } else if (object instanceof String) { - return escape((String) object); - } else { - throw new RuntimeException(String.format("not supported class:%s", object.getClass().getName())); - } - } - - public static String serializeMap(Map map) { - StringJoiner joiner = new StringJoiner("."); - TreeSet keys = new TreeSet<>(map.keySet()); - for (String key : keys) { - joiner.add(key); - joiner.add(serializeObject(map.get(key))); - } - return joiner.toString(); - } - - public static String serializeArray(Object arrayOrCollection) { - StringJoiner joiner = new StringJoiner("."); - if (arrayOrCollection instanceof Collection) { - Collection collection = ((Collection) arrayOrCollection); - for (Object element : collection) { - joiner.add(serializeObject(element)); - } - } else { - throw new RuntimeException(String.format("not supported class:%s", arrayOrCollection.getClass().getName())); - } - return joiner.toString(); - } - - public static String escape(String string) { - return string.replaceAll("([\\\\.{}\\[\\]])", "\\\\$1"); - } - -} diff --git a/score-client/src/main/java/foundation/icon/jsonrpc/model/AbstractTransaction.java b/score-client/src/main/java/foundation/icon/jsonrpc/model/AbstractTransaction.java deleted file mode 100644 index a86f2f75..00000000 --- a/score-client/src/main/java/foundation/icon/jsonrpc/model/AbstractTransaction.java +++ /dev/null @@ -1,76 +0,0 @@ -package foundation.icon.jsonrpc.model; - -import com.fasterxml.jackson.annotation.JsonInclude; -import foundation.icon.jsonrpc.Address; - -import java.math.BigInteger; - -public abstract class AbstractTransaction { - protected BigInteger version = new BigInteger("3"); - protected Address from; - protected Address to; - @JsonInclude(JsonInclude.Include.NON_NULL) - protected BigInteger value; - protected BigInteger timestamp; - protected BigInteger nid; - @JsonInclude(JsonInclude.Include.NON_NULL) - protected BigInteger nonce; - @JsonInclude(JsonInclude.Include.NON_NULL) - protected String dataType; - @JsonInclude(JsonInclude.Include.NON_NULL) - protected Object data; - - public BigInteger getVersion() { - return version; - } - - public Address getFrom() { - return from; - } - - public Address getTo() { - return to; - } - - public BigInteger getValue() { - return value; - } - - public BigInteger getTimestamp() { - return timestamp; - } - - public BigInteger getNid() { - return nid; - } - - public BigInteger getNonce() { - return nonce; - } - - public String getDataType() { - return dataType; - } - - public Object getData() { - return data; - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder("AbstractTransaction{"); - sb.append("version=").append(version); - sb.append(", from=").append(from); - sb.append(", to=").append(to); - sb.append(", value=").append(value); - sb.append(", timestamp=").append(timestamp); - sb.append(", nid=").append(nid); - sb.append(", nonce=").append(nonce); - sb.append(", dataType='").append(dataType).append('\''); - sb.append(", data=").append(data); - sb.append('}'); - return sb.toString(); - } - -} - diff --git a/score-client/src/main/java/foundation/icon/jsonrpc/model/CallData.java b/score-client/src/main/java/foundation/icon/jsonrpc/model/CallData.java deleted file mode 100644 index 27e909a2..00000000 --- a/score-client/src/main/java/foundation/icon/jsonrpc/model/CallData.java +++ /dev/null @@ -1,37 +0,0 @@ -package foundation.icon.jsonrpc.model; - -import java.util.Map; -import java.util.Objects; - -public class CallData { - private String method; - private Map params; - - public CallData(String method, Map params) { - Objects.requireNonNull(method, "method required not null"); - if (method.isEmpty()) { - throw new IllegalArgumentException("method required not empty"); - } - this.method = method; - this.params = params; - } - - public String getMethod() { - return method; - } - - public Map getParams() { - return params; - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder("CallData{"); - sb.append("method='").append(method).append('\''); - sb.append(", params=").append(params); - sb.append('}'); - return sb.toString(); - } -} - - diff --git a/score-client/src/main/java/foundation/icon/jsonrpc/model/CallParam.java b/score-client/src/main/java/foundation/icon/jsonrpc/model/CallParam.java deleted file mode 100644 index fe44e131..00000000 --- a/score-client/src/main/java/foundation/icon/jsonrpc/model/CallParam.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2021 ICON Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package foundation.icon.jsonrpc.model; - -import foundation.icon.jsonrpc.Address; - -public class CallParam { - private Address to; - private String dataType = "call"; - private CallData data; - - public CallParam(Address to, CallData data) { - this.to = to; - this.data = data; - } - - public Address getTo() { - return to; - } - - public String getDataType() { - return dataType; - } - - public CallData getData() { - return data; - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder("CallParam{"); - sb.append("to=").append(to); - sb.append(", dataType='").append(dataType).append('\''); - sb.append(", data=").append(data); - sb.append('}'); - return sb.toString(); - } -} diff --git a/score-client/src/main/java/foundation/icon/jsonrpc/model/DeployData.java b/score-client/src/main/java/foundation/icon/jsonrpc/model/DeployData.java deleted file mode 100644 index c3bd4aa5..00000000 --- a/score-client/src/main/java/foundation/icon/jsonrpc/model/DeployData.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2021 ICON Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package foundation.icon.jsonrpc.model; - -import foundation.icon.jsonrpc.IconJsonModule; - -import java.util.Map; -import java.util.Objects; - -public class DeployData { - private String contentType; - private byte[] content; - private Map params; - - public DeployData(String contentType, byte[] content, Map params) { - Objects.requireNonNull(contentType, "contentType required not null"); - if (contentType.isEmpty()) { - throw new IllegalArgumentException("contentType required not empty"); - } - Objects.requireNonNull(content, "content required not null"); - if (content.length == 0) { - throw new IllegalArgumentException("content required not empty"); - } - this.contentType = contentType; - this.content = content; - this.params = params; - } - - public String getContentType() { - return contentType; - } - - public byte[] getContent() { - return content; - } - - public Map getParams() { - return params; - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder("DeployData{"); - sb.append("contentType='").append(contentType).append('\''); - sb.append(", content=").append(IconJsonModule.bytesToHex(content)); - sb.append(", params=").append(params); - sb.append('}'); - return sb.toString(); - } -} diff --git a/score-client/src/main/java/foundation/icon/jsonrpc/model/Hash.java b/score-client/src/main/java/foundation/icon/jsonrpc/model/Hash.java deleted file mode 100644 index d7544148..00000000 --- a/score-client/src/main/java/foundation/icon/jsonrpc/model/Hash.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2021 ICON Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package foundation.icon.jsonrpc.model; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonValue; -import foundation.icon.jsonrpc.IconJsonModule; - - -public class Hash { - public static final String HEX_PREFIX = "0x"; - - private final byte[] bytes; - - public Hash(byte[] bytes) { - if (bytes == null) { - throw new IllegalArgumentException("bytes could not be null"); - } - this.bytes = bytes; - } - - @JsonCreator - public Hash(String string) { - if (string == null) { - throw new IllegalArgumentException("string could not be null"); - } - if (string.startsWith(HEX_PREFIX)) { - string = string.substring(2); - } - this.bytes = IconJsonModule.hexToBytes(string); - } - - public byte[] toBytes() { - return bytes; - } - - @JsonValue - @Override - public String toString() { - return HEX_PREFIX + IconJsonModule.bytesToHex(bytes); - } -} diff --git a/score-client/src/main/java/foundation/icon/jsonrpc/model/SendTransactionParam.java b/score-client/src/main/java/foundation/icon/jsonrpc/model/SendTransactionParam.java deleted file mode 100644 index 31482694..00000000 --- a/score-client/src/main/java/foundation/icon/jsonrpc/model/SendTransactionParam.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2021 ICON Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package foundation.icon.jsonrpc.model; - -import foundation.icon.jsonrpc.Address; - -import java.math.BigInteger; -import java.util.Objects; - -public class SendTransactionParam extends TransactionParam { - private BigInteger stepLimit; - - public SendTransactionParam(BigInteger nid, Address to, BigInteger value, String dataType, Object data) { - super(nid, to, value, dataType, data); - Objects.requireNonNull(nid, "nid required not null"); - Objects.requireNonNull(to, "to Address required not null"); - if (value != null && value.signum() == -1) { - throw new IllegalArgumentException("nid must be positive"); - } - } - - public BigInteger getStepLimit() { - return stepLimit; - } - - public void setStepLimit(BigInteger stepLimit) { - this.stepLimit = stepLimit; - } - - public void setFrom(Address from) { - this.from = from; - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder("SendTransactionParam{"); - sb.append("stepLimit=").append(stepLimit); - sb.append(", version=").append(version); - sb.append(", from=").append(from); - sb.append(", to=").append(to); - sb.append(", value=").append(value); - sb.append(", timestamp=").append(timestamp); - sb.append(", nid=").append(nid); - sb.append(", nonce=").append(nonce); - sb.append(", dataType='").append(dataType).append('\''); - sb.append(", data=").append(data); - sb.append('}'); - return sb.toString(); - } -} diff --git a/score-client/src/main/java/foundation/icon/jsonrpc/model/TransactionParam.java b/score-client/src/main/java/foundation/icon/jsonrpc/model/TransactionParam.java deleted file mode 100644 index 28ae9e75..00000000 --- a/score-client/src/main/java/foundation/icon/jsonrpc/model/TransactionParam.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2021 ICON Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package foundation.icon.jsonrpc.model; - -import foundation.icon.jsonrpc.Address; - -import java.math.BigInteger; - -public class TransactionParam extends AbstractTransaction { - public static final BigInteger TIMESTAMP_MSEC_SCALE = BigInteger.valueOf(1000); - public static BigInteger currentTimestamp() { - return TIMESTAMP_MSEC_SCALE.multiply(BigInteger.valueOf(System.currentTimeMillis())); - } - - public TransactionParam(BigInteger nid, Address to, BigInteger value, String dataType, Object data) { - super(); - this.nid = nid; - this.to = to; - this.value = value; - this.dataType = dataType; - this.data = data; - } - - public void setFrom(Address from) { - this.from = from; - } - - public void setTimestamp(BigInteger timestamp) { - this.timestamp = timestamp; - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder("TransactionParam{"); - sb.append("version=").append(version); - sb.append(", from=").append(from); - sb.append(", to=").append(to); - sb.append(", value=").append(value); - sb.append(", timestamp=").append(timestamp); - sb.append(", nid=").append(nid); - sb.append(", nonce=").append(nonce); - sb.append(", dataType='").append(dataType).append('\''); - sb.append(", data=").append(data); - sb.append('}'); - return sb.toString(); - } -} diff --git a/score-client/src/main/java/foundation/icon/jsonrpc/model/TransactionResult.java b/score-client/src/main/java/foundation/icon/jsonrpc/model/TransactionResult.java deleted file mode 100644 index c9adb3d6..00000000 --- a/score-client/src/main/java/foundation/icon/jsonrpc/model/TransactionResult.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright 2021 ICON Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package foundation.icon.jsonrpc.model; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import foundation.icon.jsonrpc.Address; -import foundation.icon.jsonrpc.IconJsonModule; - -import java.math.BigInteger; -import java.util.List; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class TransactionResult { - private Address to; - private BigInteger cumulativeStepUsed; - private BigInteger stepUsed; - private BigInteger stepPrice; - private List eventLogs; - private byte[] logsBloom; - private BigInteger status; - @JsonInclude(JsonInclude.Include.NON_NULL) - private Failure failure; - @JsonInclude(JsonInclude.Include.NON_NULL) - private Address scoreAddress; - private Hash blockHash; - private BigInteger blockHeight; - private BigInteger txIndex; - private Hash txHash; - @JsonInclude(JsonInclude.Include.NON_NULL) - private Object stepUsedDetails; //[]feePayment - - public Address getTo() { - return to; - } - - public BigInteger getCumulativeStepUsed() { - return cumulativeStepUsed; - } - - public BigInteger getStepUsed() { - return stepUsed; - } - - public BigInteger getStepPrice() { - return stepPrice; - } - - public List getEventLogs() { - return eventLogs; - } - - public byte[] getLogsBloom() { - return logsBloom; - } - - public BigInteger getStatus() { - return status; - } - - public Failure getFailure() { - return failure; - } - - public Address getScoreAddress() { - return scoreAddress; - } - - public Hash getBlockHash() { - return blockHash; - } - - public BigInteger getBlockHeight() { - return blockHeight; - } - - public BigInteger getTxIndex() { - return txIndex; - } - - public Hash getTxHash() { - return txHash; - } - - public Object getStepUsedDetails() { - return stepUsedDetails; - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder("TransactionResult{"); - sb.append("to=").append(to); - sb.append(", cumulativeStepUsed=").append(cumulativeStepUsed); - sb.append(", stepUsed=").append(stepUsed); - sb.append(", stepPrice=").append(stepPrice); - sb.append(", eventLogs=").append(eventLogs); - sb.append(", logsBloom=").append(IconJsonModule.bytesToHex(logsBloom)); - sb.append(", status=").append(status); - sb.append(", failure=").append(failure); - sb.append(", scoreAddress=").append(scoreAddress); - sb.append(", blockHash=").append(blockHash); - sb.append(", blockHeight=").append(blockHeight); - sb.append(", txIndex=").append(txIndex); - sb.append(", txHash=").append(txHash); - sb.append(", stepUsedDetails=").append(stepUsedDetails); - sb.append('}'); - return sb.toString(); - } - - public static class EventLog { - private Address scoreAddress; - private List indexed; - private List data; - - public Address getScoreAddress() { - return scoreAddress; - } - - public List getIndexed() { - return indexed; - } - - public List getData() { - return data; - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder("EventLog{"); - sb.append("scoreAddress=").append(scoreAddress); - sb.append(", indexed=").append(indexed); - sb.append(", data=").append(data); - sb.append('}'); - return sb.toString(); - } - } - - public static class Failure { - private BigInteger code; - private String message; - - public BigInteger getCode() { - return code; - } - - public String getMessage() { - return message; - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder("Failure{"); - sb.append("code=").append(code); - sb.append(", message='").append(message).append('\''); - sb.append('}'); - return sb.toString(); - } - } -} diff --git a/score-client/src/main/java/foundation/icon/score/client/DefaultScoreClient.java b/score-client/src/main/java/foundation/icon/score/client/DefaultScoreClient.java deleted file mode 100644 index 34593d68..00000000 --- a/score-client/src/main/java/foundation/icon/score/client/DefaultScoreClient.java +++ /dev/null @@ -1,510 +0,0 @@ -/* - * Copyright (c) 2022-2022 Balanced.network. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package foundation.icon.score.client; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.core.type.TypeReference; -import foundation.icon.icx.KeyWallet; -import foundation.icon.icx.Wallet; -import foundation.icon.icx.crypto.KeystoreException; -import foundation.icon.jsonrpc.Address; -import foundation.icon.jsonrpc.IconJsonModule; -import foundation.icon.jsonrpc.JsonrpcClient; -import foundation.icon.jsonrpc.SendTransactionParamSerializer; -import foundation.icon.jsonrpc.model.CallData; -import foundation.icon.jsonrpc.model.CallParam; -import foundation.icon.jsonrpc.model.DeployData; -import foundation.icon.jsonrpc.model.Hash; -import foundation.icon.jsonrpc.model.SendTransactionParam; -import foundation.icon.jsonrpc.model.TransactionParam; -import foundation.icon.jsonrpc.model.TransactionResult; -import org.bouncycastle.jcajce.provider.digest.SHA3; -import org.bouncycastle.util.encoders.Base64; -import score.UserRevertedException; - -import java.io.File; -import java.io.IOException; -import java.math.BigInteger; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.Properties; - -public class DefaultScoreClient extends JsonrpcClient { - public static final Address ZERO_ADDRESS = new Address("cx0000000000000000000000000000000000000000"); - public static final BigInteger DEFAULT_STEP_LIMIT = new BigInteger("9502f900", 16); - public static final long BLOCK_INTERVAL = 1; - public static final long DEFAULT_RESULT_RETRY_WAIT = 0; - public static final long DEFAULT_RESULT_TIMEOUT = 10000; - - protected final BigInteger nid; - protected final Wallet wallet; - protected final Address address; - protected BigInteger stepLimit = DEFAULT_STEP_LIMIT; - protected long resultTimeout = DEFAULT_RESULT_TIMEOUT; - - public DefaultScoreClient(String url, String nid, String keyStorePath, String keyStorePassword, String address) { - this(url, nid(nid), wallet(keyStorePath, keyStorePassword), new Address(address)); - } - - public DefaultScoreClient(String url, BigInteger nid, Wallet wallet, Address address) { - super(url); - initialize(this); - - this.nid = nid; - this.wallet = wallet; - this.address = address; - } - - public DefaultScoreClient(DefaultScoreClient client) { - super(client.endpoint); - initialize(this); - - this.nid = client._nid(); - this.wallet = client._wallet(); - this.address = client._address(); - this.stepLimit = client._stepLimit(); - this.resultTimeout = client._resultTimeout(); - } - - static void initialize(JsonrpcClient client) { - client.mapper().registerModule(new IconJsonModule()); - client.mapper().setSerializationInclusion(JsonInclude.Include.NON_NULL); - } - - public static DefaultScoreClient _deploy(String url, String nid, String keyStorePath, String keyStorePassword, String scoreFilePath, Map params) { - return _deploy(url, nid(nid), wallet(keyStorePath, keyStorePassword), scoreFilePath, params); - } - - public static DefaultScoreClient _deploy(String url, BigInteger nid, Wallet wallet, String scoreFilePath, Map params) { - JsonrpcClient client = new JsonrpcClient(url); - initialize(client); - Address address = deploy(client, nid, wallet, DEFAULT_STEP_LIMIT, ZERO_ADDRESS, scoreFilePath, params, DEFAULT_RESULT_TIMEOUT); - return new DefaultScoreClient(url, nid, wallet, address); - } - - public static Hash _deployAsync(String url, BigInteger nid, Wallet wallet, String scoreFilePath, Map params) { - JsonrpcClient client = new JsonrpcClient(url); - initialize(client); - return deployAsync(client, nid, wallet, DEFAULT_STEP_LIMIT, ZERO_ADDRESS, scoreFilePath, params); - } - - public static DefaultScoreClient getDeploymentResult(String url, BigInteger nid, Wallet wallet, Hash hash) { - JsonrpcClient client = new JsonrpcClient(url); - initialize(client); - TransactionResult txr = result(client, hash, DEFAULT_RESULT_TIMEOUT); - Address address = txr.getScoreAddress(); - return new DefaultScoreClient(url, nid, wallet, address); - } - - public void _update(String scoreFilePath, Map params) { - deploy(this, nid, wallet, DEFAULT_STEP_LIMIT, address, scoreFilePath, params, DEFAULT_RESULT_TIMEOUT); - } - - public BigInteger _nid() { - return nid; - } - - public Wallet _wallet() { - return wallet; - } - - public Address _address() { - return address; - } - - public BigInteger _stepLimit() { - return stepLimit; - } - - public void _stepLimit(BigInteger stepLimit) { - this.stepLimit = stepLimit; - } - - public long _resultTimeout() { - return resultTimeout; - } - - public void _resultTimeout(long resultTimeout) { - this.resultTimeout = resultTimeout; - } - - public T _call(Class responseType, String method, Map params) { - return call(this, responseType, address, method, params); - } - - public T _call(TypeReference responseType, String method, Map params) { - return call(this, responseType, address, method, params); - } - - public TransactionResult _send(String method, Map params) { - return send(this, nid, wallet, stepLimit, address, null, method, params, resultTimeout); - } - - public TransactionResult _send(BigInteger valueForPayable, String method, Map params) { - return send(this, nid, wallet, stepLimit, address, valueForPayable, method, params, resultTimeout); - } - - public TransactionResult _transfer(Address to, BigInteger value, String message) { - return transfer(this, nid, wallet, stepLimit, to, value, message, resultTimeout); - } - - public BigInteger _balance() { - return balance(this, address); - } - - public BigInteger _balance(Address address) { - return balance(this, address); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - static class BlockHeight { - BigInteger height; - - public BigInteger getHeight() { - return height; - } - } - - public BigInteger _lastBlockHeight() { - return lastBlock(this, BlockHeight.class).height; - } - - - public static DefaultScoreClient of(Properties properties) { - return of("", properties); - } - - public static DefaultScoreClient of(Properties properties, Map params) { - return of("", properties, params); - } - - public static DefaultScoreClient of(String prefix, Properties properties) { - return of(prefix, properties, null); - } - - public static DefaultScoreClient of(String prefix, Properties properties, Map params) { - String url = url(prefix, properties); - BigInteger nid = nid(prefix, properties); - Wallet wallet = wallet(prefix, properties); - Address address = address(prefix, properties); - String scoreFilePath = scoreFilePath(prefix, properties); - Map deployParams = params(prefix, properties, params); - if (address == null) { - System.out.printf("deploy prefix: %s, url: %s, nid: %s, keyStorePath: %s, scoreFilePath: %s, params: %s%n", - prefix, url, nid, wallet != null ? wallet.getAddress() : wallet, scoreFilePath, deployParams); - return _deploy(url, nid, wallet, scoreFilePath, deployParams); - } else { - System.out.printf("prefix: %s, url: %s, nid: %s, wallet: %s, address: %s%n", - prefix, url, nid, wallet != null ? wallet.getAddress() : wallet, address); - DefaultScoreClient client = new DefaultScoreClient(url, nid, wallet, address); - if (isUpdate(prefix, properties) && scoreFilePath != null && !scoreFilePath.isEmpty()) { - System.out.printf("update scoreFilePath: %s, params: %s%n", scoreFilePath, deployParams); - client._update(scoreFilePath, deployParams); - } - return client; - } - } - - public static String url(Properties properties) { - return url("", properties); - } - - public static String url(String prefix, Properties properties) { - return properties.getProperty(prefix+"url"); - } - - public static BigInteger nid(Properties properties) { - return nid("", properties); - } - - public static BigInteger nid(String prefix, Properties properties) { - return nid(properties.getProperty(prefix+"nid")); - } - - public static BigInteger nid(String nid) { - if (nid.startsWith("0x")) { - return new BigInteger(nid.substring(2), 16); - } else { - return new BigInteger(nid); - } - } - - public static Wallet wallet(Properties properties) { - return wallet("", properties); - } - - public static Wallet wallet(String prefix, Properties properties) { - String keyStore = properties.getProperty(prefix+"keyStore"); - if (keyStore == null || keyStore.isEmpty()) { - return null; - } - String keyPassword = properties.getProperty(prefix+"keyPassword"); - if (keyPassword == null || keyPassword.isEmpty()) { - String keySecret = properties.getProperty(prefix+"keySecret"); - try { - System.out.println("using keySecret "+keySecret); - keyPassword = Files.readString(Path.of(keySecret)); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - return wallet(keyStore, keyPassword); - } - - public static Wallet wallet(String keyStorePath, String keyStorePassword) { - try { - System.out.println("load wallet "+keyStorePath); - return KeyWallet.load(keyStorePassword, new File(keyStorePath)); - } catch (IOException | KeystoreException e) { - throw new RuntimeException(e); - } - } - - public static Address address(Properties properties) { - return address("", properties); - } - - public static Address address(String prefix, Properties properties) { - String address = properties.getProperty(prefix+"address"); - if (address == null || address.isEmpty()) { - return null; - } - return address(address); - } - - public static Address address(String address) { - return new Address(address); - } - - public static boolean isUpdate(Properties properties) { - return isUpdate("", properties); - } - - public static boolean isUpdate(String prefix, Properties properties) { - return Boolean.parseBoolean( - (String)properties.getOrDefault(prefix+"isUpdate", - Boolean.FALSE.toString())); - } - - public static String scoreFilePath(Properties properties) { - return scoreFilePath("", properties); - } - - public static String scoreFilePath(String prefix, Properties properties) { - return properties.getProperty(prefix+"scoreFilePath"); - } - - public static Map params(Properties properties) { - return params("", properties); - } - - public static Map params(String prefix, Properties properties) { - return params(prefix, properties, null); - } - - public static Map params(String prefix, Properties properties, Map overwrite) { - String paramsKey = prefix+"params."; - Map params = new HashMap<>(); - for(Map.Entry entry : properties.entrySet()) { - String key = ((String)entry.getKey()); - if (key.startsWith(paramsKey)) { - params.put(key.substring(paramsKey.length()), entry.getValue()); - } - } - if (overwrite != null) { - for(Map.Entry entry : overwrite.entrySet()) { - params.put(entry.getKey(), entry.getValue()); - } - } - return params.isEmpty() ? null : params; - } - - - public static CallData callData(String method, Map params) { - return new CallData(method, params != null && !params.isEmpty() ? params : null); - } - - public static T call( - JsonrpcClient client, Class responseType, Address address, - String method, Map params) { - return client.request(responseType, "icx_call", new CallParam(address, callData(method, params))); - } - - public static T call( - JsonrpcClient client, TypeReference responseType, Address address, - String method, Map params) { - return client.request(responseType, "icx_call", new CallParam(address, callData(method, params))); - } - - static Hash sendTransaction(JsonrpcClient client, Wallet wallet, SendTransactionParam sendTransactionParam) { - Objects.requireNonNull(client, "client required not null"); - Objects.requireNonNull(wallet, "wallet required not null"); - Objects.requireNonNull(wallet, "sendTransactionParam required not null"); - - sendTransactionParam.setFrom(Address.of(wallet)); - if (sendTransactionParam.getTimestamp() == null) { - sendTransactionParam.setTimestamp(TransactionParam.currentTimestamp()); - } - if (sendTransactionParam.getStepLimit() == null) { - sendTransactionParam.setStepLimit(DEFAULT_STEP_LIMIT); - } - if (sendTransactionParam.getNid() == null) { - throw new IllegalArgumentException("nid could not be null"); - } - - Map params = new HashMap<>(); - String serialized; - try { - serialized = SendTransactionParamSerializer.serialize(sendTransactionParam, params); - } catch (IOException e) { - throw new RuntimeException(e); - } - byte[] digest = new SHA3.Digest256().digest(serialized.getBytes(StandardCharsets.UTF_8)); - String signature = Base64.toBase64String(wallet.sign(digest)); - params.put("signature", signature); - return client.request(Hash.class, "icx_sendTransaction", params); - } - - static void waitBlockInterval() { - // System.out.printf("wait block interval %d msec%n", BLOCK_INTERVAL); - // try { - // Thread.sleep(BLOCK_INTERVAL); - // } catch (InterruptedException ie) { - // ie.printStackTrace(); - // } - } - - public static TransactionResult send( - JsonrpcClient client, BigInteger nid, Wallet wallet, BigInteger stepLimit, Address address, - BigInteger valueForPayable, String method, Map params, - long timeout) { - SendTransactionParam tx = new SendTransactionParam(nid, address, valueForPayable, "call", callData(method, params)); - Hash txh = sendTransaction(client, wallet, tx); - waitBlockInterval(); - System.out.println("tx hash is: "+txh); - return result(client, txh, timeout); - } - - public static Address deploy( - JsonrpcClient client, BigInteger nid, Wallet wallet, BigInteger stepLimit, Address address, - String scoreFilePath, Map params, - long timeout) { - - byte[] content; - try { - content = Files.readAllBytes(Path.of(scoreFilePath)); - } catch (IOException e) { - throw new RuntimeException(e); - } - String contentType; - if (scoreFilePath.endsWith(".jar")) { - contentType = "application/java"; - } else if (scoreFilePath.endsWith(".zip")) { - contentType = "application/zip"; - } else { - throw new RuntimeException("not supported score file"); - } - SendTransactionParam tx = new SendTransactionParam(nid, address,null,"deploy", new DeployData(contentType, content, params)); - Hash txh = sendTransaction(client, wallet, tx); - waitBlockInterval(); - TransactionResult txr = result(client, txh, timeout); - System.out.println("SCORE address: "+txr.getScoreAddress()); - return txr.getScoreAddress(); - } - - public static Hash deployAsync( - JsonrpcClient client, BigInteger nid, Wallet wallet, BigInteger stepLimit, Address address, - String scoreFilePath, Map params) { - byte[] content; - try { - content = Files.readAllBytes(Path.of(scoreFilePath)); - } catch (IOException e) { - throw new RuntimeException(e); - } - String contentType; - if (scoreFilePath.endsWith(".jar")) { - contentType = "application/java"; - } else if (scoreFilePath.endsWith(".zip")) { - contentType = "application/zip"; - } else { - throw new RuntimeException("not supported score file"); - } - - SendTransactionParam tx = new SendTransactionParam(nid, address,null,"deploy", new DeployData(contentType, content, params)); - return sendTransaction(client, wallet, tx); - } - - public static TransactionResult transfer( - JsonrpcClient client, BigInteger nid, Wallet wallet, BigInteger stepLimit, Address address, - BigInteger value, String message, long timeout) { - SendTransactionParam tx; - if (message != null) { - tx = new SendTransactionParam(nid, address, value, "message", message.getBytes(StandardCharsets.UTF_8)); - } else { - tx = new SendTransactionParam(nid, address, value, null, null); - } - Hash txh = sendTransaction(client, wallet, tx); - waitBlockInterval(); - return result(client, txh, timeout); - } - - public static TransactionResult result(JsonrpcClient client, Hash txh, long timeout) { - Map params = Map.of("txHash", txh); - long etime = System.currentTimeMillis() + timeout; - TransactionResult txr = null; - while(txr == null) { - try { - txr = client.request(TransactionResult.class, "icx_getTransactionResult", params); - } catch (JsonrpcError e) { - if (e.getCode() == -31002 /* pending */ - || e.getCode() == -31003 /* executing */ - || e.getCode() == -31004 /* not found */) { - if (timeout > 0 && System.currentTimeMillis() >= etime) { - throw new RuntimeException("timeout"); - } - } else { - throw new RuntimeException(e); - } - } - } - if (!BigInteger.ONE.equals(txr.getStatus())) { - TransactionResult.Failure failure = txr.getFailure(); - int revertCode = failure.getCode().intValue(); - String revertMessage = failure.getMessage(); - if (revertCode >= 32) { - throw new UserRevertedException(revertCode - 32, revertMessage); - } else { - throw new RevertedException(revertCode, revertMessage); - } - } - return txr; - } - - public static BigInteger balance(JsonrpcClient client, Address address) { - return client.request(BigInteger.class, "icx_getBalance", Map.of("address", address)); - } - - public static T lastBlock(JsonrpcClient client, Class blockType) { - return client.request(blockType, "icx_getLastBlock", null); - } - -} diff --git a/score-client/src/main/java/foundation/icon/score/client/RevertedException.java b/score-client/src/main/java/foundation/icon/score/client/RevertedException.java deleted file mode 100644 index b6af28d5..00000000 --- a/score-client/src/main/java/foundation/icon/score/client/RevertedException.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2021 ICON Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package foundation.icon.score.client; - -public class RevertedException extends score.RevertedException { - private int code; - public RevertedException(int code, String message) { - super(message); - this.code = code; - } - - public int getCode() { - return code; - } -} diff --git a/score-client/src/main/java/foundation/icon/score/client/ScoreClient.java b/score-client/src/main/java/foundation/icon/score/client/ScoreClient.java deleted file mode 100644 index 7ab6d42b..00000000 --- a/score-client/src/main/java/foundation/icon/score/client/ScoreClient.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2021 ICON Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package foundation.icon.score.client; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target({ElementType.TYPE, ElementType.FIELD}) -@Retention(RetentionPolicy.SOURCE) -public @interface ScoreClient { - String suffix() default "ScoreClient"; -} diff --git a/score-client/src/main/java/foundation/icon/score/client/ScoreClientProcessor.java b/score-client/src/main/java/foundation/icon/score/client/ScoreClientProcessor.java deleted file mode 100644 index d185410b..00000000 --- a/score-client/src/main/java/foundation/icon/score/client/ScoreClientProcessor.java +++ /dev/null @@ -1,425 +0,0 @@ -/* - * Copyright 2021 ICON Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package foundation.icon.score.client; - -import com.fasterxml.jackson.core.type.TypeReference; -import com.squareup.javapoet.ClassName; -import com.squareup.javapoet.CodeBlock; -import com.squareup.javapoet.JavaFile; -import com.squareup.javapoet.MethodSpec; -import com.squareup.javapoet.ParameterSpec; -import com.squareup.javapoet.ParameterizedTypeName; -import com.squareup.javapoet.TypeName; -import com.squareup.javapoet.TypeSpec; -import foundation.icon.annotation_processor.AbstractProcessor; -import foundation.icon.annotation_processor.ProcessorUtil; -import foundation.icon.icx.Wallet; -import foundation.icon.jsonrpc.Address; -import foundation.icon.jsonrpc.model.TransactionResult; -import score.annotation.EventLog; -import score.annotation.External; -import score.annotation.Payable; - -import javax.annotation.processing.Filer; -import javax.annotation.processing.ProcessingEnvironment; -import javax.annotation.processing.RoundEnvironment; -import javax.lang.model.SourceVersion; -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.Modifier; -import javax.lang.model.element.TypeElement; -import javax.lang.model.element.VariableElement; -import javax.lang.model.type.DeclaredType; -import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeMirror; -import java.io.IOException; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.Set; -import java.util.function.Consumer; - -public class ScoreClientProcessor extends AbstractProcessor { - static final String METHOD_OF = "_of"; - static final String PARAM_PROPERTEIS = "properties"; - static final String PARAM_PREFIX = "prefix"; - static final String METHOD_DEPLOY = "_deploy"; - static final String PARAM_URL = "url"; - static final String PARAM_NID = "nid"; - static final String PARAM_WALLET = "wallet"; - static final String PARAM_ADDRESS = "address"; - static final String PARAM_CLIENT = "client"; - static final String PARAM_SCORE_FILE_PATH = "scoreFilePath"; - static final String PARAM_PARAMS = "params"; - // - static final String PARAM_PAYABLE_VALUE = "valueForPayable"; - static final String PARAM_CONSUMER = "consumerFunc"; - static final String PARAM_STEP_LIMIT = "stepLimit"; - - @Override - public synchronized void init(ProcessingEnvironment processingEnv) { - super.init(processingEnv); - } - - @Override - public Set getSupportedAnnotationTypes() { - Set s = new HashSet<>(); - s.add(ScoreClient.class.getCanonicalName()); - return s; - } - - @Override - public SourceVersion getSupportedSourceVersion() { - return SourceVersion.latestSupported(); - } - - @Override - public boolean process(Set annotations, RoundEnvironment roundEnv) { - boolean ret = false; - for (TypeElement annotation : annotations) { - Set annotationElements = roundEnv.getElementsAnnotatedWith(annotation); - for (Element element : annotationElements) { - if (element.getKind().isInterface() || element.getKind().isClass() || element.getKind().isField()) { - messager.noteMessage("process %s %s", element.getKind(), element.asType(), element.getSimpleName()); - generateImplementClass(processingEnv.getFiler(), element); - ret = true; - } else { - throw new RuntimeException("not support"); - } - } - } - return ret; - } - - private void generateImplementClass(Filer filer, Element element) { - TypeElement typeElement; - if (element instanceof TypeElement) { - typeElement = (TypeElement) element; - } else if (element instanceof VariableElement) { - typeElement = super.getTypeElement(element.asType()); - } else { - throw new RuntimeException("not support"); - } - - ClassName elementClassName = ClassName.get(typeElement); - ScoreClient ann = element.getAnnotation(ScoreClient.class); - ClassName className = ClassName.get(elementClassName.packageName(), elementClassName.simpleName() + ann.suffix()); - TypeSpec typeSpec = typeSpec(className, typeElement); - JavaFile javaFile = JavaFile.builder(className.packageName(), typeSpec).build(); - try { - javaFile.writeTo(filer); - } catch (IOException e) { - messager.warningMessage("create javaFile error : %s", e.getMessage()); - } - } - - private TypeSpec typeSpec(ClassName className, TypeElement element) { - TypeSpec.Builder builder = TypeSpec - .classBuilder(className) - .addModifiers(Modifier.PUBLIC, Modifier.FINAL) - .superclass(DefaultScoreClient.class) - .addSuperinterfaces(ProcessorUtil.getSuperinterfaces(element)); - - if (element.getKind().isInterface()) { - builder.addSuperinterface(element.asType()); - builder.addMethod(deployMethodSpec(className, null)); - } - - //Constructor - builder.addMethod(MethodSpec.constructorBuilder() - .addModifiers(Modifier.PUBLIC) - .addParameter(ParameterSpec.builder(String.class, PARAM_URL).build()) - .addParameter(ParameterSpec.builder(BigInteger.class, PARAM_NID).build()) - .addParameter(ParameterSpec.builder(Wallet.class, PARAM_WALLET).build()) - .addParameter(ParameterSpec.builder(Address.class, PARAM_ADDRESS).build()) - .addStatement("super($L, $L, $L, $L)", - PARAM_URL, PARAM_NID, PARAM_WALLET, PARAM_ADDRESS).build()); - builder.addMethod(MethodSpec.constructorBuilder() - .addModifiers(Modifier.PUBLIC) - .addParameter(ParameterSpec.builder(DefaultScoreClient.class, PARAM_CLIENT).build()) - .addStatement("super($L)", PARAM_CLIENT).build()); - - //_of(Properties) - builder.addMethod(MethodSpec.methodBuilder(METHOD_OF) - .addModifiers(Modifier.PUBLIC, Modifier.STATIC) - .addParameter(ParameterSpec.builder(Properties.class, PARAM_PROPERTEIS).build()) - .addStatement("return _of(\"\", $L)", PARAM_PROPERTEIS) - .returns(className) - .build()); - //_of(String prefix, Properties) - builder.addMethod(MethodSpec.methodBuilder(METHOD_OF) - .addModifiers(Modifier.PUBLIC, Modifier.STATIC) - .addParameter(ParameterSpec.builder(String.class, PARAM_PREFIX).build()) - .addParameter(ParameterSpec.builder(Properties.class, PARAM_PROPERTEIS).build()) - .addStatement("return new $T($T.of($L, $L))", className, DefaultScoreClient.class, PARAM_PREFIX, PARAM_PROPERTEIS) - .returns(className) - .build()); - - builder.addMethods(overrideMethods(element)); - builder.addMethods(deployMethods(className, element)); - return builder.build(); - } - - private List overrideMethods(TypeElement element) { - List methods = new ArrayList<>(); - TypeMirror superClass = element.getSuperclass(); - if (!superClass.getKind().equals(TypeKind.NONE) && !superClass.toString().equals(Object.class.getName())) { - messager.noteMessage("superClass[kind:%s, name:%s]", superClass.getKind().name(), superClass.toString()); - List superMethods = overrideMethods(super.getTypeElement(element.getSuperclass())); - methods.addAll(superMethods); - } - - for (TypeMirror inf : element.getInterfaces()) { - TypeElement infElement = super.getTypeElement(inf); - List infMethods = overrideMethods(infElement); - methods.addAll(infMethods); - } - - boolean mustGenerate = element.getKind().isInterface(); - for (Element enclosedElement : element.getEnclosedElements()) { - if (ElementKind.METHOD.equals(enclosedElement.getKind()) && - ProcessorUtil.hasModifier(enclosedElement, Modifier.PUBLIC) && - !ProcessorUtil.hasModifier(enclosedElement, Modifier.STATIC)) { - ExecutableElement ee = (ExecutableElement) enclosedElement; - External external = ee.getAnnotation(External.class); - - if (external != null || mustGenerate) { - CodeBlock paramsCodeblock = paramsCodeblock(ee); - MethodSpec methodSpec = methodSpec(ee, paramsCodeblock); - addMethod(methods, methodSpec, element); - boolean isExternal = external != null ? - !external.readonly() : - methodSpec.returnType.equals(TypeName.VOID); - if (isExternal) { - addMethod(methods, consumerMethodSpec(methodSpec, paramsCodeblock, false), element); - if (ee.getAnnotation(Payable.class) != null) { - addMethod(methods, payableMethodSpec(methodSpec, paramsCodeblock), element); - addMethod(methods, consumerMethodSpec(methodSpec, paramsCodeblock, true), element); - } - } - } - } - } - return methods; - } - - private void addMethod(List methods, MethodSpec methodSpec, TypeElement element) { - if (methodSpec != null) { - MethodSpec conflictMethod = ProcessorUtil.getConflictMethod(methods, methodSpec); - if (conflictMethod != null) { - methods.remove(conflictMethod); - if (element.getKind().isInterface()) { - messager.warningMessage( - "Redeclare '%s %s(%s)' in %s", - conflictMethod.returnType.toString(), - conflictMethod.name, - ProcessorUtil.parameterSpecToString(conflictMethod.parameters), - element.getQualifiedName()); - } - } - methods.add(methodSpec); - } - } - - private CodeBlock paramsCodeblock(ExecutableElement element) { - if (element == null || element.getParameters() == null || element.getParameters().size() == 0) { - return null; - } - CodeBlock.Builder builder = CodeBlock.builder(); - builder.addStatement("$T<$T,$T> $L = new $T<>()", - Map.class, String.class, Object.class, PARAM_PARAMS, HashMap.class); - for (VariableElement ve : element.getParameters()) { - ParameterSpec ps = ParameterSpec.get(ve); - builder.addStatement("$L.put(\"$L\",$L)", PARAM_PARAMS, ps.name, ps.name); - } - return builder.build(); - } - - static Map wrapperTypeNames = Map.of( - TypeKind.BOOLEAN, TypeName.get(Boolean.class), - TypeKind.BYTE, TypeName.get(Boolean.class), - TypeKind.SHORT, TypeName.get(Byte.class), - TypeKind.INT, TypeName.get(Integer.class), - TypeKind.LONG, TypeName.get(Long.class), - TypeKind.CHAR, TypeName.get(Character.class), - TypeKind.FLOAT, TypeName.get(Float.class), - TypeKind.DOUBLE, TypeName.get(Double.class)); - - private MethodSpec methodSpec(ExecutableElement ee, CodeBlock paramsCodeblock) { - if (ee.getAnnotation(EventLog.class) != null) { - return notSupportedMethod(ee, "not supported EventLog method", null); - } - - String methodName = ee.getSimpleName().toString(); - TypeMirror returnType = ee.getReturnType(); - TypeName returnTypeName = TypeName.get(returnType); - External external = ee.getAnnotation(External.class); - - MethodSpec.Builder builder = MethodSpec - .methodBuilder(methodName) - .addModifiers(ProcessorUtil.getModifiers(ee, Modifier.ABSTRACT)) - .addParameters(ProcessorUtil.getParameterSpecs(ee)) - .returns(returnTypeName); -// .addAnnotation(Override.class); - - String params = "null"; - if (paramsCodeblock != null) { - builder.addCode(paramsCodeblock); - params = PARAM_PARAMS; - } - - boolean isVoid = returnTypeName.equals(TypeName.VOID); - boolean isExternal = external != null ? !external.readonly() : isVoid; - if (isExternal) { - if (isVoid) { - builder.addStatement("super._send(\"$L\", $L)", methodName, params); - if (ee.getAnnotation(Payable.class) != null) { - builder.addJavadoc("To payable, use $L($T $L, ...)", methodName, BigInteger.class, PARAM_PAYABLE_VALUE); - } - } else { - return notSupportedMethod(ee, "not supported response of writable method in ScoreClient", - CodeBlock.builder().add("$L($T<$T> $L, ...)", - methodName, Consumer.class, TransactionResult.class, PARAM_CONSUMER).build()); - } - } else { - if (!isVoid) { - if (returnType.getKind().isPrimitive()) { - builder.addStatement("return super._call($T.class, \"$L\", $L)", - wrapperTypeNames.get(returnType.getKind()), methodName, params); - } else { - if (returnType.getKind().equals(TypeKind.DECLARED) && - ((DeclaredType)returnType).getTypeArguments().size() > 0) { - builder.addStatement("return super._call(new $T<$T>(){}, \"$L\", $L)", - TypeReference.class, returnTypeName, methodName, params); - } else { - builder.addStatement("return super._call($T.class, \"$L\", $L)", - returnTypeName, methodName, params); - } - } - } else { - return notSupportedMethod(ee, "not supported, void of readonly method in ScoreClient", null); - } - } - return builder.build(); - } - - private MethodSpec payableMethodSpec(MethodSpec methodSpec, CodeBlock paramsCodeblock) { - MethodSpec.Builder builder = MethodSpec.methodBuilder(methodSpec.name) - .addModifiers(methodSpec.modifiers) - .addParameter(BigInteger.class, PARAM_PAYABLE_VALUE) - .addParameters(methodSpec.parameters) - .returns(TypeName.VOID); - - String params = "null"; - if (paramsCodeblock != null) { - builder.addCode(paramsCodeblock); - params = PARAM_PARAMS; - } - builder.addStatement("super._send($L, \"$L\", $L)", PARAM_PAYABLE_VALUE, methodSpec.name, params); - return builder.build(); - } - - private MethodSpec consumerMethodSpec(MethodSpec methodSpec, CodeBlock paramsCodeblock, boolean isPayable) { - MethodSpec.Builder builder = MethodSpec.methodBuilder(methodSpec.name) - .addModifiers(methodSpec.modifiers) - .addParameter(ParameterSpec.builder( - ParameterizedTypeName.get(Consumer.class, TransactionResult.class), PARAM_CONSUMER).build()) - .returns(TypeName.VOID); - - String params = "null"; - if (paramsCodeblock != null) { - builder.addCode(paramsCodeblock); - params = PARAM_PARAMS; - } - if (isPayable) { - builder.addParameter(BigInteger.class, PARAM_PAYABLE_VALUE) - .addStatement("$L.accept(super._send($L, \"$L\", $L))", - PARAM_CONSUMER, PARAM_PAYABLE_VALUE, methodSpec.name, params); - } else { - builder.addStatement("$L.accept(super._send(\"$L\", $L))", PARAM_CONSUMER, methodSpec.name, params); - } - return builder.addParameters(methodSpec.parameters).build(); - } - - private MethodSpec notSupportedMethod(ExecutableElement ee, String msg, CodeBlock instead) { - String methodName = ee.getSimpleName().toString(); - TypeName returnTypeName = TypeName.get(ee.getReturnType()); - return MethodSpec.methodBuilder(methodName) - .addModifiers(ProcessorUtil.getModifiers(ee, Modifier.ABSTRACT)) - .addParameters(ProcessorUtil.getParameterSpecs(ee)) - .returns(returnTypeName) - .addStatement("throw new $T(\"$L\")", RuntimeException.class, msg) - .addJavadoc("@deprecated Do not use this method, this is generated only for preventing compile error.\n Instead, use $L\n", - instead != null ? instead : "N/A") - .addJavadoc("@throws $L(\"$L\")", RuntimeException.class.getName(), msg) - .addAnnotation(Deprecated.class) - .build(); - } - - private List deployMethods(ClassName className, TypeElement element) { - List methods = new ArrayList<>(); - TypeMirror superClass = element.getSuperclass(); - if (!superClass.getKind().equals(TypeKind.NONE) && !superClass.toString().equals(Object.class.getName())) { - messager.noteMessage("superClass[kind:%s, name:%s]", superClass.getKind().name(), superClass.toString()); - List superMethods = deployMethods(className, super.getTypeElement(element.getSuperclass())); - methods.addAll(superMethods); - } - - for (Element enclosedElement : element.getEnclosedElements()) { - if (ElementKind.CONSTRUCTOR.equals(enclosedElement.getKind()) && - ProcessorUtil.hasModifier(enclosedElement, Modifier.PUBLIC)) { - methods.add(deployMethodSpec(className, (ExecutableElement) enclosedElement)); - } - } - return methods; - } - - private MethodSpec deployMethodSpec(ClassName className, ExecutableElement element) { - MethodSpec.Builder builder = MethodSpec.methodBuilder(METHOD_DEPLOY) - .addModifiers(Modifier.PUBLIC, Modifier.STATIC) - .addParameter(ParameterSpec.builder(String.class, PARAM_URL).build()) - .addParameter(ParameterSpec.builder(BigInteger.class, PARAM_NID).build()) - .addParameter(ParameterSpec.builder(Wallet.class, PARAM_WALLET).build()) - .addParameter(ParameterSpec.builder(String.class, PARAM_SCORE_FILE_PATH).build()) - .returns(className); - - if (element != null) { - builder.addParameters(ProcessorUtil.getParameterSpecs(element)); - } else { - builder.addParameter(ParameterSpec.builder( - ParameterizedTypeName.get(Map.class, String.class, Object.class), PARAM_PARAMS).build()); - } - - CodeBlock paramsCodeblock = paramsCodeblock(element); - if (paramsCodeblock != null) { - builder.addCode(paramsCodeblock); - } - builder - .addStatement("return new $T($T._deploy($L,$L,$L,$L,$L))", - className, DefaultScoreClient.class, - PARAM_URL, PARAM_NID, PARAM_WALLET, PARAM_SCORE_FILE_PATH, - paramsCodeblock != null || element == null ? PARAM_PARAMS : "null") - .build(); - return builder.build(); - } - -} diff --git a/score-client/src/main/java/foundation/icon/score/client/ScoreInterface.java b/score-client/src/main/java/foundation/icon/score/client/ScoreInterface.java deleted file mode 100644 index 7bfa3b1a..00000000 --- a/score-client/src/main/java/foundation/icon/score/client/ScoreInterface.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2021 ICON Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package foundation.icon.score.client; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target({ElementType.TYPE}) -@Retention(RetentionPolicy.SOURCE) -public @interface ScoreInterface { - String suffix() default "ScoreInterface"; - String addressGetter() default "_address"; -} diff --git a/score-client/src/main/java/foundation/icon/score/client/ScoreInterfaceProcessor.java b/score-client/src/main/java/foundation/icon/score/client/ScoreInterfaceProcessor.java deleted file mode 100644 index 70aa69c2..00000000 --- a/score-client/src/main/java/foundation/icon/score/client/ScoreInterfaceProcessor.java +++ /dev/null @@ -1,282 +0,0 @@ -/* - * Copyright 2021 ICON Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package foundation.icon.score.client; - -import com.squareup.javapoet.ClassName; -import com.squareup.javapoet.JavaFile; -import com.squareup.javapoet.MethodSpec; -import com.squareup.javapoet.ParameterSpec; -import com.squareup.javapoet.TypeName; -import com.squareup.javapoet.TypeSpec; -import foundation.icon.annotation_processor.AbstractProcessor; -import foundation.icon.annotation_processor.ProcessorUtil; -import score.Address; -import score.Context; -import score.annotation.EventLog; -import score.annotation.External; -import score.annotation.Payable; - -import javax.annotation.processing.Filer; -import javax.annotation.processing.ProcessingEnvironment; -import javax.annotation.processing.RoundEnvironment; -import javax.lang.model.SourceVersion; -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.Modifier; -import javax.lang.model.element.TypeElement; -import javax.lang.model.element.VariableElement; -import javax.lang.model.type.DeclaredType; -import javax.lang.model.type.TypeKind; -import javax.lang.model.type.TypeMirror; -import java.io.IOException; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.StringJoiner; - -/* - * TODO generate exception each Method - * GenericPredefinedException - * - Status.OutOfStep - * - Status.StackOverflow - * handle IllegalArgumentException - * - Status.ContractNotFound - * - Status.MethodNotFound - * - Status.MethodNotPayable - * - Status.InvalidParameter - * - Status.OutOfBalance - * - Status.PackageError - * handle RevertedException - * - Status.UnknownFailure - * - s < Status.UserReversionStart - * handle UserRevertedException - * - Status.UserReversionStart <= s < Status.UserReversionEnd - * - * Exception extends score.UserRevertException - * Exception extends Exception - */ -public class ScoreInterfaceProcessor extends AbstractProcessor { - static final String MEMBER_ADDRESS = "address"; - static final String PARAM_PAYABLE_VALUE = "valueForPayable"; - - @Override - public synchronized void init(ProcessingEnvironment processingEnv) { - super.init(processingEnv); - } - - @Override - public Set getSupportedAnnotationTypes() { - Set s = new HashSet<>(); - s.add(ScoreInterface.class.getCanonicalName()); - return s; - } - - @Override - public SourceVersion getSupportedSourceVersion() { - return SourceVersion.latestSupported(); - } - - @Override - public boolean process(Set annotations, RoundEnvironment roundEnv) { - boolean ret = false; - for (TypeElement annotation : annotations) { - Set annotationElements = roundEnv.getElementsAnnotatedWith(annotation); - for (Element element : annotationElements) { - if (element.getKind().isInterface() || element.getKind().isClass()) { - messager.noteMessage("process %s %s", element.getKind(), element.asType(), element.getSimpleName()); - generateImplementClass(processingEnv.getFiler(), (TypeElement) element); - ret = true; - } else { - throw new RuntimeException("not support"); - } - } - } - return ret; - } - - private void generateImplementClass(Filer filer, TypeElement element) { - ClassName interfaceClassName = ClassName.get(element); - TypeSpec typeSpec = typeSpec(element); - JavaFile javaFile = JavaFile.builder(interfaceClassName.packageName(), typeSpec).build(); - try { - javaFile.writeTo(filer); - } catch (IOException e) { - e.printStackTrace(); - } - } - - private TypeSpec typeSpec(TypeElement element) { - ClassName interfaceClassName = ClassName.get(element); - ScoreInterface scoreInterface = element.getAnnotation(ScoreInterface.class); - ClassName className = ClassName.get(interfaceClassName.packageName(), interfaceClassName.simpleName() + scoreInterface.suffix()); - TypeSpec.Builder builder = TypeSpec - .classBuilder(ClassName.get(interfaceClassName.packageName(), className.simpleName())) - .addModifiers(Modifier.PUBLIC, Modifier.FINAL); - - if (element.getKind().isInterface()) { - builder.addSuperinterface(element.asType()); - } - - //Fields - builder.addField(Address.class, MEMBER_ADDRESS, Modifier.PROTECTED, Modifier.FINAL); - - //Constructor - builder.addMethod(MethodSpec.constructorBuilder() - .addModifiers(Modifier.PUBLIC) - .addParameter(ParameterSpec.builder(Address.class, MEMBER_ADDRESS).build()) - .addStatement("this.$L = $L", MEMBER_ADDRESS, MEMBER_ADDRESS).build()); - - //addressGetter - builder.addMethod(MethodSpec.methodBuilder(scoreInterface.addressGetter()) - .addModifiers(Modifier.PUBLIC) - .returns(Address.class) - .addStatement("return this.$L", MEMBER_ADDRESS).build()); - - List methods = overrideMethods(element); - builder.addMethods(methods); - return builder.build(); - } - - private List overrideMethods(TypeElement element) { - List methods = new ArrayList<>(); - TypeMirror superClass = element.getSuperclass(); - if (!superClass.getKind().equals(TypeKind.NONE) && !superClass.toString().equals(Object.class.getName())) { - messager.noteMessage("superClass[kind:%s, name:%s]", superClass.getKind().name(), superClass.toString()); - List superMethods = overrideMethods(super.getTypeElement(element.getSuperclass())); - methods.addAll(superMethods); - } - - for (TypeMirror inf : element.getInterfaces()) { - TypeElement infElement = super.getTypeElement(inf); - List infMethods = overrideMethods(infElement); - methods.addAll(infMethods); - } - - boolean mustGenerate = element.getKind().isInterface(); - for (Element enclosedElement : element.getEnclosedElements()) { - if (ElementKind.METHOD.equals(enclosedElement.getKind()) && - ProcessorUtil.hasModifier(enclosedElement, Modifier.PUBLIC) && - !ProcessorUtil.hasModifier(enclosedElement, Modifier.STATIC)) { - ExecutableElement ee = (ExecutableElement) enclosedElement; - External external = ee.getAnnotation(External.class); - if (external != null || mustGenerate) { - MethodSpec methodSpec = methodSpec(ee, mustGenerate); - addMethod(methods, methodSpec, element); - if (external != null && !external.readonly() && ee.getAnnotation(Payable.class) != null) { - addMethod(methods, payableMethodSpec(ee, methodSpec), element); - } - } - } - } - return methods; - } - - private void addMethod(List methods, MethodSpec methodSpec, TypeElement element) { - if (methodSpec != null) { - MethodSpec conflictMethod = ProcessorUtil.getConflictMethod(methods, methodSpec); - if (conflictMethod != null) { - methods.remove(conflictMethod); - messager.warningMessage( - "Redeclare '%s %s(%s)' in %s", - conflictMethod.returnType.toString(), - conflictMethod.name, - ProcessorUtil.parameterSpecToString(conflictMethod.parameters), - element.getQualifiedName()); - } - methods.add(methodSpec); - } - } - - private String callParameters(ExecutableElement element) { - StringJoiner variables = new StringJoiner(", "); - variables.add(String.format("this.%s", MEMBER_ADDRESS)); - variables.add(String.format("\"%s\"", element.getSimpleName().toString())); - for (VariableElement variableElement : element.getParameters()) { - variables.add(variableElement.getSimpleName().toString()); - } - return variables.toString(); - } - - private MethodSpec methodSpec(ExecutableElement ee, boolean mustGenerate) { - if (ee.getAnnotation(EventLog.class) != null) { - return notSupportedMethod(ee, "not supported EventLog method"); - } - - String methodName = ee.getSimpleName().toString(); - TypeMirror returnType = ee.getReturnType(); - TypeName returnTypeName = TypeName.get(returnType); - - MethodSpec.Builder builder = MethodSpec - .methodBuilder(methodName) -// .addAnnotation(Override.class) - .addModifiers(ProcessorUtil.getModifiers(ee, Modifier.ABSTRACT)) - .addParameters(ProcessorUtil.getParameterSpecs(ee)) - .returns(returnTypeName); - - String callParameters = callParameters(ee); - if (returnTypeName.equals(TypeName.VOID)) { - builder.addStatement("$T.call($L)", Context.class, callParameters); - } else { - if (returnType.getKind().equals(TypeKind.DECLARED) && - ((DeclaredType)returnType).getTypeArguments().size() > 0) { - builder.addStatement("return ($T)$T.call($L)", returnTypeName, Context.class, callParameters); - } else { - builder.addStatement("return $T.call($T.class, $L)", Context.class, returnTypeName, callParameters); - } - } - return builder.build(); - } - - private MethodSpec payableMethodSpec(ExecutableElement ee, MethodSpec methodSpec) { - MethodSpec.Builder builder = MethodSpec.methodBuilder(methodSpec.name) - .addModifiers(methodSpec.modifiers) - .addParameter(BigInteger.class, PARAM_PAYABLE_VALUE) - .addParameters(methodSpec.parameters) - .returns(methodSpec.returnType); - - String callParameters = callParameters(ee); - TypeMirror returnType = ee.getReturnType(); - if (methodSpec.returnType.equals(TypeName.VOID)) { - builder.addStatement("$T.call($L, $L)", Context.class, PARAM_PAYABLE_VALUE, callParameters); - } else { - if (returnType.getKind().equals(TypeKind.DECLARED) && - ((DeclaredType)returnType).getTypeArguments().size() > 0) { - builder.addStatement("return ($T)$T.call($L, $L)", methodSpec.returnType, Context.class, PARAM_PAYABLE_VALUE, callParameters); - } else { - builder.addStatement("return $T.call($T.class, $L, $L)", Context.class, methodSpec.returnType, PARAM_PAYABLE_VALUE, callParameters); - } - } - return builder.build(); - } - - private MethodSpec notSupportedMethod(ExecutableElement ee, String msg) { - String methodName = ee.getSimpleName().toString(); - TypeName returnTypeName = TypeName.get(ee.getReturnType()); - return MethodSpec.methodBuilder(methodName) - .addModifiers(ProcessorUtil.getModifiers(ee, Modifier.ABSTRACT)) - .addParameters(ProcessorUtil.getParameterSpecs(ee)) - .returns(returnTypeName) - .addStatement("throw new $T(\"$L\")", RuntimeException.class, msg) - .addJavadoc("@deprecated Do not use this method, this is generated only for preventing compile error. $L\n", msg) - .addJavadoc("@throws $L", RuntimeException.class.getName()) - .addAnnotation(Deprecated.class) - .build(); - } -} diff --git a/score-lib/build.gradle b/score-lib/build.gradle index 28f2129d..f86d12d6 100644 --- a/score-lib/build.gradle +++ b/score-lib/build.gradle @@ -2,7 +2,6 @@ plugins { id 'java' } -version '0.1.0' repositories { mavenCentral() @@ -11,22 +10,33 @@ repositories { optimizedJar.enabled = false dependencies { - compileOnly 'foundation.icon:javaee-api:0.9.1' - implementation 'foundation.icon:javaee-scorex:0.5.2' - implementation 'com.github.sink772:minimal-json:0.9.7' - - compileOnly 'foundation.icon:javaee-score-client:0.9.0' - annotationProcessor 'foundation.icon:javaee-score-client:0.9.0' +// compileOnly 'foundation.icon:javaee-api:0.9.1' +// implementation group: 'foundation.icon', name: 'javaee-score-json', version: '0.9.0' +// implementation 'foundation.icon:javaee-scorex:0.5.2' +// implementation 'com.github.sink772:minimal-json:0.9.7' // - implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.3' - implementation 'foundation.icon:icon-sdk:2.1.0' +//// compileOnly 'foundation.icon:javaee-score-client:0.9.0' +//// annotationProcessor 'foundation.icon:javaee-score-client:0.9.0' +//// +// implementation 'com.fasterxml.jackson.core:jackson-databind:2.14.0-rc1' +// implementation 'foundation.icon:icon-sdk:2.1.0' // +// implementation("foundation.icon:javaee-annotation-processor:0.9.0") +// implementation("com.squareup:javapoet:1.12.1") +// implementation("foundation.icon:javaee-api:0.9.0") +// implementation("foundation.icon:icon-sdk:2.0.0") +// implementation("com.fasterxml.jackson.core:jackson-databind:2.9.6") +// implementation("com.squareup.okhttp3:okhttp:3.11.0") +// implementation("org.bouncycastle:bcprov-jdk15on:1.60") +// compileOnly group: 'commons-io', name: 'commons-io', version: "2.11.0" // - testImplementation 'foundation.icon:javaee-unittest:0.9.4' - testImplementation "org.junit.jupiter:junit-jupiter:5.8.2" - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' - testImplementation 'org.mockito:mockito-core:4.5.1' - testRuntimeOnly 'org.mockito:mockito-inline:4.5.1' +//// +//// +// testImplementation 'foundation.icon:javaee-unittest:0.9.4' +// testImplementation "org.junit.jupiter:junit-jupiter:5.8.2" +// testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' +// testImplementation 'org.mockito:mockito-core:4.5.1' +// testRuntimeOnly 'org.mockito:mockito-inline:4.5.1' } test { 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 d8b03b15..a4cd2ea1 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 @@ -11,8 +11,7 @@ import java.math.BigInteger; import java.util.Map; -@ScoreClient -@ScoreInterface +@ScoreInterface(suffix = "Client") public interface CPFTreasuryInterface { @External(readonly = true) String name(); 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 0cf04fb6..e0cec7bd 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 @@ -12,8 +12,7 @@ import java.util.List; import java.util.Map; -@ScoreClient -@ScoreInterface +@ScoreInterface(suffix = "Client") public interface CPSCoreInterface { public static class ProposalAttributes { @@ -120,7 +119,7 @@ public static class MilestoneVoteAttributes { void registerPrep(); @External(readonly = true) - boolean checkPriorityVoting(Address prep); + boolean checkPriorityVoting(Address _prep); @External(readonly = true) List sortPriorityProposals(); @@ -193,6 +192,9 @@ public static class MilestoneVoteAttributes { @External(readonly = true) List getProposalsKeysByStatus(String _status); + @External(readonly = true) + Map getMilestonesReport(String ipfsKey, int milestoneId); + @External(readonly = true) int checkChangeVote(Address address, String ipfsHash, String proposalType); @@ -213,7 +215,7 @@ public static class MilestoneVoteAttributes { Map getProposalDetails(String status, @Optional Address walletAddress, @Optional int startIndex); @External(readonly = true) - Map getProposalDetailsByHash(String ipfs_key); + Map getProposalDetailsByHash(String ipfsKey); @External(readonly = true) @@ -255,6 +257,9 @@ public static class MilestoneVoteAttributes { @External void updateNextBlock(int blockCount); + @External(readonly = true) + List> getRemainingProject(String projectType, Address walletAddress); + @External void updateContributor(String _ipfs_key, Address _new_contributor, Address _new_sponsor); @@ -270,6 +275,11 @@ public static class MilestoneVoteAttributes { @External(readonly = true) List> getRemainingMilestones(String ipfsHash); + @External + void setSponsorBondPercentage(BigInteger bondValue); + + @External(readonly = true) + BigInteger getSponsorBondPercentage(); // EventLogs @EventLog(indexed = 1) 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 28c30ddc..c0acf6ff 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 @@ -11,8 +11,8 @@ import java.util.List; import java.util.Map; -@ScoreClient -@ScoreInterface +//@ScoreClient +@ScoreInterface(suffix = "Client") public interface CPSTreasuryInterface { @External(readonly = true) String name(); diff --git a/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/DexInterface.java b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/DexInterface.java index 1be7d1a4..c44520f7 100644 --- a/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/DexInterface.java +++ b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/DexInterface.java @@ -1,6 +1,5 @@ package community.icon.cps.score.lib.interfaces; -import foundation.icon.score.client.ScoreClient; import foundation.icon.score.client.ScoreInterface; import score.Address; import score.annotation.EventLog; @@ -8,8 +7,8 @@ import java.math.BigInteger; -@ScoreInterface -@ScoreClient + +@ScoreInterface(suffix = "Client") public interface DexInterface { @External diff --git a/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/RouterInterface.java b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/RouterInterface.java index efb9b81b..3300534e 100644 --- a/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/RouterInterface.java +++ b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/RouterInterface.java @@ -1,6 +1,5 @@ package community.icon.cps.score.lib.interfaces; -import foundation.icon.score.client.ScoreClient; import foundation.icon.score.client.ScoreInterface; import score.Address; import score.annotation.External; @@ -9,10 +8,9 @@ import java.math.BigInteger; -@ScoreInterface -@ScoreClient +@ScoreInterface(suffix = "Client") public interface RouterInterface { @Payable @External - void route(Address[] _path, @Optional BigInteger _minReceive); + void route(Address[] _path, @Optional BigInteger _minReceive,@Optional String _receiver); } diff --git a/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/SystemInterface.java b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/SystemInterface.java index 76d46074..c6f3da42 100644 --- a/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/SystemInterface.java +++ b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/SystemInterface.java @@ -9,8 +9,8 @@ import java.math.BigInteger; import java.util.Map; -@ScoreClient -@ScoreInterface +//@ScoreClient +@ScoreInterface(suffix = "Client") public interface SystemInterface { public static class Delegation{ public Address address; diff --git a/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/bnUSDInterface.java b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/bnUSDInterface.java index 21c472a5..7d426077 100644 --- a/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/bnUSDInterface.java +++ b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/bnUSDInterface.java @@ -1,10 +1,9 @@ package community.icon.cps.score.lib.interfaces; import community.icon.cps.score.lib.interfaces.tokens.IRC2; -import foundation.icon.score.client.ScoreClient; import foundation.icon.score.client.ScoreInterface; -@ScoreInterface -@ScoreClient + +@ScoreInterface(suffix = "Client") public interface bnUSDInterface extends IRC2 { } diff --git a/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/sICXInterface.java b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/sICXInterface.java index 9433f219..ae700d7f 100644 --- a/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/sICXInterface.java +++ b/score-lib/src/main/java/community/icon/cps/score/lib/interfaces/sICXInterface.java @@ -1,10 +1,8 @@ package community.icon.cps.score.lib.interfaces; import community.icon.cps.score.lib.interfaces.tokens.IRC2; -import foundation.icon.score.client.ScoreClient; import foundation.icon.score.client.ScoreInterface; -@ScoreInterface -@ScoreClient +@ScoreInterface(suffix = "Client") public interface sICXInterface extends IRC2 { } diff --git a/script/README.md b/script/README.md new file mode 100644 index 00000000..7eefdd3a --- /dev/null +++ b/script/README.md @@ -0,0 +1,35 @@ +# DEPLOYMENT SCRIPT + +The script contains scripts to +- deploy required contracts +- configure contracts +- add funds to the system + +## Prerequisites + +Install [go](https://go.dev/doc/install) + +- ### goloop +```sh +go install github.com/icon-project/goloop/cmd/goloop@latest +``` + +- ### jq +Install jq +```sh +sudo apt install jq +brew install jq +sudo pacman -S jq +``` + +## Usage + +The constants are defined in `const.sh`. Wallet and environment can be changed +from here. +`deploy.sh` contains all the deployment and configuration script.Invoke with `-a` flag to +complete all transaction. +```sh +bash deploy.sh -a +``` + +Note: make sure optimized jar is created/updated before running the script diff --git a/script/const.sh b/script/const.sh new file mode 100644 index 00000000..66d6d683 --- /dev/null +++ b/script/const.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +export SCRIPTS_DIR=$PWD +export CPS_JAVA_SCORE="$SCRIPTS_DIR/.." +export DUMMY_SCORE="$SCRIPTS_DIR/../dummy" +export CONTRACT_FILE_NAME="contracts_$(date +"%Y%m%d_%H%M%S").txt" +export CONTRACT_ADDRESS="$SCRIPTS_DIR/contracts/$CONTRACT_FILE_NAME" + +#--------------------------------------------------------------------- +#-----------------CHANGE THIS BY REQUIREMENT-------------------------- +#--------------------------------------------------------------------- + +export ICON=icon +export ICON_NET=local ## [local, testnet, mainnet ] + +export SICX_ADMIN="hxb6b5791be0b5ef67063b3c10b840fb81514db2fd" +export DEPLOYER_ADDRESS="hxb6b5791be0b5ef67063b3c10b840fb81514db2fd" + +export ICON_WALLET_NAME=godWallet +export ICON_WALLET=$CPS_JAVA_SCORE/cps-gochain-local/data/godWallet.json +export ICON_PASSWORD=gochain + +case $ICON_NET in + "local" ) + export ICON_NID=3 + export ICON_NODE=http://localhost:9082/api/v3/ + export ICON_DEBUG_NODE=http://localhost:9082/api/v3d + ;; + "lisbon" ) + export ICON_NID=2 + export ICON_NODE=https://lisbon.net.solidwallet.io/api/v3/ + export ICON_DEBUG_NODE=https://lisbon.net.solidwallet.io/api/v3d + ;; +esac + +export ICON_COMMON_ARGS="--uri $ICON_NODE --nid $ICON_NID --step_limit 2500000000 --key_store $ICON_WALLET \ +--key_password $ICON_PASSWORD " + +export GOVERNANCE_SCORE=cx0000000000000000000000000000000000000000 \ No newline at end of file diff --git a/script/contracts/sample_contracts.txt b/script/contracts/sample_contracts.txt new file mode 100644 index 00000000..17f9dce2 --- /dev/null +++ b/script/contracts/sample_contracts.txt @@ -0,0 +1,8 @@ +CPSCore: cxd1872a8d7c65f6e05f32a81c0a1084b1a4e90a53 +CPSTreasury: cx91814b2698b27c3923f8d1aa5795fb2daebeead4 +CPFTreasury: cxd4473c8c026de126f968693129fadf7c3dad7b6b +bnUSD: cx0f2d7893bac7e308667cc2ebb67b6e3fed3aba08 +Dex: cx9673aed808682dc29b27f4e41ecf48df937b24f5 +oracle: cx68df1a3e30fc9f44bbc2fb73f7b39f211c47c1e1 +Router: cx7c40a5be786b187972886e495f933756f210e083 +sICX: cxc631f59377d412c8ffe17cd9aa52a8f670623f9e diff --git a/script/deploy.sh b/script/deploy.sh new file mode 100644 index 00000000..7b20e669 --- /dev/null +++ b/script/deploy.sh @@ -0,0 +1,316 @@ +#!/bin/bash + +source const.sh + +function icon_wait_tx() { + local ret=1 + local tx_hash=$1 + while :; do + goloop rpc \ + --uri "$ICON_NODE" \ + txresult "$tx_hash" &>/dev/null && break || sleep 1 + done + + local res=$(goloop rpc \ + --uri $ICON_NODE \ + txresult "$tx_hash") + local status=$(jq <<<"$res" -r .status) + + echo "status : $status" + [ "$status" == 0x0 ] && echo $res && exit 0 + [ "$status" == 0x1 ] && ret=0 + + return $ret +} + +function save_address() { + local ret=1 + local tx_hash=$1 + local addrLoc=$2 + local fileName=$3 + local res=$(goloop rpc \ + --uri $ICON_NODE \ + txresult "$tx_hash" 2>/dev/null) + + local score_address=$(jq <<<"$res" -r .scoreAddress) + echo "contract address : $score_address" + echo "$fileName: $score_address" >> $addrLoc +} + + +function deploy_contract() { + local jarFile=$1 + local addrLoc=$2 + + + local contractName=$(basename "$jarFile" | cut -d'-' -f1) + echo "deploying contract $contractName" + + local params=() + for i in "${@:3}"; do params+=("--param $i"); done + + local tx_hash=$( + goloop rpc sendtx deploy $jarFile \ + --content_type application/java \ + --to $GOVERNANCE_SCORE \ + $ICON_COMMON_ARGS \ + ${params[@]} | jq -r . + ) + icon_wait_tx $tx_hash + save_address $tx_hash $addrLoc $contractName + +} + +function icon_send_tx() { + local address=$1 + local method=$2 + + local params=() + for i in "${@:3}"; do params+=("--param $i"); done + local tx_hash=$( + goloop rpc sendtx call \ + --to "$address" \ + --method "$method" \ + $ICON_COMMON_ARGS \ + ${params[@]} | jq -r . + ) + icon_wait_tx "$tx_hash" +} + +function setPrepPenaltyAmount() { + local param="{\"params\":{\"penalty\":[\"2\",\"5\",\"10\"]}}" + local address=$(grep 'CPSCore' "$CONTRACT_ADDRESS" | cut -d' ' -f2) + local method="setPrepPenaltyAmount" + local tx_hash=$(goloop rpc sendtx call \ + --to "$address" \ + --method "$method" \ + --raw $param\ + $ICON_COMMON_ARGS | jq -r . + ) + icon_wait_tx $tx_hash +} + +function icon_transfer_icx() { + local address=$1 + local val=$2 + + local params=() + for i in "${@:3}"; do params+=("--param $i"); done + + local tx_hash=$( + goloop rpc sendtx transfer \ + --to "$address" \ + --value "$val" \ + $ICON_COMMON_ARGS \ + ${params[@]} | jq -r . + ) + icon_wait_tx "$tx_hash" +} + + +function deploy_cps_contracts() { + + echo "-------------------------------------------------------------------" + echo "--------------------------DEPLOY CONTRACTS-------------------------" + echo "-------------------------------------------------------------------" + local CPS_CORE_FILE=$CPS_JAVA_SCORE/CPSCore/build/libs/CPSCore-[0-9].[0-9].[0-9]-optimized.jar + deploy_contract $CPS_CORE_FILE $CONTRACT_ADDRESS bondValue="15" applicationPeriod="15" + + local cps_score_addr=$(grep 'CPSCore' "$CONTRACT_ADDRESS" | cut -d' ' -f2) + local CPS_TREASURY_FILE=$CPS_JAVA_SCORE/CPSTreasury/build/libs/CPSTreasury-[0-9].[0-9].[0-9]-optimized.jar + deploy_contract $CPS_TREASURY_FILE $CONTRACT_ADDRESS cpsScore=$cps_score_addr + + local CPF_TREASURY_FILE=$CPS_JAVA_SCORE/CPFTreasury/build/libs/CPFTreasury-[0-9].[0-9].[0-9]-optimized.jar + deploy_contract $CPF_TREASURY_FILE $CONTRACT_ADDRESS cpsScore=$cps_score_addr + + local BNUSD_FILE=$DUMMY_SCORE/bnUSD/build/libs/bnUSD-[0-9].[0-9].[0-9]-optimized.jar + deploy_contract $BNUSD_FILE $CONTRACT_ADDRESS _name="Dummy_bnUSD_Coin" _symbol="bnUSD" _decimals="18" _initialSupply="1000000000000000000000" + + local DEX_FILE=$DUMMY_SCORE/Dex/build/libs/Dex-[0-9].[0-9].[0-9]-optimized.jar + deploy_contract $DEX_FILE $CONTRACT_ADDRESS + + local ORACLE_FILE=$DUMMY_SCORE/oracle/build/libs/oracle-[0-9].[0-9].[0-9]-optimized.jar + deploy_contract $ORACLE_FILE $CONTRACT_ADDRESS + + local ROUTER_FILE=$DUMMY_SCORE/Router/build/libs/Router-[0-9].[0-9].[0-9]-optimized.jar + deploy_contract $ROUTER_FILE $CONTRACT_ADDRESS + + local SICX_FILE=$DUMMY_SCORE/sICX/build/libs/sICX-[0-9].[0-9].[0-9]-optimized.jar + deploy_contract $SICX_FILE $CONTRACT_ADDRESS _admin=$SICX_ADMIN + +} + +function setters_in_cps_score() { + echo "-------------------------------------------------------------------" + echo "--------------------SET CONTRACTS IN CPS SCORE---------------------" + echo "-------------------------------------------------------------------" + + local cps_score_addr=$(grep 'CPSCore' "$CONTRACT_ADDRESS" | cut -d' ' -f2) + + echo "setting admin address" + icon_send_tx $cps_score_addr "addAdmin" address=$SICX_ADMIN + + echo "setting cps treasury address" + local cps_treasury_addr=$(grep 'CPSTreasury' "$CONTRACT_ADDRESS" | cut -d' ' -f2) + icon_send_tx $cps_score_addr "setCpsTreasuryScore" score=$cps_treasury_addr + + echo "setting cpf treasury address" + local cpf_treasury_addr=$(grep 'CPFTreasury' "$CONTRACT_ADDRESS" | cut -d' ' -f2) + icon_send_tx $cps_score_addr "setCpfTreasuryScore" score=$cpf_treasury_addr + + echo "setting bnUSD address" + local bnUSD_addr=$(grep 'bnUSD' "$CONTRACT_ADDRESS" | cut -d' ' -f2) + icon_send_tx $cps_score_addr "setBnusdScore" score=$bnUSD_addr + +} + +function setter_in_cpf_treasury() { + echo "-------------------------------------------------------------------" + echo "-----------------SET CONTRACTS IN CPF TREASURY---------------------" + echo "-------------------------------------------------------------------" + + local cpf_treasury_addr=$(grep 'CPFTreasury' "$CONTRACT_ADDRESS" | cut -d' ' -f2) + + echo "setting cps treasury address" + local cps_treasury_addr=$(grep 'CPSTreasury' "$CONTRACT_ADDRESS" | cut -d' ' -f2) + icon_send_tx $cpf_treasury_addr "setCpsTreasuryScore" score=$cps_treasury_addr + + echo "setting bnUSD address" + local bnUSD_addr=$(grep 'bnUSD' "$CONTRACT_ADDRESS" | cut -d' ' -f2) + icon_send_tx $cpf_treasury_addr "setBnUSDScore" score=$bnUSD_addr + + echo "setting dex address" + local dex_addr=$(grep 'Dex' "$CONTRACT_ADDRESS" | cut -d' ' -f2) + icon_send_tx $cpf_treasury_addr "setDexScore" score=$dex_addr + + echo "setting oracle address" + local oracle_addr=$(grep 'oracle' "$CONTRACT_ADDRESS" | cut -d' ' -f2) + icon_send_tx $cpf_treasury_addr "setOracleAddress" score=$oracle_addr + + echo "setting router address" + local router_addr=$(grep 'Router' "$CONTRACT_ADDRESS" | cut -d' ' -f2) + icon_send_tx $cpf_treasury_addr "setRouterScore" score=$router_addr + + echo "setting sICX address" + local sICX_addr=$(grep 'sICX' "$CONTRACT_ADDRESS" | cut -d' ' -f2) + icon_send_tx $cpf_treasury_addr "setSicxScore" score=$sICX_addr +} + +function setters_in_cps_treasury() { + echo "-------------------------------------------------------------------" + echo "-----------------SET CONTRACTS IN CPS TREASURY---------------------" + echo "-------------------------------------------------------------------" + + local cps_treasury_addr=$(grep 'CPSTreasury' "$CONTRACT_ADDRESS" | cut -d' ' -f2) + + echo "setting cpf treasury address" + local cpf_treasury_addr=$(grep 'CPFTreasury' "$CONTRACT_ADDRESS" | cut -d' ' -f2) + icon_send_tx $cps_treasury_addr "setCpfTreasuryScore" score=$cpf_treasury_addr + + echo "setting bnUSD address" + local bnUSD_addr=$(grep 'bnUSD' "$CONTRACT_ADDRESS" | cut -d' ' -f2) + icon_send_tx $cps_treasury_addr "setBnUSDScore" score=$bnUSD_addr + +} + +function setters_in_dex() { + echo "-------------------------------------------------------------------" + echo "-----------------SET CONTRACTS IN DEX------------------------------" + echo "-------------------------------------------------------------------" + + local dex=$(grep 'Dex' "$CONTRACT_ADDRESS" | cut -d' ' -f2) + + local sICX_addr=$(grep 'sICX' "$CONTRACT_ADDRESS" | cut -d' ' -f2) + icon_send_tx $dex "setSicxScore" _score=$sICX_addr + +} + +function add_funds() { + echo "-------------------------------------------------------------------" + echo "-----------------ADD FUND IN TREASURY------------------------------" + echo "-------------------------------------------------------------------" + + local cpf_treasury_addr=$(grep 'CPFTreasury' "$CONTRACT_ADDRESS" | cut -d' ' -f2) + + echo "set treasury fund limit" + icon_send_tx $cpf_treasury_addr "setMaximumTreasuryFundIcx" value="0xd3c21bcecceda0000000" + icon_send_tx $cpf_treasury_addr "setMaximumTreasuryFundBnusd" value="0xd3c21bcecceda0000000" + + echo "send fund to treasury" + local bnUSD_addr=$(grep 'bnUSD' "$CONTRACT_ADDRESS" | cut -d' ' -f2) + icon_send_tx $bnUSD_addr "mintTo" to=$cpf_treasury_addr amount="50000000000000000000000" + + echo "send sicx to dex for swap" + local sICX_addr=$(grep 'sICX' "$CONTRACT_ADDRESS" | cut -d' ' -f2) + local dex_addr=$(grep 'Dex' "$CONTRACT_ADDRESS" | cut -d' ' -f2) + icon_send_tx $sICX_addr "mintWithTokenFallBack" _to=$dex_addr _amount="10000000000000000000000" \ + _data="0x7b0a2020226d6574686f64223a20225f646578220a7d" + + echo "send ICX to dex" + icon_transfer_icx $dex_addr "1000000000000000000000" + + +} + +function configure_system() { + echo "-------------------------------------------------------------------" + echo "-----------------SET SYSTEM CONFIGURATION--------------------------" + echo "-------------------------------------------------------------------" + local cps_score_addr=$(grep 'CPSCore' "$CONTRACT_ADDRESS" | cut -d' ' -f2) + + echo "turn off maintainance mode" + icon_send_tx $cps_score_addr "toggleMaintenance" + + echo "set initial block" + icon_send_tx $cps_score_addr "setInitialBlock" + + echo "set prep's penalty amount" + setPrepPenaltyAmount + + local cpf_treasury_addr=$(grep 'CPFTreasury' "$CONTRACT_ADDRESS" | cut -d' ' -f2) + + echo "toggle swap flag" + icon_send_tx $cpf_treasury_addr "toggleSwapFlag" + + echo "set oracle slippage percentage" + icon_send_tx $cpf_treasury_addr "setOraclePercentageDifference" value="3" +# icon_send_tx $cps_score_addr "toggleBudgetAdjustmentFeature" + +} + + + +function set_contracts() { + setters_in_cps_score + setters_in_cps_treasury + setter_in_cpf_treasury + setters_in_dex + +} + +function configure_fund_and_system() { + add_funds + configure_system +} + +SHORT=adsc +LONG=all,deploy-contracts,set-contracts,configure-system + +options=$(getopt -o $SHORT --long $LONG -n 'deploy.sh' -- "$@") +if [ $? -ne 0 ]; then + echo "Usage: $0 [-a] [-d] [-s] [-c]" >&2 + exit 1 +fi + +eval set -- "$options" + +while true; do + case "$1" in + -a|--all) deploy_cps_contracts; set_contracts; configure_fund_and_system; shift ;; + -d|--deploy-contracts) deploy_cps_contracts; shift ;; + -s|--set-contracts) set_contracts; shift ;; + -c|--configure-system) configure_fund_and_system; shift ;; + --) shift; break ;; + *) echo "Internal error!"; exit 1 ;; + esac +done \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 0762b7ba..5a429622 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,30 +1,32 @@ rootProject.name = 'cps_java_contracts' -include (':CPFTreasury') +include(':CPFTreasury') project(':CPFTreasury').projectDir = file("CPFTreasury") -include (':CPSTreasury') +include(':CPSTreasury') project(':CPSTreasury').projectDir = file("CPSTreasury") -include (':CPSCore') +include(':CPSCore') project(':CPSCore').projectDir = file("CPSCore") -include ('score-client') -include ('test-lib') +include('test-lib') +project(':test-lib').projectDir = file("test-lib") -include ('score-lib') +include('score-lib') +project(':score-lib').projectDir = file("score-lib") -include (':Router') + +include(':Router') project(':Router').projectDir = file("dummy/Router") -include (':Dex') +include(':Dex') project(':Dex').projectDir = file("dummy/Dex") -include (':sICX') +include(':sICX') project(':sICX').projectDir = file("dummy/sICX") -include (':bnUSD') +include(':bnUSD') project(':bnUSD').projectDir = file("dummy/bnUSD") include(':oracle') diff --git a/test-lib/build.gradle b/test-lib/build.gradle index bb9b7c53..002e452e 100644 --- a/test-lib/build.gradle +++ b/test-lib/build.gradle @@ -1,31 +1,32 @@ -plugins { - id 'java' -} +apply plugin: 'java-library' -version '0.1.0' +optimizedJar.enabled = false repositories { mavenCentral() } -optimizedJar.enabled = false - dependencies { - implementation "foundation.icon:icon-sdk:2.1.0" +// implementation "foundation.icon:icon-sdk:$iconsdkVersion" + implementation name: "score-client-$scoreClientVersion" + annotationProcessor name: "score-client-$scoreClientVersion" + + implementation "org.junit.jupiter:junit-jupiter-api:$junitVersion" + implementation "com.fasterxml.jackson.core:jackson-databind:$jacksonVersion" + implementation "com.github.javafaker:javafaker:$javafakerVersion" + implementation "foundation.icon:javaee-unittest:$javaeeUnittestVersion" + implementation "org.mockito:mockito-core:$mockitoVersion" + +// implementation "foundation.icon:icon-sdk:$iconsdkVersion" + implementation group: 'commons-io', name: 'commons-io', version: "$commonIOVersion" + implementation "org.bouncycastle:bcprov-jdk15on:1.60" +// implementation "foundation.icon:icon-sdk:$iconsdkVersion" + implementation("foundation.icon:icon-sdk:2.0.0") + testImplementation("foundation.icon:icon-sdk:2.0.0") + + + implementation project(':score-lib') - annotationProcessor project(':score-client') - implementation project(':score-client') - implementation "org.junit.jupiter:junit-jupiter-api:5.8.2" - implementation "com.fasterxml.jackson.core:jackson-databind:2.13.3" - implementation "foundation.icon:javaee-unittest:0.9.4" - implementation "org.junit.jupiter:junit-jupiter:5.8.2" - runtimeOnly "org.junit.jupiter:junit-jupiter-engine:5.8.2" - implementation "com.github.sink772:minimal-json:0.9.7" - implementation "org.mockito:mockito-core:4.5.1" - implementation "org.json:json:20220320" - implementation "foundation.icon:javaee-scorex:0.5.2" - - implementation "com.github.javafaker:javafaker:1.0.2" } test { diff --git a/test-lib/src/main/java/community/icon/cps/score/test/AssertRevertedException.java b/test-lib/src/main/java/community/icon/cps/score/test/AssertRevertedException.java new file mode 100644 index 00000000..3a1c7c52 --- /dev/null +++ b/test-lib/src/main/java/community/icon/cps/score/test/AssertRevertedException.java @@ -0,0 +1,96 @@ +/* + * Copyright 2021 ICON Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package community.icon.cps.score.test; + + +import foundation.icon.jsonrpc.JsonrpcClient; +import foundation.icon.score.client.RevertedException; +import org.junit.jupiter.api.function.Executable; +import score.UserRevertException; +import score.UserRevertedException; + +import java.util.function.Function; + +import static org.junit.jupiter.api.Assertions.*; + +public class AssertRevertedException { + + public static RevertedException assertReverted(int expected, Executable executable) { + return assertReverted(new RevertedException(expected, ""), executable); + } + + public static RevertedException assertReverted(RevertedException expected, Executable executable) { + RevertedException e = assertThrows(RevertedException.class, executable); + assertEquals(expected.getCode(), e.getCode(), + String.format("assertReverted expected: %d, actual: %d", expected.getCode(), e.getCode())); + return e; + } + + public static UserRevertedException assertUserReverted(int expected, Executable executable) { + return assertUserReverted(expected, executable, null); + } + + public static UserRevertedException assertUserReverted(int expected, Executable executable, + Function messageSupplier) { + return assertUserReverted(new UserRevertedException(expected), executable, messageSupplier); + } + + public static UserRevertedException assertUserReverted(T expected, + Executable executable, + Function messageSupplier) { + UserRevertedException e = assertThrows(UserRevertedException.class, executable); + assertEquals(expected.getCode(), e.getCode(), messageSupplier == null ? + () -> String.format("assertUserReverted expected: %d, actual: %d", expected.getCode(), e.getCode()) : + () -> messageSupplier.apply(e)); + return e; + } + + public static UserRevertedException assertUserRevert(T expected, + Executable executable, + Function messageSupplier) { + return assertUserReverted(expected.getCode(), executable, messageSupplier == null ? + (e) -> String.format("assertUserRevertException expected:%s, actual: %s", expected, e.toString()) : + messageSupplier); + } + + public static UserRevertedException assertUserRevertedFromJsonrpcError(int expected, Executable executable, + Function messageSupplier) { + return assertUserRevertedFromJsonrpcError(new UserRevertedException(expected), executable, messageSupplier); + } + + public static UserRevertedException assertUserRevertedFromJsonrpcError(T expected, Executable executable, Function messageSupplier) { + JsonrpcClient.JsonrpcError rpcError = assertThrows(JsonrpcClient.JsonrpcError.class, executable); + //ErrorCodeScore(30000) + UserReverted(32) + assertTrue(rpcError.getCode() <= -30032 && rpcError.getCode() > -31000); + UserRevertedException e = new UserRevertedException(-1 * ((int) rpcError.getCode() + 30032), + rpcError.getMessage()); + assertEquals(expected.getCode(), e.getCode(), messageSupplier == null ? + () -> String.format("assertUserRevertedFromJsonrpcError expected: %d, actual: %d", expected.getCode() + , e.getCode()) : + () -> messageSupplier.apply(e)); + return e; + } + + public static UserRevertedException assertUserRevertFromJsonrpcError(T expected, + Executable executable, Function messageSupplier) { + return assertUserRevertedFromJsonrpcError(expected.getCode(), executable, messageSupplier == null ? + (e) -> String.format("assertUserRevertFromJsonrpcError expected:%s, actual: %s", expected, + e.toString()) : + messageSupplier); + } +} + diff --git a/test-lib/src/main/java/community/icon/cps/score/test/integration/CPS.java b/test-lib/src/main/java/community/icon/cps/score/test/integration/CPS.java index ee46165d..65905c21 100644 --- a/test-lib/src/main/java/community/icon/cps/score/test/integration/CPS.java +++ b/test-lib/src/main/java/community/icon/cps/score/test/integration/CPS.java @@ -1,156 +1,301 @@ package community.icon.cps.score.test.integration; +import community.icon.cps.score.test.integration.scores.SystemInterfaceScoreClient; +import community.icon.cps.score.test.integration.model.Score; +import community.icon.cps.score.test.integration.scores.SystemInterface; +import community.icon.cps.score.test.integration.utils.DefaultICONClient; import foundation.icon.icx.KeyWallet; import foundation.icon.icx.data.Bytes; import foundation.icon.score.client.DefaultScoreClient; -import community.icon.cps.score.lib.interfaces.CPSTreasuryInterfaceScoreClient; -import community.icon.cps.score.lib.interfaces.CPFTreasuryInterfaceScoreClient; -import community.icon.cps.score.lib.interfaces.CPSCoreInterfaceScoreInterface; -import community.icon.cps.score.lib.interfaces.DexInterfaceScoreClient; -import community.icon.cps.score.lib.interfaces.sICXInterfaceScoreClient; -import community.icon.cps.score.lib.interfaces.bnUSDInterfaceScoreClient; -import community.icon.cps.score.lib.interfaces.RouterInterfaceScoreClient; import score.Address; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; import java.math.BigInteger; + import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.Callable; + +import static community.icon.cps.score.test.integration.Environment.*; +import static community.icon.cps.score.test.integration.ScoreIntegrationTest.createWalletWithBalance; +import static community.icon.cps.score.test.integration.ScoreIntegrationTest.transfer; -import static community.icon.cps.score.test.integration.ScoreIntegrationTest.*; public class CPS { - public KeyWallet user; - public KeyWallet testUser; public KeyWallet owner; - - /* - Prep wallets loaded from test-lib/src/main/java/community/icon/cps/score/test/wallets - */ - - public KeyWallet prepWallet1; - public KeyWallet prepWallet2; - public KeyWallet prepWallet3; - public KeyWallet prepWallet4; - public KeyWallet prepWallet5; - public KeyWallet prepWallet6; - public KeyWallet prepWallet7; - public CPSClient ownerClient; - public DefaultScoreClient cpsTreasury; - public DefaultScoreClient cpfTreasury; - public DefaultScoreClient cpsCore; - - public DefaultScoreClient dex; - public DefaultScoreClient router; - public DefaultScoreClient bnusd; - public DefaultScoreClient sicx; + public CPSClient testClient; - public DefaultScoreClient governanceBalanced; + private Map addresses; + public DefaultICONClient iconClient; - public CPSTreasuryInterfaceScoreClient cpsTreasuryScore; - public CPFTreasuryInterfaceScoreClient cpfTreasuryScore; - public CPSCoreInterfaceScoreInterface cpsMainScore; + HashMap cpsClients; + private String contracts; - Map cpsClients; + public CPS(String contracts) throws Exception { - public List prepList; - - public CPS() throws Exception{ + this.contracts = contracts; cpsClients = new HashMap<>(); owner = createWalletWithBalance(BigInteger.TEN.pow(24)); - user = createWalletWithBalance(BigInteger.TEN.pow(24)); - testUser = createWalletWithBalance(BigInteger.TEN.pow(24)); - BufferedReader br = new BufferedReader(new FileReader("privateKey.txt")); -// System.out.println("Reading the content of the file in cpsMain: " + br.readLine()); - String longPrivateKey = br.readLine(); - String privateKey0 = longPrivateKey.substring(0, 66); - String privateKey1 = longPrivateKey.substring(66, 132); - String privateKey2 = longPrivateKey.substring(132, 198); - String privateKey3 = longPrivateKey.substring(198, 264); - String privateKey4 = longPrivateKey.substring(264, 330); - String privateKey5 = longPrivateKey.substring(330, 396); - String privateKey6 = longPrivateKey.substring(396, 462); - - prepWallet1 = KeyWallet.load(new Bytes(privateKey1)); - prepWallet2 = KeyWallet.load(new Bytes(privateKey2)); - prepWallet3 = KeyWallet.load(new Bytes(privateKey3)); - prepWallet4 = KeyWallet.load(new Bytes(privateKey4)); - prepWallet5 = KeyWallet.load(new Bytes(privateKey5)); - prepWallet6 = KeyWallet.load(new Bytes(privateKey6)); - prepWallet7 = KeyWallet.load(new Bytes(privateKey0)); - } - - public void setupCPS() throws Exception{ - registerPreps(); - deployContracts(); -// setStakeOfPreps(); -// setDelegationOfPreps(); -// setBonderListOfPReps(); -// setBondOfPreps(); -// registerGodPrep(); -// setGodStake(); - } - - public void registerGodPrep(){ - registerGodClient(); - } - - public void setGodPrep(){ + iconClient = new DefaultICONClient(chain); + } + + public void setupCPS() throws Exception { + deployPrep(); + decentralizeChain(); + Thread.sleep(120000); + this.addresses = new ScoreDeployer(this,contracts).deployContracts(); + + ownerClient = new CPSClient(this,owner); + testClient = new CPSClient(this, createWalletWithBalance(BigInteger.TEN.pow(24))); + } + + private void decentralizeChain(){ +// if (isPRepRegistered()) { +// return; +// } + setStake(); + setDelegationOfPreps(); + setBonderList(); + setBondsofPreps(); setGodStake(); } - public void setStakeOfPreps(){ - KeyWallet[] keyWallets = {prepWallet1, prepWallet2, prepWallet3, prepWallet4, prepWallet5, prepWallet6, prepWallet7}; - setStake(keyWallets); + public void setGodStake(){ + SYSTEM_INTERFACE = new SystemInterfaceScoreClient(godClient); + SYSTEM_INTERFACE.setStake(BigInteger.valueOf(9_000_000).multiply(BigInteger.TEN.pow(18))); + SystemInterface.Delegation[] delegation = new SystemInterface.Delegation[1]; + delegation[0] = new SystemInterface.Delegation(); + delegation[0].address = score.Address.fromString(chain.godWallet.getAddress().toString()); + delegation[0].value = BigInteger.valueOf(8000000).multiply(BigInteger.TEN.pow(18)); + SYSTEM_INTERFACE.setDelegation(delegation); + + score.Address[] addresses = new score.Address[1]; + addresses[0] = score.Address.fromString(chain.godWallet.getAddress().toString()); + SYSTEM_INTERFACE.setBonderList(addresses); + + SystemInterface.Bond[] bonds = new SystemInterface.Bond[1]; + bonds[0] = new SystemInterface.Bond(); + bonds[0].address = score.Address.fromString(chain.godWallet.getAddress().toString()); + bonds[0].value = BigInteger.valueOf(1000000).multiply(BigInteger.TEN.pow(18)); + SYSTEM_INTERFACE.setBond(bonds); + System.out.println("god wallet setup done"); + } + + private void setStake(){ + int count = 0; + for (Map.Entry prep : preps.entrySet()) { + if (prep.getKey().equals(Address.fromString("hxb6b5791be0b5ef67063b3c10b840fb81514db2fd"))){ + continue; + } + if (count < 7) { + KeyWallet wallet = KeyWallet.load(new Bytes(prep.getValue())); + var client = new DefaultScoreClient( + chain.getEndpointURL(), + chain.networkId, + wallet, + DefaultScoreClient.ZERO_ADDRESS + ); + SYSTEM_INTERFACE = new SystemInterfaceScoreClient(client); + SYSTEM_INTERFACE.setStake(BigInteger.valueOf(100_000).multiply(BigInteger.TEN.pow(18))); + count++; + } + else { + break; + } + } + System.out.println("set is done"); } public void setDelegationOfPreps(){ - KeyWallet[] keyWallets = {prepWallet1, prepWallet2, prepWallet3, prepWallet4, prepWallet5, prepWallet6, prepWallet7}; - setDelegation(keyWallets); + int count = 0; + for (Map.Entry prep : preps.entrySet()) { + if (prep.getKey().equals(Address.fromString("hxb6b5791be0b5ef67063b3c10b840fb81514db2fd"))){ + continue; + } + if (count < 7) { + KeyWallet wallet = KeyWallet.load(new Bytes(prep.getValue())); + SystemInterface.Delegation[] delegations = new SystemInterface.Delegation[1]; + delegations[0] = new SystemInterface.Delegation(); + delegations[0].address = score.Address.fromString(prep.getKey().toString()); + delegations[0].value = BigInteger.valueOf(80_000).multiply(BigInteger.TEN.pow(18)); + var client = new DefaultScoreClient( + chain.getEndpointURL(), + chain.networkId, + wallet, + DefaultScoreClient.ZERO_ADDRESS + ); + SYSTEM_INTERFACE = new SystemInterfaceScoreClient(client); + SYSTEM_INTERFACE.setDelegation(delegations); + count++; + } + else { + break; + } + } + + + System.out.println("delegation of preps done "); + } + + public void setBonderList(){ + int count = 0; + for (Map.Entry prep : preps.entrySet()) { + if (prep.getKey().equals(Address.fromString("hxb6b5791be0b5ef67063b3c10b840fb81514db2fd"))){ + continue; + } + if (count < 7) { + KeyWallet wallet = KeyWallet.load(new Bytes(prep.getValue())); + score.Address[] bonderList = new score.Address[1]; + bonderList[0] = score.Address.fromString(prep.getKey().toString()); + var client = new DefaultScoreClient( + chain.getEndpointURL(), + chain.networkId, + wallet, + DefaultScoreClient.ZERO_ADDRESS + ); + SYSTEM_INTERFACE = new SystemInterfaceScoreClient(client); + SYSTEM_INTERFACE.setBonderList(bonderList); + count++; + + + + } + else { + break; + } + + + } + System.out.println("the bonder list"); + + } + + public void setBondsofPreps(){ + int count = 0; + for (Map.Entry prep : preps.entrySet()) { + if (prep.getKey().equals(Address.fromString("hxb6b5791be0b5ef67063b3c10b840fb81514db2fd"))){ + continue; + } + if (count < 7){ + KeyWallet wallet = KeyWallet.load(new Bytes(prep.getValue())); + SystemInterface.Bond[] bond = new SystemInterface.Bond[1]; + bond[0] = new SystemInterface.Bond(); + bond[0].address = score.Address.fromString(prep.getKey().toString()); + bond[0].value = BigInteger.valueOf(10_000).multiply(BigInteger.TEN.pow(18)); + var client = new DefaultScoreClient( + chain.getEndpointURL(), + chain.networkId, + wallet, + DefaultScoreClient.ZERO_ADDRESS + ); + SYSTEM_INTERFACE = new SystemInterfaceScoreClient(client); + SYSTEM_INTERFACE.setBond(bond); + count++; + } + else { + break; + } + } + + System.out.println("bond of preps done "); + } + + public CPSClient defaultClient() { + return ownerClient; + } + + public CPSClient testClient() { + return testClient; } - public void setBondOfPreps(){ - KeyWallet[] keyWallets = {prepWallet1, prepWallet2, prepWallet3, prepWallet4, prepWallet5, prepWallet6, prepWallet7}; - setBond(keyWallets); + public void send(foundation.icon.jsonrpc.Address address, String method, Map params) { + iconClient.send(owner, address, BigInteger.ZERO, method, params, DefaultICONClient.DEFAULT_RESULT_TIMEOUT); } - public void setBonderListOfPReps(){ - KeyWallet[] keyWallets = {prepWallet1, prepWallet2, prepWallet3, prepWallet4, prepWallet5, prepWallet6, prepWallet7}; - setBonderList(keyWallets); + + + public String getScorePath(String key) { + String path = System.getProperty(key); + if (path == null) { + throw new IllegalArgumentException("No such property: " + key); + } + return path; } - public void deployContracts(){ - cpsCore = deploy(owner, "CPSCore", null); + public Callable deploy(Score score) { + return () -> _deploy(score); + } - Map cpsScoreAddress = Map.of("cps_score", cpsCore._address()); - cpsTreasury = deploy(owner, "CPSTreasury", cpsScoreAddress); - cpfTreasury = deploy(owner, "CPFTreasury", cpsScoreAddress); + public foundation.icon.jsonrpc.Address _deploy(Score score) { + return iconClient.deploy(owner, DefaultICONClient.ZERO_ADDRESS, score.getPath(), score.getParams()); + } + public boolean isPRepRegistered() { + try { + SYSTEM_INTERFACE = new SystemInterfaceScoreClient(godClient); + Map result = SYSTEM_INTERFACE.getPReps(BigInteger.ONE, BigInteger.valueOf(100)); + List registeredPReps = (List) result.get("preps"); + if (registeredPReps.size() >= 100) { + return true; + } + } catch (Exception e) { + + } + return false; + } - dex = deploy(owner, "Dex", null); + public CPSClient newClient(BigInteger balance) throws Exception { + CPSClient client = new CPSClient(this, createWalletWithBalance(balance)); + cpsClients.put(client.getAddress(), client); + return client; + } - Map bnUSDParams = Map.of( - "_name", "Balanced Dollar", - "_symbol", "bnUSD", - "_decimals", BigInteger.valueOf(18), - "_initialSupply", BigInteger.valueOf(100000000)); - bnusd = deploy(owner, "bnUSD", bnUSDParams); + public CPSClient customClient(String privateKey){ + CPSClient client = new CPSClient(this,KeyWallet.load(new Bytes(privateKey))); + cpsClients.put(client.getAddress(),client); + return client; + } - sicx = deploy(owner, "sICX", bnUSDParams); + public void deployPrep() { + if (isPRepRegistered()) { + return; + } + try { + + for (Map.Entry prep : preps.entrySet()) { + KeyWallet wallet = KeyWallet.load(new Bytes(prep.getValue())); + transfer(foundation.icon.jsonrpc.Address.of(wallet), BigInteger.TEN.pow(24)); + var client = new DefaultScoreClient( + chain.getEndpointURL(), + chain.networkId, + wallet, + DefaultScoreClient.ZERO_ADDRESS + ); + SYSTEM_INTERFACE = new SystemInterfaceScoreClient(client); + ((SystemInterfaceScoreClient) SYSTEM_INTERFACE).registerPRep( + BigInteger.valueOf(2000).multiply(BigInteger.TEN.pow(18)), prep.getKey().toString(), + "kokoa@example.com", + "USA", + "New York", "https://icon.kokoa.com", "https://icon.kokoa.com/json/details.json", + "localhost:9082"); + } + } catch (Exception e) { + + } + } - router = deploy(owner, "Router", null); + public Map getAddresses() { + return this.addresses; } - public void setScoreAddresses(){ - // CPS Main + public foundation.icon.jsonrpc.Address getAddress(String key) { + + return this.addresses.get(key); } } diff --git a/test-lib/src/main/java/community/icon/cps/score/test/integration/CPSClient.java b/test-lib/src/main/java/community/icon/cps/score/test/integration/CPSClient.java index 14a22959..24796969 100644 --- a/test-lib/src/main/java/community/icon/cps/score/test/integration/CPSClient.java +++ b/test-lib/src/main/java/community/icon/cps/score/test/integration/CPSClient.java @@ -1,25 +1,140 @@ package community.icon.cps.score.test.integration; +import community.icon.cps.score.test.integration.scores.SystemInterface; +import community.icon.cps.score.test.integration.scores.SystemInterfaceScoreClient; +import community.icon.cps.score.test.integration.scores.CPFTreasuryInterface; +import community.icon.cps.score.test.integration.scores.CPFTreasuryInterfaceScoreClient; +import community.icon.cps.score.test.integration.scores.CPSCoreInterface; +import community.icon.cps.score.test.integration.scores.CPSCoreInterfaceScoreClient; +import community.icon.cps.score.test.integration.scores.CPSTreasuryInterface; +import community.icon.cps.score.test.integration.scores.CPSTreasuryInterfaceScoreClient; +import community.icon.cps.score.test.integration.scores.DummyDex; +import community.icon.cps.score.test.integration.scores.DummyDexScoreClient; +import community.icon.cps.score.test.integration.scores.BalancedDollar; +import community.icon.cps.score.test.integration.scores.BalancedDollarScoreClient; +import community.icon.cps.score.test.integration.scores.Oracle; +import community.icon.cps.score.test.integration.scores.OracleScoreClient; +import community.icon.cps.score.test.integration.scores.Router; +import community.icon.cps.score.test.integration.scores.RouterScoreClient; +import community.icon.cps.score.test.integration.scores.sICX; +import community.icon.cps.score.test.integration.scores.sICXScoreClient; + import foundation.icon.icx.KeyWallet; -import foundation.icon.score.client.DefaultScoreClient; -import community.icon.cps.score.lib.interfaces.*; +import foundation.icon.jsonrpc.Address; +import foundation.icon.score.client.ScoreClient; + +import java.util.Map; +import java.util.Map.Entry; +import java.util.NoSuchElementException; +import java.util.stream.Collectors; + +import static community.icon.cps.score.test.integration.Environment.chain; -import static community.icon.cps.score.test.integration.ScoreIntegrationTest.chain; public class CPSClient { private final KeyWallet wallet; - public CPSTreasuryInterfaceScoreClient cpsTreasury; - public CPFTreasuryInterfaceScoreClient cpfTreasury; + private CPS cps; + private Map addressMap; + + @ScoreClient + public CPSTreasuryInterface cpsTreasury; + + @ScoreClient + public CPFTreasuryInterface cpfTreasury; + + @ScoreClient + public CPSCoreInterface cpsCore; + + @ScoreClient + public BalancedDollar bnUSD; + + @ScoreClient + public DummyDex dex; + + @ScoreClient + public Router router; + + @ScoreClient + public Oracle oracle; + + @ScoreClient + public sICX sICX; + + @ScoreClient + public SystemInterface systemScore; + public CPSClient(CPS cps, KeyWallet wallet){ + this.cps = cps; this.wallet = wallet; - cpsTreasury = new CPSTreasuryInterfaceScoreClient(chain.getEndpointURL(), chain.networkId, wallet, - cps.cpsTreasury._address()); - cpfTreasury = new CPFTreasuryInterfaceScoreClient(chain.getEndpointURL(), chain.networkId, wallet, cps.cpfTreasury._address()); + init(); + } + + private void init(){ + for (Entry entry : this.cps.getAddresses().entrySet()) { + switch (entry.getKey()){ + case "cpsCore": + cpsCore = new CPSCoreInterfaceScoreClient(chain.getEndpointURL(), chain.networkId, wallet, + entry.getValue()); + break; + case "cpsTreasury": + cpsTreasury = new CPSTreasuryInterfaceScoreClient(chain.getEndpointURL(), chain.networkId, wallet, + entry.getValue()); + break; + case "cpfTreasury": + cpfTreasury = new CPFTreasuryInterfaceScoreClient(chain.getEndpointURL(), chain.networkId, wallet, + entry.getValue()); + break; + case "bnUSD": + bnUSD = new BalancedDollarScoreClient(chain.getEndpointURL(), chain.networkId, wallet, + entry.getValue()); + break; + case "dex": + dex = new DummyDexScoreClient(chain.getEndpointURL(), chain.networkId, wallet, + entry.getValue()); + break; + case "router": + router = new RouterScoreClient(chain.getEndpointURL(), chain.networkId, wallet, + entry.getValue()); + break; + case "oracle": + oracle = new OracleScoreClient(chain.getEndpointURL(), chain.networkId, wallet, + entry.getValue()); + break; + case "sICX": + sICX = new sICXScoreClient(chain.getEndpointURL(), chain.networkId, wallet, + entry.getValue()); + break; + case "systemScore": + systemScore = new SystemInterfaceScoreClient(chain.getEndpointURL(), chain.networkId, wallet, + entry.getValue()); + break; + case "owner": + break; + default: + throw new NoSuchElementException(entry.getKey() + " score not found!!"); + + } + + } + } + + public Map getContractAddresses() { + if (addressMap == null) { + addressMap = this.cps.getAddresses().entrySet() + .stream() + .collect(Collectors.toMap(Entry::getKey, + entry -> score.Address.fromString(entry.getValue().toString()))); + } + return addressMap; } public score.Address getAddress() { return score.Address.fromString(wallet.getAddress().toString()); } + + public KeyWallet getWallet() { + return wallet; + } } diff --git a/test-lib/src/main/java/community/icon/cps/score/test/integration/Env.java b/test-lib/src/main/java/community/icon/cps/score/test/integration/Environment.java similarity index 52% rename from test-lib/src/main/java/community/icon/cps/score/test/integration/Env.java rename to test-lib/src/main/java/community/icon/cps/score/test/integration/Environment.java index d2fbadbf..b49ae961 100644 --- a/test-lib/src/main/java/community/icon/cps/score/test/integration/Env.java +++ b/test-lib/src/main/java/community/icon/cps/score/test/integration/Environment.java @@ -1,45 +1,84 @@ package community.icon.cps.score.test.integration; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import community.icon.cps.score.test.integration.scores.SystemInterface; import foundation.icon.icx.KeyWallet; import foundation.icon.icx.Wallet; import foundation.icon.icx.crypto.KeystoreException; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; +import foundation.icon.score.client.DefaultScoreClient; +import foundation.icon.score.client.ScoreClient; + +import java.io.*; import java.math.BigInteger; + import java.nio.file.Path; +import java.util.Map; import java.util.Properties; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.ClassOrderer; +import score.Address; + + + -public class Env { - private static Chain chain; +public class Environment { static { - String envFile = System.getProperty("env.props", "/Users/ibriz/icon-foundation-cps/cps_java_contracts/test-lib/conf/env.props"); + String envFile = System.getProperty("env.props","conf/env.props"); Properties props = new Properties(); try { - FileInputStream fis = new FileInputStream(envFile); - props.load(fis); - fis.close(); + InputStream is = ClassOrderer.ClassName.class.getClassLoader() + .getResourceAsStream(envFile); + props.load(is); + assert is != null; + is.close(); } catch (IOException e) { System.err.printf("'%s' does not exist\n", envFile); throw new IllegalArgumentException(e.getMessage()); } + +// FileInputStream configReader; +// try { +// configReader = new FileInputStream(envFile); +// } catch (FileNotFoundException e) { +// throw new RuntimeException(e); +// } +// Properties props = new Properties(); +// try { +// props.load(configReader); +// configReader.close(); +// } catch (IOException e) { +// throw new RuntimeException(e); +// } String confPath = Path.of(envFile).getParent().toString() + "/"; readProperties(props, confPath); } - private static void readProperties(Properties props, String confPath) { + public static Chain chain; + public static DefaultScoreClient godClient; + public static Map preps; + + @ScoreClient + public static SystemInterface SYSTEM_INTERFACE; + + private static void readProperties(Properties props, String confPath){ String chainName = "chain"; - String nid = props.getProperty(chainName + ".nid"); - if (nid == null) { + String nid = props.getProperty(chainName +".nid"); + if (nid == null){ throw new IllegalArgumentException("nid not found"); } + String godWalletPath = confPath + props.getProperty(chainName + ".godWallet"); + + String godPassword = props.getProperty(chainName + ".godPassword"); KeyWallet godWallet; try { godWallet = readWalletFromFile(godWalletPath, godPassword); + loadPREPs(confPath + "preps.json"); } catch (IOException e) { throw new IllegalArgumentException(e.getMessage()); } @@ -54,26 +93,39 @@ private static void readProperties(Properties props, String confPath) { throw new IllegalArgumentException("apiVersion not found"); } chain = new Chain(BigInteger.valueOf(Integer.parseInt(nid.substring(2), 16)), godWallet, url, apiVersion); + godClient = new DefaultScoreClient( + chain.getEndpointURL(), + chain.networkId, + chain.godWallet, + DefaultScoreClient.ZERO_ADDRESS + ); + } + + private static void loadPREPs(String path) throws IOException { + ObjectMapper objectMapper = new ObjectMapper(); + InputStream is = ClassLoader.getSystemResource(path).openStream(); + + preps = objectMapper.readValue(is, new TypeReference>() { + }); + } private static KeyWallet readWalletFromFile(String path, String password) throws IOException { + InputStream is = ClassLoader.getSystemResource(path).openStream(); try { - File file = new File(path); + File file = File.createTempFile("tmp", ".tmp"); + FileUtils.copyInputStreamToFile(is, file); return KeyWallet.load(password, file); } catch (KeystoreException e) { e.printStackTrace(); throw new IOException("Key load failed!"); + } finally { + IOUtils.closeQuietly(is); } } - public static Chain getDefaultChain() { - if (chain == null) { - throw new AssertionError("Chain not found"); - } - return chain; - } - public static class Chain { + public final BigInteger networkId; public final Wallet godWallet; private final String nodeUrl; diff --git a/test-lib/src/main/java/community/icon/cps/score/test/integration/ScoreDeployer.java b/test-lib/src/main/java/community/icon/cps/score/test/integration/ScoreDeployer.java new file mode 100644 index 00000000..cd5555ec --- /dev/null +++ b/test-lib/src/main/java/community/icon/cps/score/test/integration/ScoreDeployer.java @@ -0,0 +1,89 @@ +package community.icon.cps.score.test.integration; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import community.icon.cps.score.test.integration.model.Score; +import foundation.icon.jsonrpc.Address; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.stream.Collectors; + +public class ScoreDeployer { + + private String contracts; + private CPS cps; + + public ScoreDeployer(CPS cps, String contracts){ + this.contracts = contracts; + this.cps = cps; + } + + public Map deployContracts() throws IOException, InterruptedException { + Map> scores = readSCOREs(); + + ExecutorService exec = Executors.newFixedThreadPool(10); + + Map addresses = new HashMap<>(); + + addresses.put("owner", foundation.icon.jsonrpc.Address.of(cps.owner)); + + for (Map.Entry> entry : scores.entrySet()) { + Map> result = new HashMap<>(); + for (Score score : entry.getValue()) { + score.setPath(cps.getScorePath(score.getContract())); + System.out.println("deploying contract " + score.getName() + " :: " + score.getPath()); + Thread.sleep(200); + Map addressParams = score.getAddressParams(); + + for (Map.Entry params : addressParams.entrySet()) { + String key = params.getKey(); + String value = params.getValue(); + score.addParams(key, addresses.get(value)); + } + + result.put(score.getName(), exec.submit(cps.deploy(score))); + } + + for (Map.Entry> futureEntry : result.entrySet()) { + try { + foundation.icon.jsonrpc.Address address = futureEntry.getValue().get(); + String name = futureEntry.getKey(); + addresses.put(name, address); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(futureEntry.getKey() + " -- " + e.getMessage()); + } + } + } + + exec.shutdown(); + + return addresses; + } + + + + private Map> readSCOREs() throws IOException { + + ObjectMapper objectMapper = new ObjectMapper(); + InputStream is = this.getClass() + .getClassLoader() + .getResourceAsStream(this.contracts); + + List list = objectMapper.readValue(is, new TypeReference>() { + }); + return list.stream() + .sorted((x, y) -> Float.compare(y.getOrder(), x.getOrder())) + .collect(Collectors.groupingBy(Score::getOrder, Collectors.toList())); + + } +} diff --git a/test-lib/src/main/java/community/icon/cps/score/test/integration/ScoreIntegrationTest.java b/test-lib/src/main/java/community/icon/cps/score/test/integration/ScoreIntegrationTest.java index 4390c289..ce1ddc91 100644 --- a/test-lib/src/main/java/community/icon/cps/score/test/integration/ScoreIntegrationTest.java +++ b/test-lib/src/main/java/community/icon/cps/score/test/integration/ScoreIntegrationTest.java @@ -1,181 +1,39 @@ package community.icon.cps.score.test.integration; -import community.icon.cps.score.lib.interfaces.SystemInterface; import foundation.icon.icx.KeyWallet; import foundation.icon.icx.Wallet; -import foundation.icon.icx.data.Bytes; import foundation.icon.jsonrpc.Address; -import foundation.icon.jsonrpc.model.Hash; import foundation.icon.jsonrpc.model.TransactionResult; import foundation.icon.score.client.DefaultScoreClient; import foundation.icon.score.client.RevertedException; -import community.icon.cps.score.lib.interfaces.SystemInterfaceScoreClient; -import net.bytebuddy.pool.TypePool; import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.function.Executable; import score.UserRevertedException; -import java.io.BufferedReader; -import java.io.FileOutputStream; -import java.io.FileReader; -import java.io.PrintStream; import java.math.BigInteger; import java.security.InvalidAlgorithmParameterException; -import java.security.Key; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.util.List; import java.util.Map; import java.util.Properties; +import java.util.Random; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; -import static community.icon.cps.score.test.integration.Env.Chain; -import static community.icon.cps.score.test.integration.Env.getDefaultChain; +import static community.icon.cps.score.test.integration.Environment.godClient; +import static foundation.icon.jsonrpc.IconJsonModule.hexToBytes; import static org.junit.jupiter.api.Assertions.assertEquals; -import static community.icon.cps.score.lib.interfaces.SystemInterface.Delegation; -import static community.icon.cps.score.lib.interfaces.SystemInterface.Bond; @Tag("integration") @TestMethodOrder(value = MethodOrderer.OrderAnnotation.class) public interface ScoreIntegrationTest { - Chain chain = getDefaultChain(); - DefaultScoreClient godClient = new DefaultScoreClient(chain.getEndpointURL(), chain.networkId, chain.godWallet, - DefaultScoreClient.ZERO_ADDRESS); - DefaultScoreClient client = new DefaultScoreClient(chain.getEndpointURL(), chain.networkId, null, null); - - SystemInterfaceScoreClient systemScore = new SystemInterfaceScoreClient(godClient); - public static final BigInteger EXA = BigInteger.valueOf(1_000_000_000_000_000_000L); - - @SuppressWarnings("unchecked") - static void registerPreps() throws Exception { - - Map getPreps; - String privateKey = ""; - - try { - getPreps = systemScore.getPReps(BigInteger.ONE, BigInteger.valueOf(7)); - } catch (Exception e) { - privateKey = registerPrep(); - getPreps = systemScore.getPReps(BigInteger.ONE, BigInteger.valueOf(7)); - } - - List> prepList = (List>) getPreps.get("preps"); - int prepCount = prepList.size(); - if (prepCount >= 7) { - return; - } - int remainingPrepsToRegister = 7 - prepCount; - for (int i = 0; i < remainingPrepsToRegister; i++) { - privateKey = privateKey + registerPrep(); - } - PrintStream out = new PrintStream(new FileOutputStream("privateKey.txt")); - System.out.println("private keys: " + privateKey); - out.println(privateKey); - BufferedReader br = new BufferedReader(new FileReader("privateKey.txt")); - System.out.println("Reading the content of the file: " + br.readLine()); - } - - private static String registerPrep() throws Exception { - KeyWallet owner = createWalletWithBalance(BigInteger.TEN.pow(24)); - String privateKey = String.valueOf(owner.getPrivateKey()); -// PrintStream out = new PrintStream(new FileOutputStream("privateKey.txt")); -// System.out.println("private keys: " + privateKey); -// out.println(privateKey); - DefaultScoreClient godClient = new DefaultScoreClient(chain.getEndpointURL(), chain.networkId, owner, - DefaultScoreClient.ZERO_ADDRESS); - SystemInterfaceScoreClient systemScore = new SystemInterfaceScoreClient(godClient); - systemScore.registerPRep(BigInteger.valueOf(2000).multiply(BigInteger.TEN.pow(18)), "test", - "kokoa@example.com", "USA", "New York", "https://icon.kokoa.com", - "https://icon.kokoa.com/json/details.json", "localhost:9082"); - return privateKey; - } - - public static void registerGodClient() { - systemScore.registerPRep(BigInteger.valueOf(2000).multiply(BigInteger.TEN.pow(18)), "test", - "kokoa@example.com", "USA", "New York", "https://icon.kokoa.com", - "https://icon.kokoa.com/json/details.json", "localhost:9082"); - - } - - public static void registerPrepByPrivateKey(KeyWallet owner){ - DefaultScoreClient godClient = new DefaultScoreClient(chain.getEndpointURL(), chain.networkId, owner, - DefaultScoreClient.ZERO_ADDRESS); - SystemInterfaceScoreClient systemScore = new SystemInterfaceScoreClient(godClient); - systemScore.registerPRep(BigInteger.valueOf(2000).multiply(BigInteger.TEN.pow(18)), "test", - "kokoa@example.com", "USA", "New York", "https://icon.kokoa.com", - "https://icon.kokoa.com/json/details.json", "localhost:9082"); - } - - public static void setStake(KeyWallet[] owner) { - for (int i = 0; i < owner.length; i++) { - DefaultScoreClient godClient = new DefaultScoreClient(chain.getEndpointURL(), chain.networkId, owner[i], - DefaultScoreClient.ZERO_ADDRESS); - SystemInterfaceScoreClient systemScore = new SystemInterfaceScoreClient(godClient); - systemScore.setStake(BigInteger.valueOf(1000).multiply(EXA)); - } - } - - public static void setGodStake(){ - systemScore.setStake(BigInteger.valueOf(9000000).multiply(EXA)); - Delegation[] delegation = new Delegation[1]; - delegation[0] = new Delegation(); - delegation[0].address = score.Address.fromString(chain.godWallet.getAddress().toString()); - delegation[0].value = BigInteger.valueOf(8000000).multiply(EXA); - systemScore.setDelegation(delegation); - - score.Address[] addresses = new score.Address[1]; - addresses[0] = score.Address.fromString(chain.godWallet.getAddress().toString()); - systemScore.setBonderList(addresses); - - Bond[] bonds = new Bond[1]; - bonds[0] = new Bond(); - bonds[0].address = score.Address.fromString(chain.godWallet.getAddress().toString()); - bonds[0].value = BigInteger.valueOf(1000000).multiply(EXA); - systemScore.setBond(bonds); - } - public static void setDelegation(KeyWallet[] owner){ - for (int i = 0; i < owner.length; i++) { - Delegation[] delegations = new Delegation[1]; - delegations[0] = new Delegation(); - delegations[0].address = score.Address.fromString(owner[i].getAddress().toString()); - delegations[0].value = BigInteger.valueOf(400).multiply(EXA); - DefaultScoreClient godClient = new DefaultScoreClient(chain.getEndpointURL(), chain.networkId, owner[i], - DefaultScoreClient.ZERO_ADDRESS); - SystemInterfaceScoreClient systemScore = new SystemInterfaceScoreClient(godClient); - systemScore.setDelegation(delegations); - } - } - - public static void setBond(KeyWallet[] owner) { - for (int i = 0; i < owner.length; i++) { - Bond[] bond = new Bond[1]; - bond[0] = new Bond(); - bond[0].address = score.Address.fromString(owner[i].getAddress().toString()); - bond[0].value = BigInteger.valueOf(400).multiply(EXA); - DefaultScoreClient godClient = new DefaultScoreClient(chain.getEndpointURL(), chain.networkId, owner[i], - DefaultScoreClient.ZERO_ADDRESS); - SystemInterfaceScoreClient systemScore = new SystemInterfaceScoreClient(godClient); - systemScore.setBond(bond); - } - } - - public static void setBonderList(KeyWallet[] owner){ - for (int i = 0; i < owner.length; i++) { - score.Address[] bonderList = new score.Address[1]; - bonderList[0] = score.Address.fromString(owner[i].getAddress().toString()); - DefaultScoreClient godClient = new DefaultScoreClient(chain.getEndpointURL(), chain.networkId, owner[i], - DefaultScoreClient.ZERO_ADDRESS); - SystemInterfaceScoreClient systemScore = new SystemInterfaceScoreClient(godClient); - systemScore.setBonderList(bonderList); - } - } static KeyWallet createWalletWithBalance(BigInteger amount) throws Exception { KeyWallet wallet = KeyWallet.create(); @@ -188,28 +46,6 @@ static void transfer(Address address, BigInteger amount) { godClient._transfer(address, amount, null); } - static DefaultScoreClient deploy(Wallet wallet, String name, Map params) { - String path = getFilePath(name); - return DefaultScoreClient._deploy(chain.getEndpointURL(), chain.networkId, wallet, path, params); - } - - static Hash deployAsync(Wallet wallet, String name, Map params) { - String path = getFilePath(name); - return DefaultScoreClient._deployAsync(chain.getEndpointURL(), chain.networkId, wallet, path, params); - } - - static DefaultScoreClient getDeploymentResult(Wallet wallet, Hash hash) { - return DefaultScoreClient.getDeploymentResult(chain.getEndpointURL(), chain.networkId, wallet, hash); - } - - static String getFilePath(String key) { - String path = System.getProperty(key); - if (path == null) { - throw new IllegalArgumentException("No such property: " + key); - } - return path; - } - static int indexOf(T[] array, T value) { return indexOf(array, value::equals); } @@ -231,13 +67,19 @@ static boolean contains(Map map, String key, Predicate predica return map.containsKey(key) && predicate.test(map.get(key)); } - static List eventLogs(TransactionResult txr, String signature, Address scoreAddress, - Function mapperFunc, Predicate filter) { - Predicate predicate = (el) -> el.getIndexed().get(0).equals(signature); + static List eventLogs(TransactionResult txr, + String signature, + Address scoreAddress, + Function mapperFunc, + Predicate filter) { + Predicate predicate = + (el) -> el.getIndexed().get(0).equals(signature); if (scoreAddress != null) { - predicate = predicate.and((el) -> el.getScoreAddress().toString().equals(scoreAddress.toString())); + predicate = predicate.and((el) -> el.getScoreAddress().equals(scoreAddress)); } - Stream stream = txr.getEventLogs().stream().filter(predicate).map(mapperFunc); + Stream stream = txr.getEventLogs().stream() + .filter(predicate) + .map(mapperFunc); if (filter != null) { stream = stream.filter(filter); } @@ -245,7 +87,7 @@ static List eventLogs(TransactionResult txr, String signature, Address sc } static void waitByNumOfBlock(long numOfBlock) { - waitByHeight(client._lastBlockHeight().add(BigInteger.valueOf(numOfBlock))); + waitByHeight(godClient._lastBlockHeight().add(BigInteger.valueOf(numOfBlock))); } static void waitByHeight(long waitHeight) { @@ -253,7 +95,7 @@ static void waitByHeight(long waitHeight) { } static void waitByHeight(BigInteger waitHeight) { - BigInteger height = client._lastBlockHeight(); + BigInteger height = godClient._lastBlockHeight(); while (height.compareTo(waitHeight) < 0) { System.out.println("height: " + height + ", waitHeight: " + waitHeight); try { @@ -261,12 +103,12 @@ static void waitByHeight(BigInteger waitHeight) { } catch (InterruptedException e) { e.printStackTrace(); } - height = client._lastBlockHeight(); + height = godClient._lastBlockHeight(); } } static void balanceCheck(Address address, BigInteger value, Executable executable) { - BigInteger balance = client._balance(address); + BigInteger balance = godClient._balance(address); try { executable.execute(); } catch (UserRevertedException | RevertedException e) { @@ -274,11 +116,12 @@ static void balanceCheck(Address address, BigInteger value, Executable executabl } catch (Throwable e) { throw new RuntimeException(e); } - assertEquals(balance.add(value), client._balance(address)); + assertEquals(balance.add(value), godClient._balance(address)); } @FunctionalInterface interface EventLogsSupplier { + List apply(TransactionResult txr, Address address, Predicate filter); } @@ -293,8 +136,8 @@ static Consumer eventLogChecker( }; } - static Consumer eventLogsChecker(Address address, EventLogsSupplier supplier, - Consumer> consumer) { + static Consumer eventLogsChecker( + Address address, EventLogsSupplier supplier, Consumer> consumer) { return (txr) -> { List eventLogs = supplier.apply(txr, address, null); if (consumer != null) { @@ -303,11 +146,7 @@ static Consumer eventLogsChecker(Address address, EventLo }; } - static Consumer dummyConsumer() { - return (txr) -> { - - }; - } + Wallet tester = getOrGenerateWallet("tester.", System.getProperties()); static Wallet getOrGenerateWallet(String prefix, Properties properties) { Wallet wallet = DefaultScoreClient.wallet(prefix, properties); @@ -321,6 +160,24 @@ static KeyWallet generateWallet() { throw new RuntimeException(e); } } + + interface Faker { + + com.github.javafaker.Faker faker = new com.github.javafaker.Faker(); + Random random = new Random(); + + static Address address(Address.Type type) { + byte[] body = hexToBytes(faker.crypto().sha256().substring(0, (Address.LENGTH - 1) * 2)); + return new Address(type, body); + } + + static byte[] bytes(int length) { + byte[] bytes = new byte[length]; + random.nextBytes(bytes); + return bytes; + } + } + } diff --git a/test-lib/src/main/java/community/icon/cps/score/test/integration/config/BaseConfig.java b/test-lib/src/main/java/community/icon/cps/score/test/integration/config/BaseConfig.java new file mode 100644 index 00000000..1ae48a7e --- /dev/null +++ b/test-lib/src/main/java/community/icon/cps/score/test/integration/config/BaseConfig.java @@ -0,0 +1,78 @@ +package community.icon.cps.score.test.integration.config; + +import com.eclipsesource.json.JsonObject; +import community.icon.cps.score.test.integration.CPS; +import community.icon.cps.score.test.integration.CPSClient; +import community.icon.cps.score.test.integration.Environment; +import score.Address; + +import java.math.BigInteger; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +import static community.icon.cps.score.test.integration.Environment.preps; + +public class BaseConfig { + + protected Map addressMap; + protected CPSClient cpsClient; + + public static final BigInteger EXA = BigInteger.valueOf(1000000000000000000L); + public BaseConfig(CPSClient cpsClient){ + this.cpsClient = cpsClient; + this.addressMap = cpsClient.getContractAddresses(); + } + + + public void call(){ + System.out.println("--------init base setup for cps-----------"); + System.out.println("--------admin set -----------"); + this.cpsClient.cpsCore.addAdmin(this.cpsClient.getAddress()); + + + System.out.println("------setting scores in cpscore------"); + cpsClient.cpsCore.setCpsTreasuryScore(addressMap.get("cpsTreasury")); + cpsClient.cpsCore.setCpfTreasuryScore(addressMap.get("cpfTreasury")); + cpsClient.cpsCore.setBnusdScore(addressMap.get("bnUSD")); + + System.out.println("------setting scores in cps treasury-----"); + cpsClient.cpsTreasury.setCpfTreasuryScore(addressMap.get("cpfTreasury")); + cpsClient.cpsTreasury.setBnUSDScore(addressMap.get("bnUSD")); + + System.out.println("--------setting score in cpf treasury -------"); + cpsClient.cpfTreasury.setCpsTreasuryScore(addressMap.get("cpsTreasury")); + cpsClient.cpfTreasury.setBnUSDScore(addressMap.get("bnUSD")); + cpsClient.cpfTreasury.setDexScore(addressMap.get("dex")); + cpsClient.cpfTreasury.setOracleAddress(addressMap.get("oracle")); + cpsClient.cpfTreasury.setRouterScore(addressMap.get("router")); + cpsClient.cpfTreasury.setSicxScore(addressMap.get("sICX")); + + System.out.println("----setting in dex----------"); + cpsClient.dex.setSicxScore(addressMap.get("sICX")); + + System.out.println("------setting funds--------"); + cpsClient.cpfTreasury.setMaximumTreasuryFundIcx(BigInteger.valueOf(1000).multiply(EXA)); + cpsClient.cpfTreasury.setMaximumTreasuryFundBnusd(BigInteger.valueOf(10000).multiply(EXA)); +// this.cpsClient.bnUSD.setMinter(this.cpsClient.getAddress()); + cpsClient.bnUSD.mintTo(addressMap.get("cpfTreasury"),BigInteger.valueOf(5000).multiply(EXA) ); + + JsonObject burnTokens = new JsonObject(); + burnTokens.add("method","_dex"); + + cpsClient.sICX.mintWithTokenFallBack(addressMap.get("dex"),BigInteger.valueOf(10000).multiply(EXA),burnTokens.toString().getBytes()); +// cpsClient.sICX.mintWithTokenFallBack(addressMap.get("cpfTreasury"),BigInteger.valueOf(100).multiply(EXA),"None".getBytes()); + + System.out.println(cpsClient.sICX.balanceOf(addressMap.get("dex"))); + + cpsClient.cpfTreasury.toggleSwapFlag(); + + cpsClient.cpsCore.toggleMaintenance(); + cpsClient.cpsCore.setInitialBlock(); + cpsClient.cpsCore.setPrepPenaltyAmount(new BigInteger[]{BigInteger.valueOf(2),BigInteger.valueOf(5),BigInteger.TEN}); + + + System.out.println("------system score------- " + addressMap.get("systemScore")); + + } +} diff --git a/test-lib/src/main/java/community/icon/cps/score/test/integration/model/Score.java b/test-lib/src/main/java/community/icon/cps/score/test/integration/model/Score.java new file mode 100644 index 00000000..a49e6515 --- /dev/null +++ b/test-lib/src/main/java/community/icon/cps/score/test/integration/model/Score.java @@ -0,0 +1,81 @@ +package community.icon.cps.score.test.integration.model; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import foundation.icon.jsonrpc.Address; +import java.util.Map; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class Score { + + private String name; + private String contract; + private String path; + private Map params; + private Map addressParams; + private Address address; + private float order; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public Map getParams() { + return params; + } + + public void setParams(Map params) { + this.params = params; + } + + public Address getAddress() { + return address; + } + + public void setAddress(Address address) { + this.address = address; + } + + public float getOrder() { + return order; + } + + public void setOrder(float order) { + this.order = order; + } + + public String getContract() { + return contract == null ? name : contract; + } + + public void setContract(String contract) { + this.contract = contract; + } + + public Map getAddressParams() { + if (addressParams == null) { + return Map.of(); + } + return addressParams; + } + + public void setAddressParams(Map addressParams) { + this.addressParams = addressParams; + } + + public void addParams(String key, Object value) { + this.params.put(key, value); + } +} + diff --git a/test-lib/src/main/java/community/icon/cps/score/test/integration/scores/BalancedDollar.java b/test-lib/src/main/java/community/icon/cps/score/test/integration/scores/BalancedDollar.java new file mode 100644 index 00000000..e2af737a --- /dev/null +++ b/test-lib/src/main/java/community/icon/cps/score/test/integration/scores/BalancedDollar.java @@ -0,0 +1,29 @@ +package community.icon.cps.score.test.integration.scores; + +import score.Address; +import score.annotation.External; +import score.annotation.Optional; + +import java.math.BigInteger; + +public interface BalancedDollar { + + @External(readonly = true) + BigInteger balanceOf(Address _owner); + + @External + void mint(BigInteger _amount, @Optional byte[] _data); + + @External + void mintTo(Address to, BigInteger amount); + + @External + void setMinter(Address _address); + + @External(readonly = true) + Address getMinter(); + + @External + void transfer(Address _to, BigInteger _value, @Optional byte[] _data); + +} diff --git a/test-lib/src/main/java/community/icon/cps/score/test/integration/scores/CPFTreasuryInterface.java b/test-lib/src/main/java/community/icon/cps/score/test/integration/scores/CPFTreasuryInterface.java new file mode 100644 index 00000000..f03ea500 --- /dev/null +++ b/test-lib/src/main/java/community/icon/cps/score/test/integration/scores/CPFTreasuryInterface.java @@ -0,0 +1,149 @@ +package community.icon.cps.score.test.integration.scores; + + +import score.Address; +import score.annotation.EventLog; +import score.annotation.External; +import score.annotation.Optional; +import score.annotation.Payable; + +import java.math.BigInteger; +import java.util.Map; + +public interface CPFTreasuryInterface { + @External(readonly = true) + String name(); + + @External + void setCpsScore(Address score); + + @External(readonly = true) + Address getCpsScore(); + + @External + void setCpsTreasuryScore(Address score); + + @External(readonly = true) + Address getCpsTreasuryScore(); + + @External + void setBnUSDScore(Address score); + + @External(readonly = true) + Address getBnUSDScore(); + + @External + void setSicxScore(Address score); + + @External(readonly = true) + Address getSicxScore(); + + @External + void setDexScore(Address score); + + @External(readonly = true) + Address getDexScore(); + + @External + void setRouterScore(Address score); + + @External(readonly = true) + Address getRouterScore(); + + @External + void setOracleAddress(Address score); + + @External(readonly = true) + Address getOracleAddress(); + + @External + void setSponsorBondPercentage(BigInteger bondValue); + + @External + void setPeriod(BigInteger applicationPeriod); + + @External + void setOnsetPayment(BigInteger paymentPercentage); + + @External(readonly = true) + int getSlippagePercentage(); + + @External(readonly = true) + BigInteger getEmergencyFund(); + + @External + void setMaximumTreasuryFundIcx(BigInteger value); + + @External + 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 addFund(); + + @External + void swapICXToBnUSD(BigInteger amount, @Optional BigInteger _minReceive); + + @External + void swapTokens(int _count); + + @External(readonly = true) + Map getSwapStateStatus(); + + @External + void resetSwapState(); + + @External(readonly = true) + 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) + void FundReturned(Address _sponsor_address, String note); + + @EventLog(indexed = 1) + void ProposalFundTransferred(String _ipfs_key, String note); + + @EventLog(indexed = 1) + void ProposalDisqualified(String _ipfs_key, String note); + + @EventLog(indexed = 1) + void FundReceived(Address _sponsor_address, String note); + + @EventLog(indexed = 1) + void EmergencyFundTransferred(Address _address, BigInteger _value, String _purpose); +} diff --git a/test-lib/src/main/java/community/icon/cps/score/test/integration/scores/CPSCoreInterface.java b/test-lib/src/main/java/community/icon/cps/score/test/integration/scores/CPSCoreInterface.java new file mode 100644 index 00000000..11c3ffe9 --- /dev/null +++ b/test-lib/src/main/java/community/icon/cps/score/test/integration/scores/CPSCoreInterface.java @@ -0,0 +1,343 @@ +package community.icon.cps.score.test.integration.scores; + + +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; +import java.util.List; +import java.util.Map; + +public interface CPSCoreInterface { + + public static class ProposalAttributes { + public String ipfs_hash; + public String project_title; + public int project_duration; + public BigInteger total_budget; + public String token; + public Address sponsor_address; + public String ipfs_link; + public int milestoneCount; + public Boolean isMilestone; + + } + + public static class ProgressReportAttributes { + public String ipfs_hash; + public String report_hash; + public String ipfs_link; + public String progress_report_title; + public Boolean budget_adjustment; + public BigInteger additional_budget; + public int additional_month; +// 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) + String name(); + + String proposalPrefix(String proposalKey); + + String progressReportPrefix(String progressKey); + + @External + void setCpsTreasuryScore(Address score); + + @External(readonly = true) + Address getCpsTreasuryScore(); + + @External + void setCpfTreasuryScore(Address score); + + @External(readonly = true) + Address getCpfTreasuryScore(); + + + @External + void setBnusdScore(Address score); + + + @External(readonly = true) + Address getBnusdScore(); + + + @External(readonly = true) + boolean isAdmin(Address address); + + @External + void toggleBudgetAdjustmentFeature(); + + @External(readonly = true) + boolean getBudgetAdjustmentFeature(); + + + @External + void toggleMaintenance(); + + @External(readonly = true) + boolean getMaintenanceMode(); + + @Payable + void fallback(); + + + @External + void addAdmin(Address address); + + + @External + void removeAdmin(Address address); + + + @External + void unregisterPrep(); + + + @External + void registerPrep(); + + @External(readonly = true) + boolean checkPriorityVoting(Address _prep); + + @External(readonly = true) + List sortPriorityProposals(); + + @External(readonly = true) + Map getPriorityVoteResult(); + + @External(readonly = true) + Map getMilestonesReport(String ipfsKey, int milestoneId); + + @External + void votePriority(String[] _proposals); + + @External(readonly = true) + List> getActiveProposals(Address walletAddress); + + + @External + void setPrepPenaltyAmount(BigInteger[] penalty); + + + @External + void setInitialBlock(); + + + @External(readonly = true) + Map loginPrep(Address address); + + + @External(readonly = true) + List
getAdmins(); + + @SuppressWarnings("unchecked") + + @External(readonly = true) + Map getRemainingFund(); + + + @External(readonly = true) + List> getPReps(); + + + @External(readonly = true) + List
getDenylist(); + + + @External(readonly = true) + Map getPeriodStatus(); + + + @External(readonly = true) + List
getContributors(); + + + @External(readonly = true) + Map checkClaimableSponsorBond(Address address); + + + @Payable + @External + void submitProposal(community.icon.cps.score.lib.interfaces.CPSCoreInterface.ProposalAttributes proposals, community.icon.cps.score.lib.interfaces.CPSCoreInterface.MilestonesAttributes[] milestones); + + + @External + void voteProposal(String ipfsKey, String vote, String voteReason, @Optional boolean voteChange); + + + @External + void submitProgressReport(community.icon.cps.score.lib.interfaces.CPSCoreInterface.ProgressReportAttributes progressReport, community.icon.cps.score.lib.interfaces.CPSCoreInterface.MilestoneSubmission[] milestoneSubmissions); + + + @External + void voteProgressReport(String reportKey, String voteReason, community.icon.cps.score.lib.interfaces.CPSCoreInterface.MilestoneVoteAttributes[] votes, @Optional String budgetAdjustmentVote, @Optional boolean voteChange); + + + @External(readonly = true) + List getProposalsKeysByStatus(String status); + + @External(readonly = true) + Map getMilestoneVoteResult(String reportKey, int milestoneId); + + @External(readonly = true) + int getMileststoneStatusOf(String proposalKey, int milestoneId); + + + + @External(readonly = true) + int checkChangeVote(Address address, String ipfsHash, String proposalType); + + + @External(readonly = true) + Map getProjectAmounts(); + + + @External(readonly = true) + Map getSponsorsRecord(); + + @External + void updatePeriod(); + + + @External(readonly = true) + Map getProposalDetails(String status, @Optional Address walletAddress, @Optional int startIndex); + + @External(readonly = true) + Map getProposalDetailsByHash(String ipfsKey); + + + @External(readonly = true) + Map getProgressReports(String status, @Optional int startIndex); + + + @External(readonly = true) + Map getProgressReportsByHash(String reportKey); + + + @External(readonly = true) + Map getProgressReportsByProposal(String ipfsKey); + + + @External(readonly = true) + Map getSponsorsRequests(String status, Address sponsorAddress, @Optional int startIndex); + + @External(readonly = true) + Map getVoteResult(String ipfsKey); + + @External(readonly = true) + Map getProgressReportResult(String reportKey); + + @External(readonly = true) + Map getBudgetAdjustmentVoteResult(String reportKey); + + @External + void tokenFallback(Address from, BigInteger value, byte[] data); + + @External + void removeDenylistPreps(); + + @External + void claimSponsorBond(); + + @External + void setPeriod(BigInteger applicationPeriod); + + @External + void setSwapCount(int value); + + @External + void updateNextBlock(int blockCount); + + @External(readonly = true) + List> getRemainingProject(String projectType, Address walletAddress); + + @External + void updateContributor(String _ipfs_key, Address _new_contributor, Address _new_sponsor); + + + @External(readonly = true) + Map getActiveProposalsList(@Optional int startIndex); + + @External(readonly = true) + Map getProposalDetailByWallet(Address walletAddress, @Optional int startIndex); + + @External(readonly = true) + Map getProposalsHistory(@Optional int startIndex); + + @External(readonly = true) + List> getRemainingMilestones(String ipfsHash); + + // EventLogs + @EventLog(indexed = 1) + void ProposalSubmitted(Address _sender_address, String note); + + @EventLog(indexed = 1) + void ProgressReportSubmitted(Address _sender_address, String _project_title); + + @EventLog(indexed = 1) + void SponsorBondReceived(Address _sender_address, String _notes); + + @EventLog(indexed = 1) + void SponsorBondRejected(Address _sender_address, String _notes); + + @EventLog(indexed = 1) + void VotedSuccessfully(Address _sender_address, String _notes); + + @EventLog(indexed = 1) + void PRepPenalty(Address _prep_address, String _notes); + + @EventLog(indexed = 1) + void UnRegisterPRep(Address _sender_address, String _notes); + + @EventLog(indexed = 1) + void RegisterPRep(Address _sender_address, String _notes); + + @EventLog(indexed = 1) + void SponsorBondReturned(Address _sender_address, String _notes); + + @EventLog(indexed = 1) + void PeriodUpdate(String _notes); + + @EventLog(indexed = 1) + void SponsorBondClaimed(Address _receiver_address, BigInteger _fund, String note); + + @EventLog(indexed = 1) + void PriorityVote(Address _address, String note); + + @EventLog(indexed = 1) + void UpdateContributorAddress(Address _old, Address _new); + + @EventLog(indexed = 1) + void UpdateSponsorAddress(Address _old, Address _new); + + @External(readonly = true) + int getPeriodCount(); + + @External + void setSponsorBondPercentage(BigInteger bondValue); + + @External(readonly = true) + BigInteger getSponsorBondPercentage(); +} \ No newline at end of file diff --git a/test-lib/src/main/java/community/icon/cps/score/test/integration/scores/CPSTreasuryInterface.java b/test-lib/src/main/java/community/icon/cps/score/test/integration/scores/CPSTreasuryInterface.java new file mode 100644 index 00000000..8b9cff1b --- /dev/null +++ b/test-lib/src/main/java/community/icon/cps/score/test/integration/scores/CPSTreasuryInterface.java @@ -0,0 +1,91 @@ +package community.icon.cps.score.test.integration.scores; + +import score.Address; +import score.annotation.EventLog; +import score.annotation.External; +import score.annotation.Payable; + +import java.math.BigInteger; +import java.util.List; +import java.util.Map; + +public interface CPSTreasuryInterface { + @External(readonly = true) + String name(); + + @Payable + void fallback(); + + @External + void setCpsScore(Address score); + + @External(readonly = true) + Address getCpsScore(); + + @External + void setCpfTreasuryScore(Address score); + + @External(readonly = true) + Address getCpfTreasuryScore(); + + @External + void setBnUSDScore(Address score); + + @External(readonly = true) + Address getBnUSDScore(); + + @External(readonly = true) + Map getContributorProjectedFund(Address walletAddress); + + @External(readonly = true) + List getContributorProjects(Address address); + + @External(readonly = true) + List getSponsorProjects(Address address); + + @External(readonly = true) + Map getSponsorProjectedFund(Address walletAddress); + + @External + @Payable + void updateProposalFund(String ipfsKey, BigInteger addedBudget, BigInteger addedSponsorReward, + int addedInstallmentCount); + + @External + void sendInstallmentToContributor(String ipfsKey, BigInteger milestoneBudget); + + @External + void sendRewardToSponsor(String ipfsKey, int installmentCount); + + @External + void disqualifyProject(String ipfsKey); + + @External + void claimReward(); + + @External + void tokenFallback(Address from, BigInteger value, byte[] _data); + + @External + void setOnsetPayment(BigInteger paymentPercentage); + + @External(readonly = true) + BigInteger getOnsetPayment(); + + @External + void updateContributorSponsorAddress(String _ipfs_key, Address _new_contributor_address, + Address _new_sponsor_address); + + @EventLog(indexed = 1) + void ProposalDisqualified(String _ipfs_key, String note); + + @EventLog(indexed = 1) + void ProposalFundDeposited(String _ipfs_key, String note); + + @EventLog(indexed = 1) + void ProposalFundSent(Address _receiver_address, String note); + + @EventLog(indexed = 1) + void ProposalFundWithdrawn(Address _receiver_address, String note); +} + diff --git a/test-lib/src/main/java/community/icon/cps/score/test/integration/scores/DummyDex.java b/test-lib/src/main/java/community/icon/cps/score/test/integration/scores/DummyDex.java new file mode 100644 index 00000000..c245d67c --- /dev/null +++ b/test-lib/src/main/java/community/icon/cps/score/test/integration/scores/DummyDex.java @@ -0,0 +1,58 @@ +package community.icon.cps.score.test.integration.scores; + +import score.Address; +import score.annotation.External; +import score.annotation.Optional; + +import java.math.BigInteger; +import java.util.Map; + +public interface DummyDex { + + void mint(BigInteger _id, BigInteger _supply); + + void mintTo(BigInteger _id, Address _account, BigInteger _supply); + + Map getPoolStats(BigInteger _id); + + BigInteger getPriceByName(String _name); + + BigInteger lookupPid(String _name); + + BigInteger getBalnPrice(); + + @External(readonly = true) + BigInteger getPrice(BigInteger _id); + + void transfer(Address _to, BigInteger _value, BigInteger _id, @Optional byte[] _data); + BigInteger balanceOf(Address _owner, BigInteger _id); + + + BigInteger[] balanceOfBatch(Address[] _owners, BigInteger[] _ids); + + String tokenURI(BigInteger _id); + + void transferFrom(Address _from, Address _to, BigInteger _id, BigInteger _value, @Optional byte[] _data); + + void transferFromBatch(Address _from, Address _to, BigInteger[] _ids, BigInteger[] _values, @Optional byte[] _data); + + + void setApprovalForAll(Address _operator, boolean _approved); + + + boolean isApprovedForAll(Address _owner, Address _operator); + + + + void TransferSingle(Address _operator, Address _from, Address _to, BigInteger _id, BigInteger _value); + + void TransferBatch(Address _operator, Address _from, Address _to, byte[] _ids, byte[] _values); + + + void ApprovalForAll(Address _owner, Address _operator, boolean _approved); + + + void URI(BigInteger _id, String _value); + + void setSicxScore(Address _score); +} diff --git a/test-lib/src/main/java/community/icon/cps/score/test/integration/scores/Oracle.java b/test-lib/src/main/java/community/icon/cps/score/test/integration/scores/Oracle.java new file mode 100644 index 00000000..1063ead4 --- /dev/null +++ b/test-lib/src/main/java/community/icon/cps/score/test/integration/scores/Oracle.java @@ -0,0 +1,4 @@ +package community.icon.cps.score.test.integration.scores; + +public interface Oracle { +} diff --git a/test-lib/src/main/java/community/icon/cps/score/test/integration/scores/Router.java b/test-lib/src/main/java/community/icon/cps/score/test/integration/scores/Router.java new file mode 100644 index 00000000..b75b9432 --- /dev/null +++ b/test-lib/src/main/java/community/icon/cps/score/test/integration/scores/Router.java @@ -0,0 +1,4 @@ +package community.icon.cps.score.test.integration.scores; + +public interface Router { +} diff --git a/test-lib/src/main/java/community/icon/cps/score/test/integration/scores/SystemInterface.java b/test-lib/src/main/java/community/icon/cps/score/test/integration/scores/SystemInterface.java new file mode 100644 index 00000000..200acd6b --- /dev/null +++ b/test-lib/src/main/java/community/icon/cps/score/test/integration/scores/SystemInterface.java @@ -0,0 +1,54 @@ +package community.icon.cps.score.test.integration.scores; + +import java.math.BigInteger; +import java.util.Map; + +import foundation.icon.score.client.ScoreClient; +import score.Address; +import score.annotation.Payable; + + +@ScoreClient +public interface SystemInterface { + + public class Delegation{ + public Address address; + public BigInteger value; + } + + public class Bond{ + public Address address; + public BigInteger value; + } + + Map getIISSInfo(); + + Map queryIScore(Address address); + + Map getStake(Address address); + + Map getDelegation(Address address); + + Map getPReps(BigInteger startRanking, BigInteger endRanking); + + @Payable + void registerPRep(String name, String email, String country, String city, String website, String details, + String p2pEndpoint); + + + void setDelegation(Delegation[] delegations); + + void setBond(Bond[] bonds); + Map getBonderList(Address address); + + void setBonderList(Address[] bonderList); + + void setStake(BigInteger value); + + Map getPRep(Address address); + + Map getPRepTerm(); + void initCommissionRate(BigInteger maxChangeRate,BigInteger maxRate,BigInteger rate); + void setCommissionRate(BigInteger rate); + +} diff --git a/test-lib/src/main/java/community/icon/cps/score/test/integration/scores/sICX.java b/test-lib/src/main/java/community/icon/cps/score/test/integration/scores/sICX.java new file mode 100644 index 00000000..0c130669 --- /dev/null +++ b/test-lib/src/main/java/community/icon/cps/score/test/integration/scores/sICX.java @@ -0,0 +1,25 @@ +package community.icon.cps.score.test.integration.scores; + +import score.Address; +import score.annotation.External; + +import score.annotation.Optional; + + +import java.math.BigInteger; + +public interface sICX { + + @External + + void mintWithTokenFallBack(Address _to, BigInteger _amount, byte[] _data); + + @External(readonly = true) + BigInteger balanceOf(Address _owner); + + void mintTo(Address _account, BigInteger _amount); + + @External + void transfer(Address _to, BigInteger _value, @Optional byte[] _data); + +} diff --git a/test-lib/src/main/java/community/icon/cps/score/test/integration/utils/DefaultICONClient.java b/test-lib/src/main/java/community/icon/cps/score/test/integration/utils/DefaultICONClient.java new file mode 100644 index 00000000..cc075c5d --- /dev/null +++ b/test-lib/src/main/java/community/icon/cps/score/test/integration/utils/DefaultICONClient.java @@ -0,0 +1,197 @@ +package community.icon.cps.score.test.integration.utils; + +import static foundation.icon.score.client.DefaultScoreClient.callData; + +import com.fasterxml.jackson.annotation.JsonInclude.Include; + +import community.icon.cps.score.test.integration.Environment; +import foundation.icon.icx.Wallet; +import foundation.icon.jsonrpc.Address; +import foundation.icon.jsonrpc.IconJsonModule; +import foundation.icon.jsonrpc.JsonrpcClient; +import foundation.icon.jsonrpc.SendTransactionParamSerializer; +import foundation.icon.jsonrpc.model.DeployData; +import foundation.icon.jsonrpc.model.Hash; +import foundation.icon.jsonrpc.model.SendTransactionParam; +import foundation.icon.jsonrpc.model.TransactionParam; +import foundation.icon.jsonrpc.model.TransactionResult; +import foundation.icon.score.client.RevertedException; +import java.io.IOException; +import java.math.BigInteger; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import org.apache.commons.io.IOUtils; +import score.UserRevertedException; +import org.bouncycastle.jcajce.provider.digest.SHA3; +import org.bouncycastle.util.encoders.Base64; + +/** + * inspired from foundation.icon.score.client.DefaultScoreClient + */ + +public class DefaultICONClient { + + public static final Address ZERO_ADDRESS = new Address("cx0000000000000000000000000000000000000000"); + public static final BigInteger DEFAULT_STEP_LIMIT = new BigInteger("9502f900", 16); + public static final long BLOCK_INTERVAL = 200; + public static final long DEFAULT_RESULT_RETRY_WAIT = 1000; + public static final long DEFAULT_RESULT_TIMEOUT = 1000; + + private final JsonrpcClient client; + private final BigInteger nid; + + public DefaultICONClient(Environment.Chain chain) { + client = new JsonrpcClient(chain.getEndpointURL()); + client.mapper().registerModule(new IconJsonModule()); + client.mapper().setSerializationInclusion(Include.NON_NULL); + + this.nid = chain.networkId; + + } + + public Address deploy( + Wallet wallet, Address address, + String scoreFilePath, Map params) { + return this.deploy(wallet, address, scoreFilePath, params, DEFAULT_RESULT_TIMEOUT); + } + + public Address deploy( + Wallet wallet, Address address, + String scorePath, Map params, + long timeout) { + + String contentType; + if (scorePath.endsWith(".jar")) { + contentType = "application/java"; + } else if (scorePath.endsWith(".zip")) { + contentType = "application/zip"; + } else { + throw new RuntimeException("not supported score file"); + } + + byte[] content; + try { + URI uri = getURI(scorePath); + content = IOUtils.toByteArray(uri); + } catch (IOException e) { + throw new RuntimeException(e); + } + return deploy(wallet, address, params, timeout, content, contentType); + } + + private Address deploy(Wallet wallet, Address address, Map params, + long timeout, byte[] content, String contentType) { + SendTransactionParam tx = new SendTransactionParam(nid, address, null, "deploy", + new DeployData(contentType, content, params)); + Hash txh = sendTransaction(client, wallet, tx); + waitBlockInterval(); + TransactionResult txr = result(client, txh, timeout); + System.out.println("SCORE address: " + txr.getScoreAddress()); + return txr.getScoreAddress(); + } + + + public TransactionResult send(Wallet wallet, Address address, + BigInteger valueForPayable, String method, Map params, + long timeout) { + SendTransactionParam tx = new SendTransactionParam(nid, address, valueForPayable, "call", + callData(method, params)); + Hash txh = sendTransaction(client, wallet, tx); + waitBlockInterval(); + return result(client, txh, timeout); + } + + public static URI getURI(String url) { + try { + URL obj = new URL(url); + return obj.toURI(); + } catch (MalformedURLException | URISyntaxException ignored) { + return Path.of(url).toUri(); + } + } + + public static TransactionResult result(JsonrpcClient client, Hash txh, long timeout) { + Map params = Map.of("txHash", txh); + long etime = System.currentTimeMillis() + timeout; + TransactionResult txr = null; + while (txr == null) { + try { + txr = client.request(TransactionResult.class, "icx_getTransactionResult", params); + } catch (JsonrpcClient.JsonrpcError e) { + if (e.getCode() == -31002 /* pending */ + || e.getCode() == -31003 /* executing */ + || e.getCode() == -31004 /* not found */) { + if (timeout > 0 && System.currentTimeMillis() >= etime) { + throw new RuntimeException("timeout"); + } + try { + Thread.sleep(DEFAULT_RESULT_RETRY_WAIT); + System.out.println("wait for " + txh); + } catch (InterruptedException ie) { + ie.printStackTrace(); + } + } else { + throw new RuntimeException(e); + } + } + } + if (!BigInteger.ONE.equals(txr.getStatus())) { + TransactionResult.Failure failure = txr.getFailure(); + int revertCode = failure.getCode().intValue(); + String revertMessage = failure.getMessage(); + if (revertCode >= 32) { + throw new UserRevertedException(revertCode - 32, revertMessage); + } else { + throw new RevertedException(revertCode, revertMessage); + } + } + return txr; + } + + + static Hash sendTransaction(JsonrpcClient client, Wallet wallet, SendTransactionParam sendTransactionParam) { + Objects.requireNonNull(client, "client required not null"); + Objects.requireNonNull(wallet, "wallet required not null"); + Objects.requireNonNull(wallet, "sendTransactionParam required not null"); + + sendTransactionParam.setFrom(Address.of(wallet)); + if (sendTransactionParam.getTimestamp() == null) { + sendTransactionParam.setTimestamp(TransactionParam.currentTimestamp()); + } + if (sendTransactionParam.getStepLimit() == null) { + sendTransactionParam.setStepLimit(DEFAULT_STEP_LIMIT); + } + if (sendTransactionParam.getNid() == null) { + throw new IllegalArgumentException("nid could not be null"); + } + + Map params = new HashMap<>(); + String serialized; + try { + serialized = SendTransactionParamSerializer.serialize(sendTransactionParam, params); + } catch (IOException e) { + throw new RuntimeException(e); + } + byte[] digest = new SHA3.Digest256().digest(serialized.getBytes(StandardCharsets.UTF_8)); + String signature = Base64.toBase64String(wallet.sign(digest)); + params.put("signature", signature); + return client.request(Hash.class, "icx_sendTransaction", params); + } + + static void waitBlockInterval() { + System.out.printf("wait block interval %d msec%n", BLOCK_INTERVAL); + try { + Thread.sleep(BLOCK_INTERVAL); + } catch (InterruptedException ie) { + ie.printStackTrace(); + } + } +} + diff --git a/test-lib/src/main/resources/conf/contracts.json b/test-lib/src/main/resources/conf/contracts.json new file mode 100644 index 00000000..241e653f --- /dev/null +++ b/test-lib/src/main/resources/conf/contracts.json @@ -0,0 +1,73 @@ +[ + { + "name": "cpsCore", + "contract": "CPSCore", + "params": { + "bondValue": 15, + "applicationPeriod": "20" + }, + "order": 1.0 + }, + { + "name": "bnUSD", + "contract": "bnUSD", + "params": { + "_name": "Balanced Stable Coin", + "_symbol": "bnUSD", + "_decimals": 18, + "_initialSupply": 100000000000000000000 + }, + "order": 1.0 + }, + { + "name": "dex", + "contract": "Dex", + "params": { + }, + "order": 1.0 + }, + { + "name": "router", + "contract": "Router", + "params": { + }, + "order": 1.0 + }, + { + "name": "oracle", + "contract": "oracle", + "params": { + }, + "order": 1.0 + }, + { + "name": "cpsTreasury", + "contract": "CPSTreasury", + "params": { + }, + "addressParams": { + "cpsScore": "cpsCore" + }, + "order": 2.0 + }, + { + "name": "cpfTreasury", + "contract": "CPFTreasury", + "params": { + }, + "addressParams": { + "cpsScore": "cpsCore" + }, + "order": 2.0 + }, + { + "name": "sICX", + "contract": "sICX", + "params": { + }, + "addressParams": { + "_admin": "owner" + }, + "order": 2.0 + } +] \ No newline at end of file diff --git a/test-lib/conf/env.props b/test-lib/src/main/resources/conf/env.props similarity index 82% rename from test-lib/conf/env.props rename to test-lib/src/main/resources/conf/env.props index 6d1b17d9..6d5ac16e 100644 --- a/test-lib/conf/env.props +++ b/test-lib/src/main/resources/conf/env.props @@ -4,3 +4,5 @@ node.apiVersion=3 chain.nid=0x3 chain.godWallet=godWallet.json chain.godPassword=gochain + +preps.config=preps.json diff --git a/test-lib/conf/godWallet.json b/test-lib/src/main/resources/conf/godWallet.json similarity index 100% rename from test-lib/conf/godWallet.json rename to test-lib/src/main/resources/conf/godWallet.json diff --git a/test-lib/src/main/resources/conf/preps.json b/test-lib/src/main/resources/conf/preps.json new file mode 100644 index 00000000..3f0a68fc --- /dev/null +++ b/test-lib/src/main/resources/conf/preps.json @@ -0,0 +1,108 @@ +{ + "hxb6b5791be0b5ef67063b3c10b840fb81514db2fd": "573b555367d6734ea0fecd0653ba02659fa19f7dc6ee5b93ec781350bda27376", + "hx6636c7747d4e3045253dd9fb65ae2d5e54094592": "393f6548d472787138ebc6ac54ee38ace1b8a4dd46c3edfb3122b35db589286f", + "hxe7edbaf218b7709f67b7660aad99ae7b96b9008b": "f639b497bbf871d4f0bdeb6b86a72282edb1bfb30f6ee7e78cfdc95a6ddc5d43", + "hx28715c1fa884875df8c6f912a02f0ad4d4846d2a": "6736efad6c84269c6615921c43d3885cf2c6be20e8358ada8e776ada6a26a2dd", + "hxa2beea062cfb76ed3d1f5dca0c6bf5cadca17cde": "860d07529b385759c211cbfebf4478c1b463c19591fd1e8bb6f481dcf97c3f74", + "hx03d3b8eab81a03fe7ddfc5c8b670fe003becfe98": "2ba7a948c87ed651c5d2d54705ffd05f8211b61a905c114292fb70ae8f0af620", + "hx7af05c5da0fd57b7ea74a92d9c2b8d04e8ef99b3": "ab9c733168ab087d138a763090c30e4bdc82321a216b25fd010304dfe92442cb", + "hxa90662439dffd09dee16ec993c0dd40398ec5fb0": "f5482ae4aec8a73a65e660f873f08c296b021df157847f94b9f2a3fd35d1adf6", + "hxfa710d212608482f4dbf7c917a7921a5dfb3c043": "a5316f06638c327799088fc801138c4ac3508fe5f4c4bfda2adbae6ff832b50e", + "hxff66fa360b39f7ae05d16a39a2c49ced3dc60c77": "e0029c32345d1fa03a2f3934befb75c1a5ba1561c17bb6d722cd2cfbb494e43a", + "hxab187ea842d181150dc92548e872bde0e27fe3bc": "553d0da919be0b848336c1233389f5b8ca7a9807476714922513f23d43ad1dae", + "hxb66e5890effa8662f59e92f239317acadd901097": "ef5307bab1d6ceed8a779c99ecd1daef752f0877ea84797a8b0618900edf4f57", + "hxb9de3f9bd24884e045dd33481a90abcae001de27": "77e01c5f3b91b197ac529d67d7ccf84a7b8384c1cda144eee87abec93ac7397a", + "hx36338f4269195fcd79a62d6316150ea8af81ccd2": "052a6351cd45f3c3f82685f4d9f72a5ba2320b63e4fdac854a63f607337e0d3a", + "hxeeeeaf20e4122d807e0ea47e1b7b62e1063fd69a": "de29f744619cd6ebfcb815e7d48bacc118b120192b63cbe85e611eb4792fcb7d", + "hx6c70314a246c03ba59bd462d1d42fd54d5510cf0": "fc1c750e6e02f8d68d86ae2b28e25632ad427a7b60eab63cc4a43f61054f7457", + "hx3c9ab844bcf7d473c3f797c7b3004260d561cd72": "df9f518ea7c6f72ffb43414633887fe32f9deef072cf1e9c8b46add774573e42", + "hx83c00fcd9164b925eb48a5ddb65c55aa3877be1d": "1accdc447c56345839c9d9e0afe8dad1ac7afc938053c6ef34e3affd81e9d7d1", + "hxc1230b7498bcbc04daf95233f2da8cf36baac625": "af74ae1fe4355f9b12030282f5f5ae2ae72e01ac8d36041e4aa73ac4672cdce4", + "hx1849adbe91b7aefc9f84320f96fec0fda6f24654": "b34b033d527341fdcdec151d693b0f6943886b6733bd5fdf73c7779006b4e344", + "hxbfe3974f1491c134b68363989e09e17cc641a84c": "e49de438fbd33a3e88371178d76b29d03a4af9ac9cdfc91ed0e9a3f0d38752fc", + "hx9b1a5055c02f180eeb3e2ce1e97a000520eec3cf": "fff396bcf81cc56636db0c29f9c2d2f078f1d16392c2ea711595c98899a1d41c", + "hx93772d3ea28aadc5428c608a86144045d440a059": "40c4c0a26c05c849cd26a2150cf98d0a04d4229e042dbdc38b95fbc0dd86e432", + "hxc1d8673163360b18207623b18531c4d6d00167e0": "10e02b1da084418ee1c6231d7b902ef5f2c1f2d1705868a9b72268aeb531f23c", + "hxdb617a70f0e180e458c520b498c9cc5c1d79c2d3": "6953d7f021446d66caf8e2e5712446ae73cff5db1e37228c5ad9378450375899", + "hx97992a0b424b6bb31e3000620ef998ecd3a136f2": "1be95816e171ab56a2d390f4cc4b56d30884eb97e946976a524c913dc1f511a2", + "hxe80c59c99e6b9edd40a3e299f4086705654f671e": "18a8cd1857993b7b0496e3ed8ee030e0012923089e62089d885cf6214806882e", + "hx9973edc14286f19bfef673e1cd19eec8cbc988e8": "325e06ed2319af4d806d2ae9099daf91ffbcbfd5b3946b026dd11637b141a899", + "hxe80f04b7c2fdaafe2d7b1e9a304a827fdabf79a7": "b3e3baad508c4f47e7b4395f56bdd751a924f4148f2ddde2686f8adb0c80f7b1", + "hxf57ef33184c3fee6c43ec60df057769c1605c9a2": "741b555357f358bcc7c9b62498829d813f473e0b36c1c8510aaffc5858a584df", + "hx9c4298fc042210ab828fe4050fdcef033ecca326": "a1b948cb104d02a6bac54bb137b84f614cad8cf73da1919615c0cac4e5bd9789", + "hx068d880060b58abcf41436460fd92c6589c13c34": "0ab150bdadfdd607723ce6ef302ee3a331d45391b593cb4f28a936157188db51", + "hx72552d36897a700a684df2ce7974735c89e4ee24": "96ed02df17bff24802646f527ed26c2eb3c95806a649545b5f607ab060bd4174", + "hxe4e71d6807a7610294a2325fae87ce384f57a5b6": "6128d69aaad2238cbd42128169d4cd42c5b6db497679a7655e8427396796fb22", + "hx1991ca745d3c4b6ffab5ad92ea3d0c067b5f75e5": "baa5024dd1ceeb5af07a9ed7dfebfcb7f55eddc2c78b8db6345acb78f0c07203", + "hx43946dd08fb3fa7c9905df10afc30077c3c7975a": "553751e0338948f6ebfacde61f476fd2d9f4ffdae2b87b0ce36c7d90b20538ff", + "hx05a2c1eee05c927dda0f14a384b70c5b3e77c8ef": "8c68a066a6a769f69bac5fcb1a69a847ab4d528d092973d48f87e32ba6a68ceb", + "hx2ef7f7035a86bb39db8b6957394ebbe34b6b06fd": "8f6be89b5e2b21538cdd5410f08fe1307ae0d9d43e7b9d3a551577c0d925db3e", + "hxcf34dfb66faaa17bb96e66039a8d9164f7c0cac4": "a2d48ceddf8cd9f7e5d710fceac7eea1809b8dfda4659fe228b24dec9c5f2102", + "hx1e5614bde3be064f6ebe204007c967c8f08e0528": "61ed6c34822da8577f766f51ebe8a8539b7322fe2697acf239312f87b3d6c1bf", + "hx53d867d0ea96f6d2121b86da81b4b338b153c29c": "8e779fddcf0e63e9a7d6acf59f548ca23abde83004edf40e3bb42c61c3ef1ce5", + "hxcfdcd6d312afadf1826fa01f88a5e34fd1f539ce": "e31b323f4146f4274feddb3abf8b5e30c916b1bf04398cd1a08e6ac0b9055c8d", + "hx00ae4f48b64f3230f998a658d32cec9b5a9ee1e5": "4302f800c4f2ef8b881b7080b386366ab2088c2e8d9042b3c8946b3d0c338637", + "hx254010613e06e67378a6338f3d1fd0f700c882f6": "bd642909546f2c9e5f2d75b542269458a698cc18993ec0ccbf3da96f7ceaaf1d", + "hx2e9aae6b81c497a5af752f9285755488c8d291c7": "2ad9982a66c7248d960717e9109818cc5e46c5b7122ce62b5d3fd1c1584197c8", + "hx53bf8da223d199922e517e4306e0d2776d0793db": "67202e3581fe91af90d2f892aef51dc77bb0eba15111db367774b96b7290f2f3", + "hx8daf83576eb39507a1e1d5ce993036239d843e9d": "e18a19dbaa7192be847135a9e6d0eada0eb63bc393342c39858dd895dcd443c8", + "hxc862db463151c07f9a895bd9caeb6c5ae0969d86": "b830975dbadde629d07fcce49fe95c165c721ae3510489e9fc413dd632b60fb0", + "hx13df39540bddc6451f61689296ef564a0e8b21c9": "395bff275b62fa8f509738f2c25e7aebeed2bbe93d096d7773a410dd47ce1ca8", + "hx0b20a8e403ee06f87c2b967ee7e1ac9527d67913": "ded83336b4a0b7c8e81e0a96e8b813df374b28b0d702f6f5b9edab89dac1eff1", + "hx657726fdbac8bf6329d7c4a0d7c7489a57d9000d": "b69801a720c2796f04199134e409f73c3e23d3ac9394595ca2f8875bedfc3dff", + "hx35cb5d9c994ea6ee9bc66a8443fc8d63f539bba1": "b5efd48bf5262a86d723f050662933ef3a7a247820ca932ccecc4b79406191fa", + "hx6d21e5a05e1d79c53d08d9d37519fd8050051968": "83f4cdd3a5fccabb023ba68d9b0b0efbb1cbe3afdb6663ec550b1656f8cdea00", + "hx77b9f82d58ef154c7c092f2f0d82498002ef531e": "eec3a2a7116e5a9ae7a980319e086acd72e46d840345cc5ab76ffb089cf43fb0", + "hxe7786d1bcc22a0318ab170b5baa89f5b0a8e489d": "116030a7c079fdf60c602b6533323c03a61760428e1fc6d1658124e97f7775a3", + "hx7cf047eb75051019893de4b2ae94f0c43d018c7e": "4ebe9f3f1cd49110ceff08df4be92a4e28acf68fa9739ee5eb0a71de961c108a", + "hx9a7d29e6d251bca4a5811a426b9c27eb616b69f4": "8069f2a64762e4b7395c825958dd62629dba5c1c31d43e1ef69df38528708bd9", + "hxe6398003d4be27cd439c3892df4ae88527e9557d": "4f6f1316a12ba098478b3e081701c63350fde59781f274ec62fc3d3ee02d9370", + "hx7c5d9900892a346db84b6859759c382910a98bc0": "16c948e4e4a64b4a507586553410f0922b3fd8217566f8ec873821e12c5eeb33", + "hxa1f147deec635fe8a9f6ea3d02ac9e933e24909d": "89f2856612da91d6be1334e6a5d55119f53a639ea45da5aa12e1ece4278bdb41", + "hx454604142bd696bad4d1a7ba43707d4c92ad318c": "930a912d5425eede6707518668fb44302f3a9a04bfd3604336c7621cc998f18b", + "hx04c6f4443128869d874e1cd85080020a139e5ec1": "f0cd8083119fed78a6261388c4755222af8b8b47a87d6139ac1d1e3b69468619", + "hxd087d79e31e2417ad37b64085bc304b4f23bdb48": "1d6b8dabed1425925398e54f97c0e95a7ce5eebf94f07799d1d0ba97b8e88d92", + "hx192939a9f187b39ed7f08013fc86a6873a57706d": "aaf526bcd3a65e18c62e3b193c414401acd949e6f5aa7d73ccf8caa742c52834", + "hx3b146925c3f93e9ab7b6f99b1a8755aa76c9b5f4": "c95ff03e7f52e6473b957aff0f6942daf441c7c1327772fd56a89b22d13dc5f2", + "hxebc6282520de4275fedf16ee02abf86b39d10fb0": "62579b57d8123adf16bed7ad8c07f7116e42a690c30801d9c889085e1f6fcd4f", + "hxd6850304c0c63b5feb6d280a5b5a8732eacd79ec": "7340382aa2bb3c9fe693740485a908a9f52cd3d14696458a1e54117e8fe4d114", + "hxbfda75139dc9b6fdf0702d9a7ec3b9d37e5b1a8f": "375a6af5fdb9f31b77bcff9a4c5194190e72fd484f863f353c57057f2b560195", + "hxc707fe573bec0d3f79162303e45fba571766a73b": "93572fc6bd19475208e4724345432c63da4792e475021af5fd4e82794b448bd8", + "hx1ef8be9f98f831168298a168858127155fbbf855": "4936bdae329626253a2b16077d6f27964f2e5fea47bfc000afbe315a73150525", + "hx51c835949506a005a1ca8f612c8225e229a44695": "0f21de53aa85c4747f9bd0377c09b1e9e86473bbbb8267d527e517cd4cb45f86", + "hx25828f58f936e5135ddd970bcaa9e21a5254bb3a": "e6f31635efe681e8320bda2d1811656ea211f7cac684a0b2db4e28d66bc5d9db", + "hx33151e6d1d5e314cea00b6731e1cccf430d14c69": "0ac82dc2f456a4f69633de7177a196eab0daddd8fc1995ea151d1619d426e4b7", + "hxc24ff906776a486da1f553d0a3f75c3886ee3dd1": "9fa3fd3655cefe35dc8dde05d5e4a646133705cea775b7fa8199d477f42c4ae9", + "hxdb69ac6830a3d4af942057d09203c0b85e75e412": "295b9588123a0d222e59a2d39b304baebbda1f69ece6a27881d696b4a90d0db4", + "hx6d49b95e9d2694781fa1821b6c940791942746fd": "948ffb8f246885d7912704bd9db55bbfaa3a3a66dcb8a537c886178b495a8e8f", + "hx56bf6eedc7399530562a87ff020c0aea50e83e44": "12e47c0fd51bbb6498d6a7854e9e43ea2af69955ca99b0a3daa0da518f750501", + "hx7854d878952f4eefa7d657d802878c61746d659a": "736e73e266704b0bb3d08fcec1978f82a19c87b56dc606aaf075b0086fe235e3", + "hx08865f68914ec2abee8896c214396c34b99f47f6": "b4da40c2c83782fd416ee4890d5336a83858f43a17acb58f3b7e00d135a51a03", + "hxf6b7066bdeb27ade9e9e995b0a06ad814b7e4f61": "68ce7931dcbf00b184a327c5e84bec8ccea2054425b249973fd8a7dd2ed41050", + "hx67daa5605280f1c19399bf39b4a4cc9cafea3299": "64e87cb647203f02be78090c5d2e1cc089d49921961ed9ad122093a59f55d11c", + "hx6fcf5ca62512d490c7775f33cc12ce236dece1b4": "279640083f5393e37ff15b0bc680a8a785e4492cc8669bdbe1c5cd1f9be20f93", + "hxb76477d89baf57f2c17e98955e851e258472725b": "b336b8cf3750dbe59124658e6c1549dd2d97cad2fd42c47d7a43104d983399a9", + "hx34b146115b9c8a4fb53ba57792bb00e7b8a613d0": "d0e4aecaa2df9472045e47996c86d6c70b7e598df02801282670ad9928d37043", + "hx72d9a56d45e414311813359adc1ed9e2b012796a": "7e53a199296dc663431b109ddc2433efad477bc2c6137d28ad2c780861b4cb45", + "hxe8c5ad611a582e8df48bc75f98705c53c750e144": "cb0b36ca42f0e02b95c9b068aaa3f7671e3eb5810ad40a636f18a49cf70307a9", + "hx22926175cdba85f17e721730832f83545fb8c978": "765d1b6276e82cb31caa3e7f65e0421af80913061cb55c866a52949661ea2c12", + "hxda694f573b4e400b622bb83231078a964806d019": "87c3f5131224bcee566eff40d802978c3e9175e2810dff9247bcb8b79cec19ad", + "hx76bd1d301d145e9f44f4829a7a55c6e9c5465517": "86148add5b919241d6506283531a7e8e7b5ab57753fe622c225dc4424d6eb7e2", + "hxfc24ae3cd3fff914f800d746b65cef38808e62ae": "c13c849ebe47d65b4b263ffc117b7c921e762c654174d179d6e5ef668c06d6b6", + "hxed9e74c5bf92974867e6ceac399e42766e3c6d70": "2d49758aa02284ce381f960200a722a31034bafb9b145c1aebbbaa7eb5d885f8", + "hx4ba269f1ad0363ed886d96d2cf2fc9b02bd4add3": "fa3fe9bee9037efa00798bb5e3d7e3bb0e4a31285348f5161c7e178f9f97e22a", + "hx359097eeb9a034408dde077cc17427061eba58f6": "6e66fbbcfb5d000a761ca2a3c50bfa19dd758c4af5d046add1562625a9197b4b", + "hxa6f4b6586db9d7d7d2d09c3cad2eaadb8a8e570f": "b63d0e9214e0ad85bbacddd562f7b145d0cee9c47efdfca09b71e61823a2e036", + "hx1baacdc1831abcfed4cfd632f78ba581858515a1": "fb6b7f96bdea75c77199cb9c3b3a19df678aec38e9ed95d3b9a99ba6270832b4", + "hxfb1ef73510861d8759fd6f05db78ccc704979ad6": "6285c3f09c183248c63b4da22b4f1fe3c79488e589bf2b3805ce08eb8a1fd3c8", + "hx27ed4f60d48a93b93776c11ffa215103d2cb827c": "bd3f9fd19fed74c24ae7d2f380113484a7a8a0ff8e629132e9d3b1ae3dfad3c6", + "hxbba0f33fb754bdb287e199eead2c0f2ca4e8914f": "26d3033febc327dfb6fb61cd47dd569700aed15215898f4b0e38e539705dc3fe", + "hx37764062fc3f073cda91d2ce839870d53e987c82": "f16de08a347054b082be78d9b148c1f9a04227ce5f034cdd2dde5dc6cb5147a5", + "hxf1fec4f23a0dce8376efa6a880531c9c862dbcce": "433812a444251331e514f185dab31d8539b9ec85e0a30483d47680b32bdab63e", + "hx4a227dd1eccdd1196e135a0eea100bb1b95a3098": "c1a627565ed2f9c3675cda8f49caa8ffe5ef139e8b4da4df0d11b6ce5da85b4c", + "hx387350216461e0d206048ce7e58945ce4bc30b23": "0e50a9d67db39e15aa10a3051e75df9e64164c1978acc7da48ef38591969d803", + "hxfbd0abfa0079fa9ae51dd7331e0852a04f5a8cb5": "38af9fe413ae82199bab686c5ce79955a7b1b347a9323525512fd2dd9073a9ed", + "hxe95832467255889c39d78429b9ea2a22ef8e1951": "4dd5970a8d476f102a0d1dbbd0bd0523ce56128f76a5f6f8333bdd395676f274", + "hx8ce11c6a023aa95b2daef897f156d3cc52eb82de": "8ffc192824dc9c2bfc75979bb98da8e0cb50f06d7f9834379209627063613d55" + +} \ No newline at end of file diff --git a/testinteg/build.gradle b/testinteg/build.gradle deleted file mode 100644 index ae8ec6eb..00000000 --- a/testinteg/build.gradle +++ /dev/null @@ -1,8 +0,0 @@ -apply plugin: 'java-library' - -optimizedJar.enabled = false - -dependencies { - implementation 'foundation.icon:icon-sdk:2.0.0' - implementation 'org.junit.jupiter:junit-jupiter-api:5.8.1' -} diff --git a/testinteg/build/classes/java/main/foundation/icon/test/Constants.class b/testinteg/build/classes/java/main/foundation/icon/test/Constants.class deleted file mode 100644 index 1cf1ff97..00000000 Binary files a/testinteg/build/classes/java/main/foundation/icon/test/Constants.class and /dev/null differ diff --git a/testinteg/build/classes/java/main/foundation/icon/test/Env$Chain.class b/testinteg/build/classes/java/main/foundation/icon/test/Env$Chain.class deleted file mode 100644 index 03b61857..00000000 Binary files a/testinteg/build/classes/java/main/foundation/icon/test/Env$Chain.class and /dev/null differ diff --git a/testinteg/build/classes/java/main/foundation/icon/test/Env.class b/testinteg/build/classes/java/main/foundation/icon/test/Env.class deleted file mode 100644 index 0e998a1b..00000000 Binary files a/testinteg/build/classes/java/main/foundation/icon/test/Env.class and /dev/null differ diff --git a/testinteg/build/classes/java/main/foundation/icon/test/Log.class b/testinteg/build/classes/java/main/foundation/icon/test/Log.class deleted file mode 100644 index f235f026..00000000 Binary files a/testinteg/build/classes/java/main/foundation/icon/test/Log.class and /dev/null differ diff --git a/testinteg/build/classes/java/main/foundation/icon/test/ResultTimeoutException.class b/testinteg/build/classes/java/main/foundation/icon/test/ResultTimeoutException.class deleted file mode 100644 index 983da11d..00000000 Binary files a/testinteg/build/classes/java/main/foundation/icon/test/ResultTimeoutException.class and /dev/null differ diff --git a/testinteg/build/classes/java/main/foundation/icon/test/TestBase.class b/testinteg/build/classes/java/main/foundation/icon/test/TestBase.class deleted file mode 100644 index 4b71e21d..00000000 Binary files a/testinteg/build/classes/java/main/foundation/icon/test/TestBase.class and /dev/null differ diff --git a/testinteg/build/classes/java/main/foundation/icon/test/TransactionFailureException.class b/testinteg/build/classes/java/main/foundation/icon/test/TransactionFailureException.class deleted file mode 100644 index 84669153..00000000 Binary files a/testinteg/build/classes/java/main/foundation/icon/test/TransactionFailureException.class and /dev/null differ diff --git a/testinteg/build/classes/java/main/foundation/icon/test/TransactionHandler.class b/testinteg/build/classes/java/main/foundation/icon/test/TransactionHandler.class deleted file mode 100644 index 043a1741..00000000 Binary files a/testinteg/build/classes/java/main/foundation/icon/test/TransactionHandler.class and /dev/null differ diff --git a/testinteg/build/classes/java/main/foundation/icon/test/score/ChainScore.class b/testinteg/build/classes/java/main/foundation/icon/test/score/ChainScore.class deleted file mode 100644 index f98501d0..00000000 Binary files a/testinteg/build/classes/java/main/foundation/icon/test/score/ChainScore.class and /dev/null differ diff --git a/testinteg/build/classes/java/main/foundation/icon/test/score/Score.class b/testinteg/build/classes/java/main/foundation/icon/test/score/Score.class deleted file mode 100644 index 7b327f77..00000000 Binary files a/testinteg/build/classes/java/main/foundation/icon/test/score/Score.class and /dev/null differ diff --git a/testinteg/build/classes/java/main/foundation/icon/test/util/ZipFile.class b/testinteg/build/classes/java/main/foundation/icon/test/util/ZipFile.class deleted file mode 100644 index d0644e57..00000000 Binary files a/testinteg/build/classes/java/main/foundation/icon/test/util/ZipFile.class and /dev/null differ diff --git a/testinteg/build/libs/testinteg.jar b/testinteg/build/libs/testinteg.jar deleted file mode 100644 index b1fb089a..00000000 Binary files a/testinteg/build/libs/testinteg.jar and /dev/null differ diff --git a/testinteg/build/tmp/jar/MANIFEST.MF b/testinteg/build/tmp/jar/MANIFEST.MF deleted file mode 100644 index 58630c02..00000000 --- a/testinteg/build/tmp/jar/MANIFEST.MF +++ /dev/null @@ -1,2 +0,0 @@ -Manifest-Version: 1.0 - diff --git a/testinteg/conf/env.props b/testinteg/conf/env.props deleted file mode 100644 index 80aebffc..00000000 --- a/testinteg/conf/env.props +++ /dev/null @@ -1,5 +0,0 @@ -node.url=http://localhost:9082 - -chain.nid=0x3 -chain.godWallet=godWallet.json -chain.godPassword=gochain diff --git a/testinteg/conf/godWallet.json b/testinteg/conf/godWallet.json deleted file mode 100644 index 2a611aa3..00000000 --- a/testinteg/conf/godWallet.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "address": "hxb6b5791be0b5ef67063b3c10b840fb81514db2fd", - "id": "87323a66-289a-4ce2-88e4-00278deb5b84", - "version": 3, - "coinType": "icx", - "crypto": { - "cipher": "aes-128-ctr", - "cipherparams": { - "iv": "069e46aaefae8f1c1f840d6b09144999" - }, - "ciphertext": "f35ff7cf4f5759cb0878088d0887574a896f7f0fc2a73898d88be1fe52977dbd", - "kdf": "scrypt", - "kdfparams": { - "dklen": 32, - "n": 65536, - "r": 8, - "p": 1, - "salt": "0fc9c3b24cdb8175" - }, - "mac": "1ef4ff51fdee8d4de9cf59e160da049eb0099eb691510994f5eca492f56c817a" - } -} diff --git a/testinteg/src/main/java/foundation/icon/test/Constants.java b/testinteg/src/main/java/foundation/icon/test/Constants.java deleted file mode 100644 index 5fba7cf3..00000000 --- a/testinteg/src/main/java/foundation/icon/test/Constants.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2019 ICON Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package foundation.icon.test; - -import foundation.icon.icx.data.Address; - -import java.math.BigInteger; - -public class Constants { - public static final BigInteger STATUS_SUCCESS = BigInteger.ONE; - public static final BigInteger STATUS_FAILURE = BigInteger.ZERO; - - public static final BigInteger DEFAULT_STEPS = BigInteger.valueOf(100000); - public static final long DEFAULT_WAITING_TIME = 7000; - - public static final Address ZERO_ADDRESS = - new Address("cx0000000000000000000000000000000000000000"); - public static final Address TREASURY_ADDRESS = - new Address("hx1000000000000000000000000000000000000000"); - - public static final String CONTENT_TYPE_PYTHON = "application/zip"; - public static final String CONTENT_TYPE_JAVA = "application/java"; -} diff --git a/testinteg/src/main/java/foundation/icon/test/Env.java b/testinteg/src/main/java/foundation/icon/test/Env.java deleted file mode 100644 index 11416d45..00000000 --- a/testinteg/src/main/java/foundation/icon/test/Env.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2020 ICON Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package foundation.icon.test; - -import foundation.icon.icx.KeyWallet; -import foundation.icon.icx.Wallet; -import foundation.icon.icx.crypto.KeystoreException; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.nio.file.Path; -import java.util.Properties; - -public class Env { - public static final Log LOG = Log.getGlobal(); - private static Chain chain; - - static { - String envFile = System.getProperty("env.props", "conf/env.props"); - Properties props = new Properties(); - try { - LOG.info("Using env.props: " + envFile); - FileInputStream fis = new FileInputStream(envFile); - props.load(fis); - fis.close(); - } catch (IOException e) { - System.err.printf("'%s' does not exist\n", envFile); - throw new IllegalArgumentException(e.getMessage()); - } - String confPath = Path.of(envFile).getParent().toString() + "/"; - readProperties(props, confPath); - } - - private static void readProperties(Properties props, String confPath) { - String chainName = "chain"; - String nid = props.getProperty(chainName + ".nid"); - if (nid == null) { - throw new IllegalArgumentException("nid not found"); - } - String godWalletPath = confPath + props.getProperty(chainName + ".godWallet"); - String godPassword = props.getProperty(chainName + ".godPassword"); - KeyWallet godWallet; - try { - godWallet = readWalletFromFile(godWalletPath, godPassword); - } catch (IOException e) { - throw new IllegalArgumentException(e.getMessage()); - } - String nodeName = "node"; - String url = props.getProperty(nodeName + ".url"); - if (url == null) { - throw new IllegalArgumentException("node url not found"); - } - chain = new Chain(Integer.parseInt(nid.substring(2), 16), godWallet, url); - } - - private static KeyWallet readWalletFromFile(String path, String password) throws IOException { - try { - File file = new File(path); - return KeyWallet.load(password, file); - } catch (KeystoreException e) { - e.printStackTrace(); - throw new IOException("Key load failed!"); - } - } - - public static Chain getDefaultChain() { - if (chain == null) { - throw new AssertionError("Chain not found"); - } - return chain; - } - - public static class Chain { - public final int networkId; - public final Wallet godWallet; - private final String nodeUrl; - - public Chain(int networkId, Wallet godWallet, String url) { - this.networkId = networkId; - this.godWallet = godWallet; - this.nodeUrl = url; - } - - public String getEndpointURL(int v) { - return this.nodeUrl + "/api/v" + v; - } - } -} diff --git a/testinteg/src/main/java/foundation/icon/test/Log.java b/testinteg/src/main/java/foundation/icon/test/Log.java deleted file mode 100644 index b48cc6da..00000000 --- a/testinteg/src/main/java/foundation/icon/test/Log.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright 2019 ICON Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package foundation.icon.test; - -import java.util.EmptyStackException; -import java.util.Stack; - -public class Log { - private static final String[] PREFIX_LEVELS = {null, "[S]", "[W]", null, null}; - private static final String PREFIX_STEP_IN = "--> "; - private static final String PREFIX_STEP_OUT = "<-- "; - private static final String DEPTH_STRING = " "; - - private static final int LEVEL_START = 0; - public static final int LEVEL_NONE = LEVEL_START; - public static final int LEVEL_SEVERE = LEVEL_NONE + 1; - public static final int LEVEL_WARNING = LEVEL_SEVERE + 1; - public static final int LEVEL_INFO = LEVEL_WARNING + 1; - public static final int LEVEL_DEBUG = LEVEL_INFO + 1; - private static final int LEVEL_END = LEVEL_DEBUG; - - private int level = LEVEL_INFO; - private Stack frames = new Stack<>(); - - public static Log getGlobal() { - return new Log(); - } - - public void setLevel(int newLevel) { - if (newLevel >= LEVEL_START && newLevel <= LEVEL_END) { - level = newLevel; - } - } - - private boolean isLoggable(int level) { - return this.level >= level && level > LEVEL_START; - } - - public void info(String msg) { - log(LEVEL_INFO, msg); - } - - public void warning(String msg) { - log(LEVEL_WARNING, msg); - } - - public void severe(String msg) { - log(LEVEL_SEVERE, msg); - } - - public void infoEntering(String taskName, String msg) { - if (taskName == null) { - taskName = ""; - } - if (msg == null) { - msg = ""; - } - StringBuilder buf = new StringBuilder(5 + taskName.length() + msg.length()); - buf.append(PREFIX_STEP_IN).append(taskName); - if (msg.length() > 0) { - buf.append(": ").append(msg); - } - log(LEVEL_INFO, buf.toString()); - frames.push(taskName); - } - - public void infoEntering(String taskName) { - infoEntering(taskName, null); - } - - public void infoExiting(String msg) { - if (msg == null) { - msg = ""; - } - try { - String taskName = frames.pop(); - StringBuilder buf = new StringBuilder(5 + taskName.length() + msg.length()); - buf.append(PREFIX_STEP_OUT).append(taskName); - if (msg.length() > 0) { - buf.append(": ").append(msg); - } - log(LEVEL_INFO, buf.toString()); - } catch (EmptyStackException e) { - log(LEVEL_WARNING, "(INVALID) Exiting without no entering" + msg); - } - } - - public void infoExiting() { - infoExiting(null); - } - - public void debug(String msg) { - log(LEVEL_DEBUG, msg); - } - - public void log(int level, String msg) { - if (msg != null && isLoggable(level)) { - if (PREFIX_LEVELS[level] != null || !frames.empty()) { - StringBuilder buf = new StringBuilder(msg.length() + frames.size() * 3 + 3); - for (int i = frames.size(); i > 0; i--) { - buf.append(DEPTH_STRING); - } - if (PREFIX_LEVELS[level] != null) { - buf.append(PREFIX_LEVELS[level]); - } - buf.append(msg); - msg = buf.toString(); - } - System.out.println(msg); - } - } -} diff --git a/testinteg/src/main/java/foundation/icon/test/ResultTimeoutException.java b/testinteg/src/main/java/foundation/icon/test/ResultTimeoutException.java deleted file mode 100644 index 9f4c6f0f..00000000 --- a/testinteg/src/main/java/foundation/icon/test/ResultTimeoutException.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2019 ICON Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package foundation.icon.test; - -import foundation.icon.icx.data.Bytes; - -public class ResultTimeoutException extends Exception { - Bytes txHash; - - public ResultTimeoutException() { - super(); - } - - public ResultTimeoutException(String message) { - super(message); - } - - public ResultTimeoutException(Bytes txHash) { - super("Timeout. txHash=" + txHash); - this.txHash = txHash; - } - - public Bytes getTxHash() { - return this.txHash; - } -} diff --git a/testinteg/src/main/java/foundation/icon/test/TestBase.java b/testinteg/src/main/java/foundation/icon/test/TestBase.java deleted file mode 100644 index 0bfe3a2e..00000000 --- a/testinteg/src/main/java/foundation/icon/test/TestBase.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2020 ICON Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package foundation.icon.test; - -import foundation.icon.icx.data.Address; -import foundation.icon.icx.data.Bytes; -import foundation.icon.icx.data.TransactionResult; -import org.opentest4j.AssertionFailedError; - -import java.io.IOException; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.List; - -import static foundation.icon.test.Env.LOG; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.fail; - -public class TestBase { - protected static final BigInteger ICX = BigInteger.TEN.pow(18); - - protected static void assertSuccess(TransactionResult result) { - assertStatus(Constants.STATUS_SUCCESS, result); - } - - protected static void assertFailure(TransactionResult result) { - assertStatus(Constants.STATUS_FAILURE, result); - LOG.info("Expected " + result.getFailure()); - } - - protected static void assertStatus(BigInteger status, TransactionResult result) { - try { - assertEquals(status, result.getStatus()); - } catch (AssertionFailedError e) { - LOG.info("Assertion Failed: result=" + result); - fail(e.getMessage()); - } - } - - protected static void transferAndCheckResult(TransactionHandler txHandler, Address to, BigInteger amount) - throws IOException, ResultTimeoutException { - Bytes txHash = txHandler.transfer(to, amount); - assertSuccess(txHandler.getResult(txHash)); - } - - protected static void transferAndCheckResult(TransactionHandler txHandler, Address[] addresses, BigInteger amount) - throws IOException, ResultTimeoutException { - List hashes = new ArrayList<>(); - for (Address to : addresses) { - hashes.add(txHandler.transfer(to, amount)); - } - for (Bytes hash : hashes) { - assertSuccess(txHandler.getResult(hash)); - } - } - - protected static void ensureIcxBalance(TransactionHandler txHandler, Address address, - BigInteger oldVal, BigInteger newVal) throws Exception { - long limitTime = System.currentTimeMillis() + Constants.DEFAULT_WAITING_TIME; - while (true) { - BigInteger icxBalance = txHandler.getBalance(address); - String msg = "ICX balance of " + address + ": " + icxBalance; - if (icxBalance.equals(oldVal)) { - if (limitTime < System.currentTimeMillis()) { - throw new ResultTimeoutException(); - } - try { - // wait until block confirmation - LOG.debug(msg + "; Retry in 1 sec."); - Thread.sleep(1000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } else if (icxBalance.equals(newVal)) { - LOG.info(msg); - break; - } else { - throw new IOException(String.format("ICX balance mismatch: expected <%s>, but was <%s>", - newVal, icxBalance)); - } - } - } -} diff --git a/testinteg/src/main/java/foundation/icon/test/TransactionFailureException.java b/testinteg/src/main/java/foundation/icon/test/TransactionFailureException.java deleted file mode 100644 index bd3a8887..00000000 --- a/testinteg/src/main/java/foundation/icon/test/TransactionFailureException.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2019 ICON Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package foundation.icon.test; - -import foundation.icon.icx.data.TransactionResult; - -import java.math.BigInteger; - -public class TransactionFailureException extends Exception { - private final TransactionResult.Failure failure; - - public TransactionFailureException(TransactionResult.Failure failure) { - this.failure = failure; - } - - @Override - public String toString() { - return this.failure.toString(); - } - - public BigInteger getCode() { - return this.failure.getCode(); - } - - public String getMessage() { - return this.failure.getMessage(); - } -} diff --git a/testinteg/src/main/java/foundation/icon/test/TransactionHandler.java b/testinteg/src/main/java/foundation/icon/test/TransactionHandler.java deleted file mode 100644 index 92d999cd..00000000 --- a/testinteg/src/main/java/foundation/icon/test/TransactionHandler.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright 2019 ICON Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package foundation.icon.test; - -import foundation.icon.icx.Call; -import foundation.icon.icx.IconService; -import foundation.icon.icx.SignedTransaction; -import foundation.icon.icx.Transaction; -import foundation.icon.icx.TransactionBuilder; -import foundation.icon.icx.Wallet; -import foundation.icon.icx.data.Address; -import foundation.icon.icx.data.Bytes; -import foundation.icon.icx.data.ConfirmedTransaction; -import foundation.icon.icx.data.ScoreApi; -import foundation.icon.icx.data.TransactionResult; -import foundation.icon.icx.transport.jsonrpc.RpcError; -import foundation.icon.icx.transport.jsonrpc.RpcItem; -import foundation.icon.icx.transport.jsonrpc.RpcObject; -import foundation.icon.test.score.ChainScore; -import foundation.icon.test.score.Score; -import foundation.icon.test.util.ZipFile; - -import java.io.IOException; -import java.math.BigInteger; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; - -import static foundation.icon.test.Env.LOG; - -public class TransactionHandler { - private final IconService iconService; - private final Env.Chain chain; - - public TransactionHandler(IconService iconService, Env.Chain chain) { - this.iconService = iconService; - this.chain = chain; - } - - public Score deploy(Wallet owner, String scorePath, RpcObject params) - throws IOException, ResultTimeoutException, TransactionFailureException { - return deploy(owner, scorePath, params, null); - } - - public Score deploy(Wallet owner, String scorePath, RpcObject params, BigInteger steps) - throws IOException, ResultTimeoutException, TransactionFailureException { - return deploy(owner, scorePath, Constants.ZERO_ADDRESS, params, steps); - } - - public Score deploy(Wallet owner, String scorePath, Address to, RpcObject params, BigInteger steps) - throws IOException, ResultTimeoutException, TransactionFailureException { - if (scorePath.endsWith(".jar")) { - byte[] data = Files.readAllBytes(Path.of(scorePath)); - return getScore(doDeploy(owner, data, to, params, steps, Constants.CONTENT_TYPE_JAVA)); - } else { - byte[] data = ZipFile.zipContent(scorePath); - return getScore(doDeploy(owner, data, to, params, steps, Constants.CONTENT_TYPE_PYTHON)); - } - } - - private Bytes doDeploy(Wallet owner, byte[] content, Address to, RpcObject params, - BigInteger steps, String contentType) throws IOException { - Transaction transaction = TransactionBuilder.newBuilder() - .nid(getNetworkId()) - .from(owner.getAddress()) - .to(to) - .deploy(contentType, content) - .params(params) - .build(); - if (steps == null) { - steps = estimateStep(transaction); - } - SignedTransaction signedTransaction = new SignedTransaction(transaction, owner, steps); - return iconService.sendTransaction(signedTransaction).execute(); - } - - public Score getScore(Bytes txHash) - throws IOException, ResultTimeoutException, TransactionFailureException { - TransactionResult result = getResult(txHash, Constants.DEFAULT_WAITING_TIME); - if (!Constants.STATUS_SUCCESS.equals(result.getStatus())) { - throw new TransactionFailureException(result.getFailure()); - } - return new Score(this, new Address(result.getScoreAddress())); - } - - public Env.Chain getChain() { - return this.chain; - } - - public BigInteger getNetworkId() { - return BigInteger.valueOf(chain.networkId); - } - - public BigInteger getBalance(Address address) throws IOException { - return iconService.getBalance(address).execute(); - } - - public List getScoreApi(Address scoreAddress) throws IOException { - return iconService.getScoreApi(scoreAddress).execute(); - } - - public BigInteger estimateStep(Transaction transaction) throws IOException { - try { - return iconService.estimateStep(transaction).execute(); - } catch (RpcError e) { - LOG.info("estimateStep failed(" + e.getCode() + ", " + e.getMessage() + "); use default steps."); - return Constants.DEFAULT_STEPS.multiply(BigInteger.TWO); - } - } - - public RpcItem call(Call call) throws IOException { - return this.iconService.call(call).execute(); - } - - public Bytes invoke(Wallet wallet, Transaction tx, BigInteger steps) throws IOException { - if (steps == null) { - steps = estimateStep(tx); - } - return this.iconService.sendTransaction(new SignedTransaction(tx, wallet, steps)).execute(); - } - - public TransactionResult getResult(Bytes txHash) - throws IOException, ResultTimeoutException { - return getResult(txHash, Constants.DEFAULT_WAITING_TIME); - } - - public TransactionResult getResult(Bytes txHash, long waiting) - throws IOException, ResultTimeoutException { - long limitTime = System.currentTimeMillis() + waiting; - while (true) { - try { - return iconService.getTransactionResult(txHash).execute(); - } catch (RpcError e) { - if (e.getCode() == -31002 /* pending */ - || e.getCode() == -31003 /* executing */ - || e.getCode() == -31004 /* not found */) { - if (limitTime < System.currentTimeMillis()) { - throw new ResultTimeoutException(txHash); - } - try { - // wait until block confirmation - LOG.debug("RpcError: code(" + e.getCode() + ") message(" + e.getMessage() + "); Retry in 1 sec."); - Thread.sleep(1000); - } catch (InterruptedException ex) { - ex.printStackTrace(); - } - continue; - } - LOG.warning("RpcError: code(" + e.getCode() + ") message(" + e.getMessage() + "); Retry in 1 sec."); - throw e; - } - } - } - - public Bytes transfer(Address to, BigInteger amount) throws IOException { - return transfer(chain.godWallet, to, amount); - } - - public Bytes transfer(Wallet owner, Address to, BigInteger amount) throws IOException { - return transfer(owner, to, amount, null); - } - - public Bytes transfer(Wallet owner, Address to, BigInteger amount, BigInteger steps) throws IOException { - Transaction transaction = TransactionBuilder.newBuilder() - .nid(getNetworkId()) - .from(owner.getAddress()) - .to(to) - .value(amount) - .build(); - if (steps == null) { - steps = estimateStep(transaction).add(BigInteger.valueOf(10000)); - } - SignedTransaction signedTransaction = new SignedTransaction(transaction, owner, steps); - return iconService.sendTransaction(signedTransaction).execute(); - } - - public void refundAll(Wallet owner) throws IOException { - BigInteger stepPrice = new ChainScore(this).getStepPrice(); - BigInteger remaining = getBalance(owner.getAddress()); - BigInteger fee = Constants.DEFAULT_STEPS.multiply(stepPrice); - transfer(owner, chain.godWallet.getAddress(), remaining.subtract(fee), Constants.DEFAULT_STEPS); - } - - public ConfirmedTransaction getTransaction(Bytes txHash) throws IOException { - return iconService.getTransaction(txHash).execute(); - } -} diff --git a/testinteg/src/main/java/foundation/icon/test/score/ChainScore.java b/testinteg/src/main/java/foundation/icon/test/score/ChainScore.java deleted file mode 100644 index e9f025f5..00000000 --- a/testinteg/src/main/java/foundation/icon/test/score/ChainScore.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2020 ICONLOOP Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package foundation.icon.test.score; - -import foundation.icon.test.Constants; -import foundation.icon.test.TransactionHandler; - -import java.io.IOException; -import java.math.BigInteger; - -public class ChainScore extends Score { - - public ChainScore(TransactionHandler txHandler) { - super(txHandler, Constants.ZERO_ADDRESS); - } - - public BigInteger getStepPrice() throws IOException { - return call("getStepPrice", null).asInteger(); - } -} diff --git a/testinteg/src/main/java/foundation/icon/test/score/Score.java b/testinteg/src/main/java/foundation/icon/test/score/Score.java deleted file mode 100644 index d4230f81..00000000 --- a/testinteg/src/main/java/foundation/icon/test/score/Score.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright 2019 ICON Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package foundation.icon.test.score; - -import foundation.icon.icx.Call; -import foundation.icon.icx.Transaction; -import foundation.icon.icx.TransactionBuilder; -import foundation.icon.icx.Wallet; -import foundation.icon.icx.data.Address; -import foundation.icon.icx.data.Bytes; -import foundation.icon.icx.data.TransactionResult; -import foundation.icon.icx.data.TransactionResult.EventLog; -import foundation.icon.icx.transport.jsonrpc.RpcItem; -import foundation.icon.icx.transport.jsonrpc.RpcObject; -import foundation.icon.test.Constants; -import foundation.icon.test.ResultTimeoutException; -import foundation.icon.test.TransactionHandler; - -import java.io.IOException; -import java.math.BigInteger; -import java.util.List; - -public class Score { - private final TransactionHandler txHandler; - private final Address address; - - public Score(TransactionHandler txHandler, Address scoreAddress) { - this.txHandler = txHandler; - this.address = scoreAddress; - } - - public Score(Score other) { - this(other.txHandler, other.address); - } - - public static String getFilePath(String pkgName) { - String key = "score.path." + pkgName; - String path = System.getProperty(key); - if (path == null) { - throw new IllegalArgumentException("No such property: " + key); - } - return path; - } - - protected static EventLog findEventLog(TransactionResult result, Address scoreAddress, String funcSig) { - List eventLogs = result.getEventLogs(); - for (EventLog event : eventLogs) { - if (event.getScoreAddress().equals(scoreAddress.toString())) { - String signature = event.getIndexed().get(0).asString(); - if (funcSig.equals(signature)) { - return event; - } - } - } - return null; - } - - public RpcItem call(String method, RpcObject params) - throws IOException { - if (params == null) { - params = new RpcObject.Builder().build(); - } - Call call = new Call.Builder() - .to(getAddress()) - .method(method) - .params(params) - .build(); - return this.txHandler.call(call); - } - - public Bytes invoke(Wallet wallet, String method, RpcObject params) throws IOException { - return invoke(wallet, method, params, BigInteger.ZERO, null); - } - - public Bytes invoke(Wallet wallet, String method, RpcObject params, - BigInteger value, BigInteger steps) throws IOException { - return invoke(wallet, method, params, value, steps, null, null); - } - - public Bytes invoke(Wallet wallet, String method, RpcObject params, BigInteger value, - BigInteger steps, BigInteger timestamp, BigInteger nonce) throws IOException { - Transaction tx = getTransaction(wallet, method, params, value, timestamp, nonce); - return this.txHandler.invoke(wallet, tx, steps); - } - - private Transaction getTransaction(Wallet wallet, String method, RpcObject params, BigInteger value, - BigInteger timestamp, BigInteger nonce) { - TransactionBuilder.Builder builder = TransactionBuilder.newBuilder() - .nid(getNetworkId()) - .from(wallet.getAddress()) - .to(getAddress()); - - if ((value != null) && value.bitLength() != 0) { - builder.value(value); - } - if ((timestamp != null) && timestamp.bitLength() != 0) { - builder.timestamp(timestamp); - } - if (nonce != null) { - builder.nonce(nonce); - } - - Transaction tx; - if (params != null) { - tx = builder.call(method).params(params).build(); - } else { - tx = builder.call(method).build(); - } - return tx; - } - - public TransactionResult invokeAndWaitResult(Wallet wallet, String method, RpcObject params) - throws ResultTimeoutException, IOException { - return invokeAndWaitResult(wallet, method, params, null, null); - } - - public TransactionResult invokeAndWaitResult(Wallet wallet, String method, RpcObject params, - BigInteger steps) - throws ResultTimeoutException, IOException { - return invokeAndWaitResult(wallet, method, params, null, steps); - } - - public TransactionResult invokeAndWaitResult(Wallet wallet, String method, RpcObject params, - BigInteger value, BigInteger steps) - throws ResultTimeoutException, IOException { - Bytes txHash = this.invoke(wallet, method, params, value, steps); - return getResult(txHash); - } - - public TransactionResult getResult(Bytes txHash) throws ResultTimeoutException, IOException { - return getResult(txHash, Constants.DEFAULT_WAITING_TIME); - } - - public TransactionResult getResult(Bytes txHash, long waiting) throws ResultTimeoutException, IOException { - return this.txHandler.getResult(txHash, waiting); - } - - public Address getAddress() { - return this.address; - } - - public BigInteger getNetworkId() { - return txHandler.getNetworkId(); - } - - @Override - public String toString() { - return "SCORE(" + getAddress().toString() + ")"; - } -} diff --git a/testinteg/src/main/java/foundation/icon/test/util/ZipFile.java b/testinteg/src/main/java/foundation/icon/test/util/ZipFile.java deleted file mode 100644 index 8f351df6..00000000 --- a/testinteg/src/main/java/foundation/icon/test/util/ZipFile.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2020 ICON Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package foundation.icon.test.util; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; - -public class ZipFile { - public static byte[] zipContent(String path) throws IOException { - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - ZipOutputStream zos = new ZipOutputStream(outputStream); - recursiveZip(new File(path), null, zos); - zos.close(); - outputStream.close(); - return outputStream.toByteArray(); - } - - private static void recursiveZip(File source, String zipPath, ZipOutputStream zos) throws IOException { - if (source.isHidden()) { - return; - } - if (source.isDirectory()) { - String dir = source.getName(); - if (!dir.endsWith(File.separator)) { - dir = dir + File.separator; - } - zos.putNextEntry(new ZipEntry(dir)); - zos.closeEntry(); - File[] files = source.listFiles(); - if (files == null) { - return; - } - String path = zipPath == null ? dir : zipPath + dir; - for (File file : files) { - recursiveZip(file, path, zos); - } - } else { - ZipEntry ze = new ZipEntry(zipPath + source.getName()); - zos.putNextEntry(ze); - zos.write(Files.readAllBytes(source.toPath())); - zos.closeEntry(); - } - } -}