diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..bdde1d6 --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,40 @@ + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..79ee123 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/src/deploy/java/com/axlabs/neo/grantshares/DeployConfig.java b/src/deploy/java/com/axlabs/neo/grantshares/DeployConfig.java index e0014eb..60d1738 100644 --- a/src/deploy/java/com/axlabs/neo/grantshares/DeployConfig.java +++ b/src/deploy/java/com/axlabs/neo/grantshares/DeployConfig.java @@ -54,7 +54,8 @@ static ContractParameter getGovDeployConfig() { MIN_ACCEPTANCE_RATE_KEY, Config.getIntProperty(MIN_ACCEPTANCE_RATE_KEY), MIN_QUORUM_KEY, Config.getIntProperty(MIN_QUORUM_KEY), THRESHOLD_KEY, Config.getIntProperty(THRESHOLD_KEY) - )); + ) + ); } /** @@ -94,6 +95,7 @@ static ContractParameter getTreasuryDeployConfig(Hash160 grantSharesGovHash) { hash160(grantSharesGovHash), fundersParam, map(tokens), - Config.getIntProperty(THRESHOLD_KEY)); + Config.getIntProperty(THRESHOLD_KEY) + ); } } diff --git a/src/deploy/java/com/axlabs/neo/grantshares/Deployment.java b/src/deploy/java/com/axlabs/neo/grantshares/Deployment.java index 798928d..9cbf295 100644 --- a/src/deploy/java/com/axlabs/neo/grantshares/Deployment.java +++ b/src/deploy/java/com/axlabs/neo/grantshares/Deployment.java @@ -41,7 +41,8 @@ private static Hash160 deployGrantSharesGov(AccountSigner signer) throws Throwab "error message: " + log.getExecutions().get(0).getException()); } Hash160 contractHash = SmartContract.calcContractHash(signer.getScriptHash(), - res.getNefFile().getCheckSumAsInteger(), res.getManifest().getName()); + res.getNefFile().getCheckSumAsInteger(), res.getManifest().getName() + ); System.out.println("GrantSharesGov Contract Hash: " + contractHash); return contractHash; } @@ -50,7 +51,8 @@ private static void deployGrantSharesTreasury(Hash160 grantSharesGovHash, Accoun CompilationUnit res = new Compiler().compile(GrantSharesTreasury.class.getCanonicalName()); TransactionBuilder builder = new ContractManagement(getNeow3j()) .deploy(res.getNefFile(), res.getManifest(), - DeployConfig.getTreasuryDeployConfig(grantSharesGovHash)) + DeployConfig.getTreasuryDeployConfig(grantSharesGovHash) + ) .signers(signer); Hash256 txHash = builder.sign().send().getSendRawTransaction().getHash(); @@ -63,7 +65,8 @@ private static void deployGrantSharesTreasury(Hash160 grantSharesGovHash, Accoun "error message: " + log.getExecutions().get(0).getException()); } Hash160 contractHash = SmartContract.calcContractHash(signer.getScriptHash(), - res.getNefFile().getCheckSumAsInteger(), res.getManifest().getName()); + res.getNefFile().getCheckSumAsInteger(), res.getManifest().getName() + ); System.out.println("GrantSharesTreasury Contract Hash: " + contractHash); } diff --git a/src/deploy/java/com/axlabs/neo/grantshares/Invocations.java b/src/deploy/java/com/axlabs/neo/grantshares/Invocations.java index 5e8bb4f..a9d257e 100644 --- a/src/deploy/java/com/axlabs/neo/grantshares/Invocations.java +++ b/src/deploy/java/com/axlabs/neo/grantshares/Invocations.java @@ -61,12 +61,15 @@ private static void endorseProposal(GrantSharesGovContract gov, Account a, int i System.out.println(txHash.toString()); } - static void createProposal(GrantSharesTreasuryContract treasury, GrantSharesGovContract gov, Account a) throws Throwable { + static void createProposal(GrantSharesTreasuryContract treasury, GrantSharesGovContract gov, Account a) + throws Throwable { IntentParam intent = IntentParam.releaseTokenProposal(treasury.getScriptHash(), NeoToken.SCRIPT_HASH, - a.getScriptHash(), BigInteger.ONE); + a.getScriptHash(), BigInteger.ONE + ); NeoApplicationLog.Execution exec = signSendAwait( gov.createProposal(a.getScriptHash(), "https://github.com/axlabs/grantshares-dev/issues/42", -1, - intent), a); + intent + ), a); } static NeoApplicationLog.Execution signSendAwait(TransactionBuilder b, Account signer) throws Throwable { diff --git a/src/main/java/com/axlabs/neo/grantshares/GrantSharesGov.java b/src/main/java/com/axlabs/neo/grantshares/GrantSharesGov.java index ec5fb24..301b506 100644 --- a/src/main/java/com/axlabs/neo/grantshares/GrantSharesGov.java +++ b/src/main/java/com/axlabs/neo/grantshares/GrantSharesGov.java @@ -1,9 +1,25 @@ package com.axlabs.neo.grantshares; -import io.neow3j.devpack.*; +import io.neow3j.devpack.Account; +import io.neow3j.devpack.ByteString; +import io.neow3j.devpack.Contract; +import io.neow3j.devpack.ECPoint; +import io.neow3j.devpack.Hash160; +import io.neow3j.devpack.Helper; +import io.neow3j.devpack.Iterator; +import io.neow3j.devpack.List; +import io.neow3j.devpack.Map; import io.neow3j.devpack.Runtime; import io.neow3j.devpack.Iterator.Struct; -import io.neow3j.devpack.annotations.*; +import io.neow3j.devpack.Storage; +import io.neow3j.devpack.StorageContext; +import io.neow3j.devpack.StorageMap; +import io.neow3j.devpack.annotations.ContractSourceCode; +import io.neow3j.devpack.annotations.DisplayName; +import io.neow3j.devpack.annotations.ManifestExtra; +import io.neow3j.devpack.annotations.OnDeployment; +import io.neow3j.devpack.annotations.Permission; +import io.neow3j.devpack.annotations.Safe; import io.neow3j.devpack.constants.FindOptions; import io.neow3j.devpack.contracts.ContractManagement; import io.neow3j.devpack.contracts.StdLib; @@ -20,7 +36,9 @@ @ManifestExtra(key = "Email", value = "info@grantshares.io") @ManifestExtra(key = "Description", value = "The governing contract of the GrantShares DAO") @ManifestExtra(key = "Website", value = "https://grantshares.io") +//@formatter:off @ContractSourceCode("https://github.com/AxLabs/grantshares-contracts/blob/main/src/main/java/com/axlabs/neo/grantshares/GrantSharesGov.java") +//@formatter:on @DisplayName("GrantSharesGov") @SuppressWarnings("unchecked") public class GrantSharesGov { @@ -72,8 +90,6 @@ public class GrantSharesGov { static Event unpaused; @DisplayName("ProposalMigrated") static Event1Arg migrated; - @DisplayName("Error") - static Event2Args error; //endregion EVENTS /** @@ -242,10 +258,8 @@ public static int getProposalCount() { */ @Safe public static Paginator.Paginated getProposals(int page, int itemsPerPage) throws Exception { - if (page < 0) - throw new Exception("[GrantSharesGov.getProposals] Page number was negative"); - if (itemsPerPage <= 0) - throw new Exception("[GrantSharesGov.getProposals] Page number was negative or zero"); + if (page < 0) throw new Exception("[GrantSharesGov.getProposals] Page number was negative"); + if (itemsPerPage <= 0) throw new Exception("[GrantSharesGov.getProposals] Page number was negative or zero"); int n = Storage.getInt(getReadOnlyContext(), PROPOSALS_COUNT_KEY); int[] pagination = Paginator.calcPagination(n, page, itemsPerPage); List list = new List<>(); @@ -293,8 +307,9 @@ public static int calcMembersMultiSigAccountThreshold() throws Exception { if (thresholdTimes100 % 100 != 0) { threshold += 1; // Always round up. } - if (threshold == 0) + if (threshold == 0) { throw new Exception("[GrantSharesGov.calcMembersMultiSigAccountThreshold] Threshold was zero"); + } return threshold; } @@ -312,8 +327,8 @@ public static int calcMembersMultiSigAccountThreshold() throws Exception { */ public static int createProposal(Hash160 proposer, Intent[] intents, String offchainUri, int linkedProposal) { return createProposal(proposer, intents, offchainUri, linkedProposal, - parameters.getInt(MIN_ACCEPTANCE_RATE_KEY), - parameters.getInt(MIN_QUORUM_KEY)); + parameters.getInt(MIN_ACCEPTANCE_RATE_KEY), parameters.getInt(MIN_QUORUM_KEY) + ); } /** @@ -330,20 +345,24 @@ public static int createProposal(Hash160 proposer, Intent[] intents, String offc public static int createProposal(Hash160 proposer, Intent[] intents, String offchainUri, int linkedProposal, int acceptanceRate, int quorum) { - if (!checkWitness(proposer)) fireErrorAndAbort("Not authorised", "createProposal"); - if (acceptanceRate < parameters.getInt(MIN_ACCEPTANCE_RATE_KEY) || acceptanceRate > 100) - fireErrorAndAbort("Invalid acceptance rate", "createProposal"); - if (quorum < parameters.getInt(MIN_QUORUM_KEY) || quorum > 100) - fireErrorAndAbort("Invalid quorum", "createProposal"); - if (linkedProposal >= 0 && proposals.get(linkedProposal) == null) - fireErrorAndAbort("Linked proposal doesn't exist", "createProposal"); - if (!areIntentsValid(intents)) fireErrorAndAbort("Invalid intents", "createProposal"); + if (!checkWitness(proposer)) Helper.abort("createProposal" + ": " + "Not authorised"); + if (acceptanceRate < parameters.getInt(MIN_ACCEPTANCE_RATE_KEY) || acceptanceRate > 100) { + Helper.abort("createProposal" + ": " + "Invalid acceptance rate"); + } + if (quorum < parameters.getInt(MIN_QUORUM_KEY) || quorum > 100) { + Helper.abort("createProposal" + ": " + "Invalid quorum"); + } + if (linkedProposal >= 0 && proposals.get(linkedProposal) == null) { + Helper.abort("createProposal" + ": " + "Linked proposal doesn't exist"); + } + if (!areIntentsValid(intents)) Helper.abort("createProposal" + ": " + "Invalid intents"); int id = Storage.getInt(getReadOnlyContext(), PROPOSALS_COUNT_KEY); int expiration = parameters.getInt(EXPIRATION_LENGTH_KEY) + getTime(); proposals.put(id, new StdLib().serialize(new Proposal(id, expiration))); - proposalData.put(id, new StdLib().serialize(new ProposalData(proposer, linkedProposal, acceptanceRate, - quorum, intents, offchainUri))); + proposalData.put(id, new StdLib().serialize( + new ProposalData(proposer, linkedProposal, acceptanceRate, quorum, intents, offchainUri)) + ); proposalVotes.put(id, new StdLib().serialize(new ProposalVotes())); Storage.put(ctx, PROPOSALS_COUNT_KEY, id + 1); @@ -376,13 +395,14 @@ private static boolean areIntentsValid(Intent[] intents) { */ public static void endorseProposal(int id, Hash160 endorser) { abortIfPaused(); - if (members.get(endorser.toByteString()) == null || !checkWitness(endorser)) - fireErrorAndAbort("Not authorised", "endorseProposal"); + if (members.get(endorser.toByteString()) == null || !checkWitness(endorser)) { + Helper.abort("endorseProposal" + ": " + "Not authorised"); + } ByteString proposalBytes = proposals.get(id); - if (proposalBytes == null) fireErrorAndAbort("Proposal doesn't exist", "endorseProposal"); + if (proposalBytes == null) Helper.abort("endorseProposal" + ": " + "Proposal doesn't exist"); Proposal proposal = (Proposal) new StdLib().deserialize(proposalBytes); - if (proposal.expiration <= getTime()) fireErrorAndAbort("Proposal expired", "endorseProposal"); - if (proposal.endorser != null) fireErrorAndAbort("Proposal already endorsed", "endorseProposal"); + if (proposal.expiration <= getTime()) Helper.abort("endorseProposal" + ": " + "Proposal expired"); + if (proposal.endorser != null) Helper.abort("endorseProposal" + ": " + "Proposal already endorsed"); proposal.endorser = endorser; proposal.reviewEnd = getTime() + parameters.getInt(REVIEW_LENGTH_KEY); @@ -404,17 +424,19 @@ public static void endorseProposal(int id, Hash160 endorser) { */ public static void vote(int id, int vote, Hash160 voter) { abortIfPaused(); - if (vote < -1 || vote > 1) fireErrorAndAbort("Invalid vote", "vote"); - if (members.get(voter.toByteString()) == null || !checkWitness(voter)) - fireErrorAndAbort("Not authorised", "vote"); + if (vote < -1 || vote > 1) Helper.abort("vote" + ": " + "Invalid vote"); + if (members.get(voter.toByteString()) == null || !checkWitness(voter)) { + Helper.abort("vote" + ": " + "Not authorised"); + } ByteString proposalBytes = proposals.get(id); - if (proposalBytes == null) fireErrorAndAbort("Proposal doesn't exist", "vote"); + if (proposalBytes == null) Helper.abort("vote" + ": " + "Proposal doesn't exist"); Proposal proposal = (Proposal) new StdLib().deserialize(proposalBytes); int time = getTime(); - if (proposal.endorser == null || time < proposal.reviewEnd || time >= proposal.votingEnd) - fireErrorAndAbort("Proposal not active", "vote"); + if (proposal.endorser == null || time < proposal.reviewEnd || time >= proposal.votingEnd) { + Helper.abort("vote" + ": " + "Proposal not active"); + } ProposalVotes pv = (ProposalVotes) new StdLib().deserialize(proposalVotes.get(id)); - if (pv.voters.containsKey(voter)) fireErrorAndAbort("Already voted on this proposal", "vote"); + if (pv.voters.containsKey(voter)) Helper.abort("vote" + ": " + "Already voted on this proposal"); pv.voters.put(voter, vote); if (vote < 0) { @@ -440,20 +462,23 @@ public static void vote(int id, int vote, Hash160 voter) { public static Object[] execute(int id) { abortIfPaused(); ByteString proposalBytes = proposals.get(id); - if (proposalBytes == null) fireErrorAndAbort("Proposal doesn't exist", "execute"); + if (proposalBytes == null) Helper.abort("execute" + ": " + "Proposal doesn't exist"); Proposal proposal = (Proposal) new StdLib().deserialize(proposalBytes); - if (proposal.endorser == null || getTime() < proposal.timeLockEnd) - fireErrorAndAbort("Proposal not in execution phase", "execute"); - if (proposal.executed) fireErrorAndAbort("Proposal already executed", "execute"); - if (proposal.expiration <= getTime()) fireErrorAndAbort("Proposal expired", "execute"); + if (proposal.endorser == null || getTime() < proposal.timeLockEnd) { + Helper.abort("execute" + ": " + "Proposal not in execution phase"); + } + if (proposal.executed) Helper.abort("execute" + ": " + "Proposal already executed"); + if (proposal.expiration <= getTime()) Helper.abort("execute" + ": " + "Proposal expired"); ProposalData data = (ProposalData) new StdLib().deserialize(proposalData.get(id)); ProposalVotes votes = (ProposalVotes) new StdLib().deserialize(proposalVotes.get(id)); int voteCount = votes.approve + votes.abstain + votes.reject; - if (voteCount * 100 / Storage.getInt(getReadOnlyContext(), MEMBERS_COUNT_KEY) < data.quorum) - fireErrorAndAbort("Quorum not reached", "execute"); + if (voteCount * 100 / Storage.getInt(getReadOnlyContext(), MEMBERS_COUNT_KEY) < data.quorum) { + Helper.abort("execute" + ": " + "Quorum not reached"); + } int yesNoCount = votes.approve + votes.reject; - if (yesNoCount == 0 || (votes.approve * 100 / yesNoCount <= data.acceptanceRate)) - fireErrorAndAbort("Proposal rejected", "execute"); + if (yesNoCount == 0 || (votes.approve * 100 / yesNoCount <= data.acceptanceRate)) { + Helper.abort("execute" + ": " + "Proposal rejected"); + } proposal.executed = true; Object[] returnVals = new Object[data.intents.length]; @@ -491,17 +516,17 @@ private static void abortOnInvalidValue(String paramKey, int value) { case VOTING_LENGTH_KEY: case TIMELOCK_LENGTH_KEY: case EXPIRATION_LENGTH_KEY: - if (value < 0) fireErrorAndAbort("Invalid parameter value", "changeParam"); + if (value < 0) Helper.abort("changeParam" + ": " + "Invalid parameter value"); break; case MIN_ACCEPTANCE_RATE_KEY: case MIN_QUORUM_KEY: - if (value < 0 || value > 100) fireErrorAndAbort("Invalid parameter value", "changeParam"); + if (value < 0 || value > 100) Helper.abort("changeParam" + ": " + "Invalid parameter value"); break; case MULTI_SIG_THRESHOLD_KEY: - if (value <= 0 || value > 100) fireErrorAndAbort("Invalid parameter value", "changeParam"); + if (value <= 0 || value > 100) Helper.abort("changeParam" + ": " + "Invalid parameter value"); break; default: - fireErrorAndAbort("Unknown parameter", "changeParam"); + Helper.abort("changeParam" + ": " + "Unknown parameter"); } } @@ -516,7 +541,7 @@ public static void addMember(ECPoint memberPubKey) { abortIfPaused(); abortIfCallerIsNotSelf(); Hash160 memberHash = createStandardAccount(memberPubKey); - if (members.get(memberHash.toByteString()) != null) fireErrorAndAbort("Already a member", "addMember"); + if (members.get(memberHash.toByteString()) != null) Helper.abort("addMember" + ": " + "Already a member"); members.put(memberHash.toByteString(), memberPubKey.toByteString()); Storage.put(ctx, MEMBERS_COUNT_KEY, Storage.getInt(getReadOnlyContext(), MEMBERS_COUNT_KEY) + 1); memberAdded.fire(memberHash); @@ -533,7 +558,7 @@ public static void removeMember(ECPoint memberPubKey) { abortIfPaused(); abortIfCallerIsNotSelf(); Hash160 memberHash = createStandardAccount(memberPubKey); - if (members.get(memberHash.toByteString()) == null) fireErrorAndAbort("Not a member", "removeMember"); + if (members.get(memberHash.toByteString()) == null) Helper.abort("removeMember" + ": " + "Not a member"); members.delete(memberHash.toByteString()); Storage.put(ctx, MEMBERS_COUNT_KEY, Storage.getInt(getReadOnlyContext(), MEMBERS_COUNT_KEY) - 1); memberRemoved.fire(memberHash); @@ -562,9 +587,9 @@ public static void pause() { try { membersMultiSigHash = calcMembersMultiSigAccount(); } catch (Exception e) { - fireErrorAndAbort(e.getMessage(), "pause"); + Helper.abort("pause" + ": " + e.getMessage()); } - if (!checkWitness(membersMultiSigHash)) fireErrorAndAbort("Not authorized", "pause"); + if (!checkWitness(membersMultiSigHash)) Helper.abort("pause" + ": " + "Not authorized"); Storage.put(ctx, PAUSED_KEY, 1); paused.fire(); } @@ -574,27 +599,22 @@ public static void unpause() { try { membersMultiSigHash = calcMembersMultiSigAccount(); } catch (Exception e) { - fireErrorAndAbort(e.getMessage(), "pause"); + Helper.abort("pause" + ": " + e.getMessage()); } - if (!checkWitness(membersMultiSigHash)) fireErrorAndAbort("Not authorized", "unpause"); + if (!checkWitness(membersMultiSigHash)) Helper.abort("unpause" + ": " + "Not authorized"); Storage.put(ctx, PAUSED_KEY, 0); unpaused.fire(); } private static void abortIfCallerIsNotSelf() { if (Runtime.getCallingScriptHash() != Runtime.getExecutingScriptHash()) { - fireErrorAndAbort("Method only callable by the contract itself", "abortIfCallerIsNotSelf"); + Helper.abort("abortIfCallerIsNotSelf" + ": " + "Method only callable by the contract itself"); } } public static void abortIfPaused() { if (Storage.getBoolean(getReadOnlyContext(), PAUSED_KEY)) { - fireErrorAndAbort("Contract is paused", "abortIfPaused"); + Helper.abort("abortIfPaused" + ": " + "Contract is paused"); } } - - private static void fireErrorAndAbort(String msg, String method) { - error.fire(msg, method); - Helper.abort(); - } } diff --git a/src/main/java/com/axlabs/neo/grantshares/GrantSharesTreasury.java b/src/main/java/com/axlabs/neo/grantshares/GrantSharesTreasury.java index 4f54d66..3eab3de 100644 --- a/src/main/java/com/axlabs/neo/grantshares/GrantSharesTreasury.java +++ b/src/main/java/com/axlabs/neo/grantshares/GrantSharesTreasury.java @@ -48,7 +48,9 @@ @ManifestExtra(key = "Email", value = "info@grantshares.io") @ManifestExtra(key = "Description", value = "The treasury of the GrantShares DAO") @ManifestExtra(key = "Website", value = "https://grantshares.io") +//@formatter:off @ContractSourceCode("https://github.com/AxLabs/grantshares-contracts/blob/main/src/main/java/com/axlabs/neo/grantshares/GrantSharesTreasury.java") +//@formatter:on @DisplayName("GrantSharesTreasury") public class GrantSharesTreasury { @@ -61,6 +63,7 @@ public class GrantSharesTreasury { static final StorageMap funders = new StorageMap(ctx, FUNDERS_PREFIX); // [hash, List] static final StorageMap whitelistedTokens = new StorageMap(ctx, WHITELISTED_TOKENS_PREFIX); // [hash, max_amount] + //region EVENTS @DisplayName("FunderAdded") static Event1Arg funderAdded; @DisplayName("FunderRemoved") @@ -87,8 +90,7 @@ public class GrantSharesTreasury { static Event3Args tokensReceived; @DisplayName("WhitelistedTokenMigrated") static Event2Args whitelistedTokenMigrated; - @DisplayName("Error") - static Event2Args error; + //endregion EVENTS /** * Initialises this contract on deployment. @@ -215,7 +217,8 @@ private static List getFunderPublicKeys() { public static Hash160 calcFundersMultiSigAddress() throws Exception { List funderPublicKeys = getFunderPublicKeys(); return Account.createMultiSigAccount(calcFundersMultiSigAddressThreshold(funderPublicKeys.size()), - funderPublicKeys.toArray()); + funderPublicKeys.toArray() + ); } /** @@ -246,8 +249,9 @@ private static int calcFundersMultiSigAddressThreshold(int count) throws Excepti if (thresholdTimes100 % 100 != 0) { threshold += 1; // Always round up. } - if (threshold == 0) + if (threshold == 0) { throw new Exception("[GrantSharesTreasury.calcFundersMultiSigAddressThreshold] Threshold was zero"); + } return threshold; } @@ -275,7 +279,8 @@ public static Map getWhitelistedTokens() { @Safe public static boolean isPaused() { return (boolean) Contract.call(new Hash160(Storage.get(getReadOnlyContext(), OWNER_KEY)), - "isPaused", CallFlags.ReadOnly, new Object[]{}); + "isPaused", CallFlags.ReadOnly, new Object[]{} + ); } /** @@ -299,8 +304,9 @@ public static int getFundersMultiSigThresholdRatio() { public static void setFundersMultiSigThresholdRatio(Integer value) { abortIfPaused(); abortIfCallerIsNotOwner(); - if (value <= 0 || value > 100) - fireErrorAndAbort("Invalid threshold ratio", "setFundersMultiSigThresholdRatio"); + if (value <= 0 || value > 100) { + Helper.abort("setFundersMultiSigThresholdRatio" + ": " + "Invalid threshold ratio"); + } Storage.put(ctx, MULTI_SIG_THRESHOLD_KEY, value); thresholdChanged.fire(value); } @@ -319,11 +325,11 @@ public static void setFundersMultiSigThresholdRatio(Integer value) { public static void addFunder(Hash160 accountHash, ECPoint[] publicKeys) { abortIfPaused(); abortIfCallerIsNotOwner(); - if (funders.get(accountHash.toByteString()) != null) fireErrorAndAbort("Already a funder", "addFunder"); - if (!isValid(accountHash) || accountHash == zero()) fireErrorAndAbort("Invalid funder hash", "addFunder"); - if (publicKeys.length == 0) fireErrorAndAbort("List of public keys is empty", "addFunder"); + if (funders.get(accountHash.toByteString()) != null) Helper.abort("addFunder" + ": " + "Already a funder"); + if (!isValid(accountHash) || accountHash == zero()) Helper.abort("addFunder" + ": " + "Invalid funder hash"); + if (publicKeys.length == 0) Helper.abort("addFunder" + ": " + "List of public keys is empty"); for (ECPoint key : publicKeys) { - if (!ECPoint.isValid(key)) fireErrorAndAbort("Invalid public key", "addFunder"); + if (!ECPoint.isValid(key)) Helper.abort("addFunder" + ": " + "Invalid public key"); } funders.put(accountHash.toByteString(), new StdLib().serialize(publicKeys)); funderAdded.fire(accountHash); @@ -339,7 +345,7 @@ public static void addFunder(Hash160 accountHash, ECPoint[] publicKeys) { public static void removeFunder(Hash160 accountHash) { abortIfPaused(); abortIfCallerIsNotOwner(); - if (funders.get(accountHash.toByteString()) == null) fireErrorAndAbort("Not a funder", "removeFunder"); + if (funders.get(accountHash.toByteString()) == null) Helper.abort("removeFunder" + ": " + "Not a funder"); funders.delete(accountHash.toByteString()); funderRemoved.fire(accountHash); } @@ -356,8 +362,8 @@ public static void removeFunder(Hash160 accountHash) { public static void addWhitelistedToken(Hash160 token, int maxFundingAmount) { abortIfPaused(); abortIfCallerIsNotOwner(); - if (!isValid(token) || token == zero()) fireErrorAndAbort("Invalid token hash", "addWhitelistedToken"); - if (maxFundingAmount <= 0) fireErrorAndAbort("Invalid max funding amount", "addWhitelistedToken"); + if (!isValid(token) || token == zero()) Helper.abort("addWhitelistedToken" + ": " + "Invalid token hash"); + if (maxFundingAmount <= 0) Helper.abort("addWhitelistedToken" + ": " + "Invalid max funding amount"); whitelistedTokens.put(token.toByteString(), maxFundingAmount); whitelistedTokenAdded.fire(token, maxFundingAmount); } @@ -372,8 +378,9 @@ public static void addWhitelistedToken(Hash160 token, int maxFundingAmount) { public static void removeWhitelistedToken(Hash160 token) { abortIfPaused(); abortIfCallerIsNotOwner(); - if (whitelistedTokens.get(token.toByteString()) == null) - fireErrorAndAbort("Not a whitelisted token", "removeWhitelistedToken"); + if (whitelistedTokens.get(token.toByteString()) == null) { + Helper.abort("removeWhitelistedToken" + ": " + "Not a whitelisted token"); + } whitelistedTokens.delete(token.toByteString()); whitelistedTokenRemoved.fire(token); } @@ -392,8 +399,8 @@ public static void releaseTokens(Hash160 tokenContract, Hash160 to, int amount) abortIfPaused(); abortIfCallerIsNotOwner(); int maxFundingAmount = whitelistedTokens.getIntOrZero(tokenContract.toByteString()); - if (maxFundingAmount == 0) fireErrorAndAbort("Token not whitelisted", "releaseTokens"); - if (amount > maxFundingAmount) fireErrorAndAbort("Above token's max funding amount", "releaseTokens"); + if (maxFundingAmount == 0) Helper.abort("releaseTokens" + ": " + "Token not whitelisted"); + if (amount > maxFundingAmount) Helper.abort("releaseTokens" + ": " + "Above token's max funding amount"); Object[] params = new Object[]{Runtime.getExecutingScriptHash(), to, amount, new Object[]{}}; boolean success = (boolean) Contract.call(tokenContract, "transfer", CallFlags.All, params); if (success) { @@ -410,14 +417,14 @@ public static void releaseTokens(Hash160 tokenContract, Hash160 to, int amount) * paused. */ public static void drain() { - if (!isPaused()) fireErrorAndAbort("Contract is not paused", "drain"); + if (!isPaused()) Helper.abort("drain" + ": " + "Contract is not paused"); Hash160 fundersMultiAddress = null; try { fundersMultiAddress = calcFundersMultiSigAddress(); } catch (Exception e) { - fireErrorAndAbort(e.getMessage(), "drain"); + Helper.abort("drain" + ": " + e.getMessage()); } - if (!checkWitness(fundersMultiAddress)) fireErrorAndAbort("Not authorized", "drain"); + if (!checkWitness(fundersMultiAddress)) Helper.abort("drain" + ": " + "Not authorized"); Hash160 selfHash = Runtime.getExecutingScriptHash(); Iterator it = whitelistedTokens.find((byte) (RemovePrefix | KeysOnly)); while (it.next()) { @@ -441,8 +448,9 @@ public static void drain() { public static void voteCommitteeMemberWithLeastVotes() { abortIfPaused(); ECPoint c = getCommitteeMemberWithLeastVotes(); - if (!new NeoToken().vote(Runtime.getExecutingScriptHash(), c)) - fireErrorAndAbort("Failed voting on candidate", "voteCommitteeMemberWithLeastVotes"); + if (!new NeoToken().vote(Runtime.getExecutingScriptHash(), c)) { + Helper.abort("voteCommitteeMemberWithLeastVotes" + ": " + "Failed voting on candidate"); + } voted.fire(c); } @@ -480,16 +488,12 @@ public static void updateContract(ByteString nef, String manifest, Object data) } private static void abortIfCallerIsNotOwner() { - if (Runtime.getCallingScriptHash().toByteString() != Storage.get(getReadOnlyContext(), OWNER_KEY)) - fireErrorAndAbort("Not authorised", "abortIfCallerIsNotOwner"); + if (Runtime.getCallingScriptHash().toByteString() != Storage.get(getReadOnlyContext(), OWNER_KEY)) { + Helper.abort("abortIfCallerIsNotOwner" + ": " + "Not authorised"); + } } private static void abortIfPaused() { - if (isPaused()) fireErrorAndAbort("Contract is paused", "abortIfCallerIsNotOwner"); - } - - private static void fireErrorAndAbort(String msg, String method) { - error.fire(msg, method); - Helper.abort(); + if (isPaused()) Helper.abort("abortIfCallerIsNotOwner" + ": " + "Contract is paused"); } } diff --git a/src/test/java/com/axlabs/neo/grantshares/GovernanceMembersTest.java b/src/test/java/com/axlabs/neo/grantshares/GovernanceMembersTest.java index f50c3fc..fddcc35 100644 --- a/src/test/java/com/axlabs/neo/grantshares/GovernanceMembersTest.java +++ b/src/test/java/com/axlabs/neo/grantshares/GovernanceMembersTest.java @@ -10,6 +10,7 @@ import io.neow3j.test.DeployConfig; import io.neow3j.test.DeployConfiguration; import io.neow3j.transaction.AccountSigner; +import io.neow3j.transaction.exceptions.TransactionConfigurationException; import io.neow3j.types.CallFlags; import io.neow3j.types.ContractParameter; import io.neow3j.types.Hash256; @@ -26,19 +27,18 @@ import java.util.List; import java.util.stream.Collectors; -import static com.axlabs.neo.grantshares.util.TestHelper.ADD_MEMBER; -import static com.axlabs.neo.grantshares.util.TestHelper.ALICE; -import static com.axlabs.neo.grantshares.util.TestHelper.BOB; -import static com.axlabs.neo.grantshares.util.TestHelper.CALC_MEMBER_MULTI_SIG_ACC; -import static com.axlabs.neo.grantshares.util.TestHelper.CHARLIE; -import static com.axlabs.neo.grantshares.util.TestHelper.DENISE; -import static com.axlabs.neo.grantshares.util.TestHelper.GET_MEMBERS; -import static com.axlabs.neo.grantshares.util.TestHelper.MEMBER_ADDED; -import static com.axlabs.neo.grantshares.util.TestHelper.MEMBER_REMOVED; -import static com.axlabs.neo.grantshares.util.TestHelper.PHASE_LENGTH; -import static com.axlabs.neo.grantshares.util.TestHelper.PROPOSAL_EXECUTED; -import static com.axlabs.neo.grantshares.util.TestHelper.REMOVE_MEMBER; -import static com.axlabs.neo.grantshares.util.TestHelper.assertAborted; +import static com.axlabs.neo.grantshares.util.TestHelper.Events.MEMBER_ADDED; +import static com.axlabs.neo.grantshares.util.TestHelper.Events.MEMBER_REMOVED; +import static com.axlabs.neo.grantshares.util.TestHelper.Events.PROPOSAL_EXECUTED; +import static com.axlabs.neo.grantshares.util.TestHelper.GovernanceMethods.ADD_MEMBER; +import static com.axlabs.neo.grantshares.util.TestHelper.GovernanceMethods.CALC_MEMBER_MULTI_SIG_ACC; +import static com.axlabs.neo.grantshares.util.TestHelper.GovernanceMethods.GET_MEMBERS; +import static com.axlabs.neo.grantshares.util.TestHelper.GovernanceMethods.REMOVE_MEMBER; +import static com.axlabs.neo.grantshares.util.TestHelper.Members.ALICE; +import static com.axlabs.neo.grantshares.util.TestHelper.Members.BOB; +import static com.axlabs.neo.grantshares.util.TestHelper.Members.CHARLIE; +import static com.axlabs.neo.grantshares.util.TestHelper.Members.DENISE; +import static com.axlabs.neo.grantshares.util.TestHelper.ParameterValues.PHASE_LENGTH; import static com.axlabs.neo.grantshares.util.TestHelper.createAndEndorseProposal; import static com.axlabs.neo.grantshares.util.TestHelper.createMultiSigAccount; import static com.axlabs.neo.grantshares.util.TestHelper.prepareDeployParameter; @@ -52,6 +52,8 @@ import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.core.Is.is; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; @ContractTest(contracts = GrantSharesGov.class, blockTime = 1, configFile = "default.neo-express", batchFile = "setup.batch") @@ -79,7 +81,6 @@ public static DeployConfiguration deployConfig() throws Exception { @BeforeAll public static void setUp() throws Throwable { neow3j = ext.getNeow3j(); - neow3j.allowTransmissionOnFault(); gov = new GrantSharesGovContract(ext.getDeployedContract(GrantSharesGov.class).getScriptHash(), neow3j); alice = ext.getAccount(ALICE); bob = ext.getAccount(BOB); @@ -89,10 +90,11 @@ public static void setUp() throws Throwable { //region ADD MEMBER @Test - public void fail_calling_add_member_directly() throws Throwable { - Hash256 tx = gov.invokeFunction(ADD_MEMBER, hash160(bob)).signers(AccountSigner.calledByEntry(alice)) - .sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Method only callable by the contract itself", neow3j); + public void fail_calling_add_member_directly() { + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.invokeFunction(ADD_MEMBER, hash160(bob)).signers(AccountSigner.calledByEntry(alice)).sign() + ); + assertTrue(e.getMessage().endsWith("Method only callable by the contract itself")); } @Order(1) // Is executed before the execute_remove_member test which removes bob from members. @@ -105,7 +107,8 @@ public void execute_add_member() throws Throwable { gov.getScriptHash(), ADD_MEMBER, array(publicKey(bob.getECKeyPair().getPublicKey().getEncoded(true))), - CallFlags.ALL.getValue())); + CallFlags.ALL.getValue() + )); String offchainUri = "execute_add_member"; // 1. Create and endorse proposal @@ -118,8 +121,8 @@ public void execute_add_member() throws Throwable { // 3. Skip till after vote and queued phase, then execute. ext.fastForwardOneBlock(PHASE_LENGTH + PHASE_LENGTH); - Hash256 tx = gov.execute(id).signers(AccountSigner.calledByEntry(charlie)).sign().send() - .getSendRawTransaction().getHash(); + Hash256 tx = gov.execute(id).signers( + AccountSigner.calledByEntry(charlie)).sign().send().getSendRawTransaction().getHash(); Await.waitUntilTransactionIsExecuted(tx, neow3j); NeoApplicationLog.Execution execution = neow3j.getApplicationLog(tx).send() @@ -129,7 +132,8 @@ public void execute_add_member() throws Throwable { assertThat(returnVals.get(0).getValue(), is(nullValue())); assertThat(execution.getNotifications().get(0).getEventName(), is(MEMBER_ADDED)); assertThat(execution.getNotifications().get(0).getState().getList().get(0).getAddress(), - is(bob.getAddress())); + is(bob.getAddress()) + ); assertThat(execution.getNotifications().get(1).getEventName(), is(PROPOSAL_EXECUTED)); List newMembers = gov.getMembers(); @@ -138,7 +142,8 @@ public void execute_add_member() throws Throwable { bob.getECKeyPair().getPublicKey(), charlie.getECKeyPair().getPublicKey(), alice.getECKeyPair().getPublicKey(), - denise.getECKeyPair().getPublicKey())); + denise.getECKeyPair().getPublicKey() + )); assertThat(gov.getMembersCount(), is(4)); } @@ -149,7 +154,8 @@ public void fail_execute_add_member_with_already_member() throws Throwable { gov.getScriptHash(), ADD_MEMBER, array(publicKey(alice.getECKeyPair().getPublicKey().getEncoded(true))), - CallFlags.ALL.getValue())); + CallFlags.ALL.getValue() + )); String offchainUri = "fail_execute_add_member_with_already_member"; // 1. Create and endorse proposal @@ -160,9 +166,10 @@ public void fail_execute_add_member_with_already_member() throws Throwable { voteForProposal(gov, neow3j, id, charlie); // 3. Skip till after vote and queued phase, then execute. ext.fastForwardOneBlock(PHASE_LENGTH + PHASE_LENGTH); - Hash256 tx = gov.execute(id).signers(AccountSigner.calledByEntry(charlie)).sign().send() - .getSendRawTransaction().getHash(); - assertAborted(tx, "Already a member", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.execute(id).signers(AccountSigner.calledByEntry(charlie)).sign() + ); + assertTrue(e.getMessage().endsWith("Already a member")); } @Test @@ -173,7 +180,8 @@ public void fail_execute_add_member_with_invalid_public_key() throws Throwable { gov.getScriptHash(), ADD_MEMBER, array(publicKey(invalidPubKey)), - CallFlags.ALL.getValue())); + CallFlags.ALL.getValue() + )); String offchainUri = "fail_execute_add_member_with_invalid_public_key"; // 1. Create and endorse proposal @@ -192,10 +200,12 @@ public void fail_execute_add_member_with_invalid_public_key() throws Throwable { //region REMOVE MEMBER @Test - public void fail_calling_remove_member_directly() throws Throwable { - Hash256 tx = gov.invokeFunction(REMOVE_MEMBER, hash160(bob)).signers(AccountSigner.calledByEntry(alice)) - .sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Method only callable by the contract itself", neow3j); + public void fail_calling_remove_member_directly() { + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.invokeFunction(REMOVE_MEMBER, hash160(bob)).signers( + AccountSigner.calledByEntry(alice)).sign() + ); + assertTrue(e.getMessage().endsWith("Method only callable by the contract itself")); } @Order(2) // Is executed right after the execute_add_member test to remove bob from members @@ -207,7 +217,8 @@ public void execute_remove_member() throws Throwable { gov.getScriptHash(), REMOVE_MEMBER, array(publicKey(bob.getECKeyPair().getPublicKey().getEncoded(true))), - CallFlags.ALL.getValue())); + CallFlags.ALL.getValue() + )); String offchainUri = "execute_remove_member"; // 1. Create and endorse proposal @@ -220,8 +231,8 @@ public void execute_remove_member() throws Throwable { // 3. Skip till after vote and queued phase, then execute. ext.fastForwardOneBlock(PHASE_LENGTH + PHASE_LENGTH); - Hash256 tx = gov.execute(id).signers(AccountSigner.calledByEntry(charlie)).sign().send() - .getSendRawTransaction().getHash(); + Hash256 tx = gov.execute(id).signers( + AccountSigner.calledByEntry(charlie)).sign().send().getSendRawTransaction().getHash(); Await.waitUntilTransactionIsExecuted(tx, neow3j); NeoApplicationLog.Execution execution = neow3j.getApplicationLog(tx).send() @@ -231,7 +242,8 @@ public void execute_remove_member() throws Throwable { assertThat(returnVals.get(0).getValue(), is(nullValue())); assertThat(execution.getNotifications().get(0).getEventName(), is(MEMBER_REMOVED)); assertThat(execution.getNotifications().get(0).getState().getList().get(0).getAddress(), - is(bob.getAddress())); + is(bob.getAddress()) + ); assertThat(execution.getNotifications().get(1).getEventName(), is(PROPOSAL_EXECUTED)); List newMembers = gov.getMembers(); @@ -239,7 +251,8 @@ public void execute_remove_member() throws Throwable { assertThat(newMembers, containsInAnyOrder( charlie.getECKeyPair().getPublicKey(), alice.getECKeyPair().getPublicKey(), - denise.getECKeyPair().getPublicKey())); + denise.getECKeyPair().getPublicKey() + )); } @Test @@ -249,7 +262,8 @@ public void fail_execute_remove_member_with_non_member() throws Throwable { gov.getScriptHash(), REMOVE_MEMBER, array(publicKey(acc.getECKeyPair().getPublicKey().getEncoded(true))), - CallFlags.ALL.getValue())); + CallFlags.ALL.getValue() + )); String offchainUri = "fail_execute_remove_member_with_non_member"; // 1. Create and endorse proposal @@ -260,9 +274,10 @@ public void fail_execute_remove_member_with_non_member() throws Throwable { voteForProposal(gov, neow3j, id, charlie); // 3. Skip till after vote and queued phase, then execute. ext.fastForwardOneBlock(PHASE_LENGTH + PHASE_LENGTH); - Hash256 tx = gov.execute(id).signers(AccountSigner.calledByEntry(charlie)) - .sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Not a member", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.execute(id).signers(AccountSigner.calledByEntry(charlie)).sign() + ); + assertTrue(e.getMessage().endsWith("Not a member")); } //endregion REMOVE MEMBER @@ -275,7 +290,8 @@ public void get_members() throws IOException { assertThat(members, contains( alice.getECKeyPair().getPublicKey().getEncoded(true), charlie.getECKeyPair().getPublicKey().getEncoded(true), - denise.getECKeyPair().getPublicKey().getEncoded(true))); + denise.getECKeyPair().getPublicKey().getEncoded(true) + )); } @Test diff --git a/src/test/java/com/axlabs/neo/grantshares/GovernanceParametersTest.java b/src/test/java/com/axlabs/neo/grantshares/GovernanceParametersTest.java index a253aa4..bccb32f 100644 --- a/src/test/java/com/axlabs/neo/grantshares/GovernanceParametersTest.java +++ b/src/test/java/com/axlabs/neo/grantshares/GovernanceParametersTest.java @@ -10,6 +10,7 @@ import io.neow3j.test.DeployConfig; import io.neow3j.test.DeployConfiguration; import io.neow3j.transaction.AccountSigner; +import io.neow3j.transaction.exceptions.TransactionConfigurationException; import io.neow3j.types.ContractParameter; import io.neow3j.types.Hash256; import io.neow3j.utils.Await; @@ -23,24 +24,23 @@ import java.util.List; import java.util.Map; -import static com.axlabs.neo.grantshares.util.TestHelper.ALICE; -import static com.axlabs.neo.grantshares.util.TestHelper.BOB; -import static com.axlabs.neo.grantshares.util.TestHelper.CHANGE_PARAM; -import static com.axlabs.neo.grantshares.util.TestHelper.CHARLIE; -import static com.axlabs.neo.grantshares.util.TestHelper.EXPIRATION_LENGTH_KEY; -import static com.axlabs.neo.grantshares.util.TestHelper.MIN_ACCEPTANCE_RATE; -import static com.axlabs.neo.grantshares.util.TestHelper.MIN_ACCEPTANCE_RATE_KEY; -import static com.axlabs.neo.grantshares.util.TestHelper.MIN_QUORUM; -import static com.axlabs.neo.grantshares.util.TestHelper.MIN_QUORUM_KEY; -import static com.axlabs.neo.grantshares.util.TestHelper.MULTI_SIG_THRESHOLD_KEY; -import static com.axlabs.neo.grantshares.util.TestHelper.MULTI_SIG_THRESHOLD_RATIO; -import static com.axlabs.neo.grantshares.util.TestHelper.PARAMETER_CHANGED; -import static com.axlabs.neo.grantshares.util.TestHelper.PHASE_LENGTH; -import static com.axlabs.neo.grantshares.util.TestHelper.PROPOSAL_EXECUTED; -import static com.axlabs.neo.grantshares.util.TestHelper.REVIEW_LENGTH_KEY; -import static com.axlabs.neo.grantshares.util.TestHelper.TIMELOCK_LENGTH_KEY; -import static com.axlabs.neo.grantshares.util.TestHelper.VOTING_LENGTH_KEY; -import static com.axlabs.neo.grantshares.util.TestHelper.assertAborted; +import static com.axlabs.neo.grantshares.util.TestHelper.Events.PARAMETER_CHANGED; +import static com.axlabs.neo.grantshares.util.TestHelper.Events.PROPOSAL_EXECUTED; +import static com.axlabs.neo.grantshares.util.TestHelper.GovernanceMethods.CHANGE_PARAM; +import static com.axlabs.neo.grantshares.util.TestHelper.Members.ALICE; +import static com.axlabs.neo.grantshares.util.TestHelper.Members.BOB; +import static com.axlabs.neo.grantshares.util.TestHelper.Members.CHARLIE; +import static com.axlabs.neo.grantshares.util.TestHelper.ParameterNames.EXPIRATION_LENGTH_KEY; +import static com.axlabs.neo.grantshares.util.TestHelper.ParameterNames.MIN_ACCEPTANCE_RATE_KEY; +import static com.axlabs.neo.grantshares.util.TestHelper.ParameterNames.MIN_QUORUM_KEY; +import static com.axlabs.neo.grantshares.util.TestHelper.ParameterNames.MULTI_SIG_THRESHOLD_KEY; +import static com.axlabs.neo.grantshares.util.TestHelper.ParameterNames.REVIEW_LENGTH_KEY; +import static com.axlabs.neo.grantshares.util.TestHelper.ParameterNames.TIMELOCK_LENGTH_KEY; +import static com.axlabs.neo.grantshares.util.TestHelper.ParameterNames.VOTING_LENGTH_KEY; +import static com.axlabs.neo.grantshares.util.TestHelper.ParameterValues.MIN_ACCEPTANCE_RATE; +import static com.axlabs.neo.grantshares.util.TestHelper.ParameterValues.MIN_QUORUM; +import static com.axlabs.neo.grantshares.util.TestHelper.ParameterValues.MULTI_SIG_THRESHOLD_RATIO; +import static com.axlabs.neo.grantshares.util.TestHelper.ParameterValues.PHASE_LENGTH; import static com.axlabs.neo.grantshares.util.TestHelper.createAndEndorseProposal; import static com.axlabs.neo.grantshares.util.TestHelper.prepareDeployParameter; import static com.axlabs.neo.grantshares.util.TestHelper.voteForProposal; @@ -50,6 +50,8 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.core.Is.is; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; @ContractTest(contracts = GrantSharesGov.class, blockTime = 1, configFile = "default.neo-express", batchFile = "setup.batch") @@ -75,7 +77,6 @@ public static DeployConfiguration deployConfig() throws Exception { @BeforeAll public static void setUp() throws Throwable { neow3j = ext.getNeow3j(); - neow3j.allowTransmissionOnFault(); gov = new GrantSharesGovContract(ext.getDeployedContract(GrantSharesGov.class).getScriptHash(), neow3j); alice = ext.getAccount(ALICE); bob = ext.getAccount(BOB); @@ -137,10 +138,12 @@ public void execute_change_parameter() throws Throwable { } @Test - public void fail_calling_change_parameter_directly() throws Throwable { - Hash256 tx = gov.invokeFunction(CHANGE_PARAM, string(REVIEW_LENGTH_KEY), integer(100)) - .signers(AccountSigner.calledByEntry(alice)).sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Method only callable by the contract itself", neow3j); + public void fail_calling_change_parameter_directly() { + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.invokeFunction(CHANGE_PARAM, string(REVIEW_LENGTH_KEY), integer(100)).signers( + AccountSigner.calledByEntry(alice)).sign() + ); + assertTrue(e.getMessage().endsWith("Method only callable by the contract itself")); } @Test @@ -158,9 +161,10 @@ public void fail_changing_unknown_parameter() throws Throwable { // 3. Skip till after vote and queued phase, then execute. ext.fastForwardOneBlock(PHASE_LENGTH + PHASE_LENGTH); - Hash256 tx = gov.execute(id).signers(AccountSigner.calledByEntry(bob)) - .sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Unknown parameter", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.execute(id).signers(AccountSigner.calledByEntry(bob)).sign() + ); + assertTrue(e.getMessage().endsWith("Unknown parameter")); } @Test @@ -176,9 +180,10 @@ public void fail_changing_voting_length_to_negative_value() throws Throwable { // 3. Skip till after vote and queued phase, then execute. ext.fastForwardOneBlock(PHASE_LENGTH + PHASE_LENGTH); - Hash256 tx = gov.execute(id).signers(AccountSigner.calledByEntry(bob)) - .sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Invalid parameter value", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.execute(id).signers(AccountSigner.calledByEntry(bob)).sign() + ); + assertTrue(e.getMessage().endsWith("Invalid parameter value")); assertThat(gov.getParameter(VOTING_LENGTH_KEY).getInteger().intValue(), is(PHASE_LENGTH * 1000)); } @@ -195,9 +200,10 @@ public void fail_changing_min_acceptance_rate_to_negative_value() throws Throwab // 3. Skip till after vote and queued phase, then execute. ext.fastForwardOneBlock(PHASE_LENGTH + PHASE_LENGTH); - Hash256 tx = gov.execute(id).signers(AccountSigner.calledByEntry(bob)) - .sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Invalid parameter value", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.execute(id).signers(AccountSigner.calledByEntry(bob)).sign() + ); + assertTrue(e.getMessage().endsWith("Invalid parameter value")); assertThat(gov.getParameter(MIN_ACCEPTANCE_RATE_KEY).getInteger().intValue(), is(MIN_ACCEPTANCE_RATE)); } @@ -214,9 +220,10 @@ public void fail_changing_min_acceptance_rate_to_more_than_hundred() throws Thro // 3. Skip till after vote and queued phase, then execute. ext.fastForwardOneBlock(PHASE_LENGTH + PHASE_LENGTH); - Hash256 tx = gov.execute(id).signers(AccountSigner.calledByEntry(bob)) - .sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Invalid parameter value", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.execute(id).signers(AccountSigner.calledByEntry(bob)).sign() + ); + assertTrue(e.getMessage().endsWith("Invalid parameter value")); assertThat(gov.getParameter(MIN_ACCEPTANCE_RATE_KEY).getInteger().intValue(), is(MIN_ACCEPTANCE_RATE)); } @@ -233,9 +240,10 @@ public void fail_changing_multisig_threshold_to_zero() throws Throwable { // 3. Skip till after vote and queued phase, then execute. ext.fastForwardOneBlock(PHASE_LENGTH + PHASE_LENGTH); - Hash256 tx = gov.execute(id).signers(AccountSigner.calledByEntry(bob)) - .sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Invalid parameter value", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.execute(id).signers(AccountSigner.calledByEntry(bob)).sign() + ); + assertTrue(e.getMessage().endsWith("Invalid parameter value")); assertThat(gov.getParameter(MULTI_SIG_THRESHOLD_KEY).getInteger().intValue(), is(MULTI_SIG_THRESHOLD_RATIO)); } @@ -252,9 +260,10 @@ public void fail_changing_multisig_threshold_to_more_than_hundred() throws Throw // 3. Skip till after vote and queued phase, then execute. ext.fastForwardOneBlock(PHASE_LENGTH + PHASE_LENGTH); - Hash256 tx = gov.execute(id).signers(AccountSigner.calledByEntry(bob)) - .sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Invalid parameter value", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.execute(id).signers(AccountSigner.calledByEntry(bob)).sign() + ); + assertTrue(e.getMessage().endsWith("Invalid parameter value")); assertThat(gov.getParameter(MULTI_SIG_THRESHOLD_KEY).getInteger().intValue(), is(MULTI_SIG_THRESHOLD_RATIO)); } diff --git a/src/test/java/com/axlabs/neo/grantshares/GrantSharesGovTest.java b/src/test/java/com/axlabs/neo/grantshares/GrantSharesGovTest.java index 9970179..cdaba78 100644 --- a/src/test/java/com/axlabs/neo/grantshares/GrantSharesGovTest.java +++ b/src/test/java/com/axlabs/neo/grantshares/GrantSharesGovTest.java @@ -9,7 +9,11 @@ import io.neow3j.contract.NefFile; import io.neow3j.contract.NeoToken; import io.neow3j.protocol.Neow3j; -import io.neow3j.protocol.core.response.*; +import io.neow3j.protocol.core.response.ContractManifest; +import io.neow3j.protocol.core.response.InvocationResult; +import io.neow3j.protocol.core.response.NeoApplicationLog; +import io.neow3j.protocol.core.response.NeoInvokeFunction; +import io.neow3j.protocol.core.response.Notification; import io.neow3j.protocol.core.stackitem.StackItem; import io.neow3j.test.ContractTest; import io.neow3j.test.ContractTestExtension; @@ -18,6 +22,7 @@ import io.neow3j.transaction.AccountSigner; import io.neow3j.transaction.Transaction; import io.neow3j.transaction.Witness; +import io.neow3j.transaction.exceptions.TransactionConfigurationException; import io.neow3j.types.CallFlags; import io.neow3j.types.ContractParameter; import io.neow3j.types.Hash160; @@ -36,32 +41,20 @@ import java.math.BigInteger; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Collections; import java.util.List; -import static com.axlabs.neo.grantshares.util.TestHelper.ADD_MEMBER; -import static com.axlabs.neo.grantshares.util.TestHelper.ALICE; -import static com.axlabs.neo.grantshares.util.TestHelper.BOB; -import static com.axlabs.neo.grantshares.util.TestHelper.CHANGE_PARAM; -import static com.axlabs.neo.grantshares.util.TestHelper.CHARLIE; -import static com.axlabs.neo.grantshares.util.TestHelper.CREATE; -import static com.axlabs.neo.grantshares.util.TestHelper.ENDORSE; -import static com.axlabs.neo.grantshares.util.TestHelper.EXECUTE; -import static com.axlabs.neo.grantshares.util.TestHelper.GET_PROPOSAL; -import static com.axlabs.neo.grantshares.util.TestHelper.GET_PROPOSAL_COUNT; -import static com.axlabs.neo.grantshares.util.TestHelper.IS_PAUSED; -import static com.axlabs.neo.grantshares.util.TestHelper.MIN_ACCEPTANCE_RATE; -import static com.axlabs.neo.grantshares.util.TestHelper.MIN_ACCEPTANCE_RATE_KEY; -import static com.axlabs.neo.grantshares.util.TestHelper.MIN_QUORUM; -import static com.axlabs.neo.grantshares.util.TestHelper.PAUSE; -import static com.axlabs.neo.grantshares.util.TestHelper.PHASE_LENGTH; -import static com.axlabs.neo.grantshares.util.TestHelper.PROPOSAL_CREATED; -import static com.axlabs.neo.grantshares.util.TestHelper.PROPOSAL_ENDORSED; -import static com.axlabs.neo.grantshares.util.TestHelper.REMOVE_MEMBER; -import static com.axlabs.neo.grantshares.util.TestHelper.UNPAUSE; -import static com.axlabs.neo.grantshares.util.TestHelper.UPDATE_CONTRACT; -import static com.axlabs.neo.grantshares.util.TestHelper.VOTE; -import static com.axlabs.neo.grantshares.util.TestHelper.VOTED; -import static com.axlabs.neo.grantshares.util.TestHelper.assertAborted; +import static com.axlabs.neo.grantshares.util.TestHelper.Events.PROPOSAL_CREATED; +import static com.axlabs.neo.grantshares.util.TestHelper.Events.PROPOSAL_ENDORSED; +import static com.axlabs.neo.grantshares.util.TestHelper.Events.VOTED; +import static com.axlabs.neo.grantshares.util.TestHelper.GovernanceMethods.*; +import static com.axlabs.neo.grantshares.util.TestHelper.Members.ALICE; +import static com.axlabs.neo.grantshares.util.TestHelper.Members.BOB; +import static com.axlabs.neo.grantshares.util.TestHelper.Members.CHARLIE; +import static com.axlabs.neo.grantshares.util.TestHelper.ParameterNames.MIN_ACCEPTANCE_RATE_KEY; +import static com.axlabs.neo.grantshares.util.TestHelper.ParameterValues.MIN_ACCEPTANCE_RATE; +import static com.axlabs.neo.grantshares.util.TestHelper.ParameterValues.MIN_QUORUM; +import static com.axlabs.neo.grantshares.util.TestHelper.ParameterValues.PHASE_LENGTH; import static com.axlabs.neo.grantshares.util.TestHelper.createAndEndorseProposal; import static com.axlabs.neo.grantshares.util.TestHelper.createMultiSigAccount; import static com.axlabs.neo.grantshares.util.TestHelper.createSimpleProposal; @@ -83,6 +76,7 @@ import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsNot.not; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @ContractTest(contracts = GrantSharesGov.class, blockTime = 1, configFile = "default.neo-express", @@ -91,8 +85,9 @@ public class GrantSharesGovTest { @RegisterExtension - private static ContractTestExtension ext = new ContractTestExtension(); - + private static final ContractTestExtension ext = new ContractTestExtension(); + private final static Path TESTCONTRACT_NEF_FILE = Paths.get("TestContract.nef"); + private final static Path TESTCONTRACT_MANIFEST_FILE = Paths.get("TestGrantSharesGov.manifest.json"); private static Neow3j neow3j; private static GrantSharesGovContract gov; private static Account alice; // Set to be a DAO member. @@ -100,37 +95,30 @@ public class GrantSharesGovTest { private static Account charlie; // Set to be a DAO member. private static int defaultProposalId; - private final static Path TESTCONTRACT_NEF_FILE = Paths.get("TestContract.nef"); - private final static Path TESTCONTRACT_MANIFEST_FILE = - Paths.get("TestGrantSharesGov.manifest.json"); - @DeployConfig(GrantSharesGov.class) public static DeployConfiguration deployConfig() throws Exception { DeployConfiguration config = new DeployConfiguration(); - config.setDeployParam(prepareDeployParameter( - ext.getAccount(ALICE), ext.getAccount(CHARLIE))); + config.setDeployParam(prepareDeployParameter(ext.getAccount(ALICE), ext.getAccount(CHARLIE))); return config; } @BeforeAll public static void setUp() throws Throwable { neow3j = ext.getNeow3j(); - neow3j.allowTransmissionOnFault(); gov = new GrantSharesGovContract(ext.getDeployedContract(GrantSharesGov.class).getScriptHash(), neow3j); alice = ext.getAccount(ALICE); bob = ext.getAccount(BOB); charlie = ext.getAccount(CHARLIE); Hash256 creationTx = gov.invokeFunction(CREATE, hash160(alice.getScriptHash()), - array(array(NeoToken.SCRIPT_HASH, "balanceOf", array(new Hash160(defaultAccountScriptHash())), - integer(CallFlags.ALL.getValue()))), - string("default_proposal"), - integer(-1)) - .signers(AccountSigner.calledByEntry(alice)) - .sign().send().getSendRawTransaction().getHash(); + array(array(NeoToken.SCRIPT_HASH, "balanceOf", array(new Hash160(defaultAccountScriptHash())), + integer(CallFlags.ALL.getValue()) + )), string("default_proposal"), integer(-1) + ).signers( + AccountSigner.calledByEntry(alice)).sign().send().getSendRawTransaction().getHash(); Await.waitUntilTransactionIsExecuted(creationTx, neow3j); - defaultProposalId = neow3j.getApplicationLog(creationTx).send().getApplicationLog() - .getExecutions().get(0).getStack().get(0).getInteger().intValue(); + defaultProposalId = neow3j.getApplicationLog(creationTx).send().getApplicationLog().getExecutions().get( + 0).getStack().get(0).getInteger().intValue(); } @Test @@ -142,20 +130,18 @@ public void succeed_creating_and_retrieving_proposal() throws Throwable { Hash160 targetParam1 = gov.getScriptHash(); Hash160 targetParam2 = alice.getScriptHash(); int targetParam3 = 1; - ContractParameter intent = array(targetContract, targetMethod, - array(targetParam1, targetParam2, targetParam3), integer(CallFlags.ALL.getValue())); + ContractParameter intent = array(targetContract, targetMethod, array(targetParam1, targetParam2, targetParam3), + integer(CallFlags.ALL.getValue()) + ); String offchainUri = "offchainUri of the proposal"; - Hash256 proposalCreationTx = gov.invokeFunction(CREATE, - hash160(alice.getScriptHash()), - array(intent), - string(offchainUri), - integer(-1)) // no linked proposal - .signers(AccountSigner.calledByEntry(alice)) - .sign().send().getSendRawTransaction().getHash(); + Hash256 proposalCreationTx = gov.invokeFunction(CREATE, hash160(alice.getScriptHash()), array(intent), + string(offchainUri), integer(-1) + ) // no linked proposal + .signers(AccountSigner.calledByEntry(alice)).sign().send().getSendRawTransaction().getHash(); Await.waitUntilTransactionIsExecuted(proposalCreationTx, neow3j); - int id = neow3j.getApplicationLog(proposalCreationTx).send() - .getApplicationLog().getExecutions().get(0).getStack().get(0).getInteger().intValue(); + int id = neow3j.getApplicationLog(proposalCreationTx).send().getApplicationLog().getExecutions().get( + 0).getStack().get(0).getInteger().intValue(); // 2. Test correct setup of the created proposal. NeoInvokeFunction r = gov.callInvokeFunction(GET_PROPOSAL, asList(integer(id))); @@ -176,9 +162,8 @@ public void succeed_creating_and_retrieving_proposal() throws Throwable { assertThat(p.intents.get(0).params.get(2).getInteger().intValue(), is(targetParam3)); // 3. Test CreateProposal event values - List ntfs = - neow3j.getApplicationLog(proposalCreationTx).send().getApplicationLog() - .getExecutions().get(0).getNotifications(); + List ntfs = neow3j.getApplicationLog( + proposalCreationTx).send().getApplicationLog().getExecutions().get(0).getNotifications(); Notification ntf = ntfs.get(0); assertThat(ntf.getEventName(), is(PROPOSAL_CREATED)); @@ -191,46 +176,62 @@ public void succeed_creating_and_retrieving_proposal() throws Throwable { @Test @Order(0) - public void fail_creating_with_missing_linked_proposal() throws Throwable { + public void fail_creating_with_missing_linked_proposal() { ContractParameter intent = array(NeoToken.SCRIPT_HASH, "transfer", - array(gov.getScriptHash(), alice.getScriptHash(), 1)); + array(gov.getScriptHash(), alice.getScriptHash(), 1) + ); String offchainUri = "fail_creating_with_missing_linked_proposal"; - Hash256 tx = gov.createProposal(alice.getScriptHash(), offchainUri, 1000, intent) - .signers(AccountSigner.calledByEntry(alice)).sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Linked proposal doesn't exist", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.createProposal(alice.getScriptHash(), offchainUri, 1000, intent).signers( + AccountSigner.calledByEntry(alice)).sign() + ); + assertTrue(e.getMessage().endsWith("Linked proposal doesn't exist")); } @Test @Order(0) - public void fail_creating_with_bad_quorum() throws Throwable { + public void fail_creating_with_bad_quorum() { ContractParameter intent = array(NeoToken.SCRIPT_HASH, "transfer", - array(gov.getScriptHash(), alice.getScriptHash(), 1)); + array(gov.getScriptHash(), alice.getScriptHash(), 1) + ); String offchainUri = "fail_creating_with_bad_quorum"; - Hash256 tx = gov.createProposal(alice.getScriptHash(), offchainUri, -1, MIN_ACCEPTANCE_RATE, MIN_QUORUM - 1, - intent).signers(AccountSigner.calledByEntry(alice)).sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Invalid quorum", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.createProposal(alice.getScriptHash(), offchainUri, -1, MIN_ACCEPTANCE_RATE, MIN_QUORUM - 1, + intent + ).signers(AccountSigner.calledByEntry(alice)).sign() + ); + assertTrue(e.getMessage().endsWith("Invalid quorum")); - tx = gov.createProposal(alice.getScriptHash(), offchainUri, -1, MIN_ACCEPTANCE_RATE, 101, intent) - .signers(AccountSigner.calledByEntry(alice)).sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Invalid quorum", neow3j); + e = assertThrows(TransactionConfigurationException.class, + () -> gov.createProposal(alice.getScriptHash(), offchainUri, -1, MIN_ACCEPTANCE_RATE, 101, + intent + ).signers(AccountSigner.calledByEntry(alice)).sign() + ); + assertTrue(e.getMessage().endsWith("Invalid quorum")); } @Test @Order(0) - public void fail_creating_with_bad_acceptance_rate() throws Throwable { + public void fail_creating_with_bad_acceptance_rate() { ContractParameter intent = array(NeoToken.SCRIPT_HASH, "transfer", - array(gov.getScriptHash(), alice.getScriptHash(), 1)); + array(gov.getScriptHash(), alice.getScriptHash(), 1) + ); String offchainUri = "fail_creating_with_bad_acceptance_rate"; - Hash256 tx = gov.createProposal(alice.getScriptHash(), offchainUri, -1, MIN_ACCEPTANCE_RATE - 1, MIN_QUORUM, - intent).signers(AccountSigner.calledByEntry(alice)).sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Invalid acceptance rate", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.createProposal(alice.getScriptHash(), offchainUri, -1, MIN_ACCEPTANCE_RATE - 1, MIN_QUORUM, + intent + ).signers(AccountSigner.calledByEntry(alice)).sign() + ); + assertTrue(e.getMessage().endsWith("Invalid acceptance rate")); - tx = gov.createProposal(alice.getScriptHash(), offchainUri, -1, 101, MIN_QUORUM, intent) - .signers(AccountSigner.calledByEntry(alice)).sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Invalid acceptance rate", neow3j); + e = assertThrows(TransactionConfigurationException.class, + () -> gov.createProposal(alice.getScriptHash(), offchainUri, -1, 101, MIN_QUORUM, intent).signers( + AccountSigner.calledByEntry(alice)).sign() + ); + assertTrue(e.getMessage().endsWith("Invalid acceptance rate")); } @Test @@ -239,8 +240,8 @@ public void succeed_endorsing_with_member() throws Throwable { // 1. Create a proposal Hash256 creationTx = createSimpleProposal(gov, alice, "succeed_endorsing_with_member"); Await.waitUntilTransactionIsExecuted(creationTx, neow3j); - int id = neow3j.getApplicationLog(creationTx).send() - .getApplicationLog().getExecutions().get(0).getStack().get(0).getInteger().intValue(); + int id = neow3j.getApplicationLog(creationTx).send().getApplicationLog().getExecutions().get(0).getStack().get( + 0).getInteger().intValue(); // 2. Test that proposal endorser and phases have not yet been setup. ProposalStruct p = gov.getProposal(id); @@ -251,10 +252,8 @@ public void succeed_endorsing_with_member() throws Throwable { assertThat(p.expiration, is(greaterThan(BigInteger.ZERO))); // 3. Endorse - Hash256 endorseTx = gov.invokeFunction(ENDORSE, integer(id), - hash160(alice.getScriptHash())) - .signers(AccountSigner.calledByEntry(alice)) - .sign().send().getSendRawTransaction().getHash(); + Hash256 endorseTx = gov.invokeFunction(ENDORSE, integer(id), hash160(alice.getScriptHash())).signers( + AccountSigner.calledByEntry(alice)).sign().send().getSendRawTransaction().getHash(); Await.waitUntilTransactionIsExecuted(endorseTx, neow3j); // 4. Test the right setup of the proposal phases @@ -275,8 +274,8 @@ public void succeed_endorsing_with_member() throws Throwable { assertThat(p.abstain, is(0)); // 6. Test emitted "endorsed" event - Notification ntf = neow3j.getApplicationLog(endorseTx).send() - .getApplicationLog().getExecutions().get(0).getNotifications().get(0); + Notification ntf = neow3j.getApplicationLog(endorseTx).send().getApplicationLog().getExecutions().get( + 0).getNotifications().get(0); assertThat(ntf.getEventName(), is(PROPOSAL_ENDORSED)); List state = ntf.getState().getList(); assertThat(state.get(0).getInteger().intValue(), is(id)); @@ -285,18 +284,22 @@ public void succeed_endorsing_with_member() throws Throwable { @Test @Order(0) - public void fail_endorsing_with_non_member() throws Throwable { - Hash256 tx = gov.endorseProposal(defaultProposalId, bob.getScriptHash()) - .signers(AccountSigner.calledByEntry(bob)).sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Not authorised", neow3j); + public void fail_endorsing_with_non_member() { + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.endorseProposal(defaultProposalId, bob.getScriptHash()).signers( + AccountSigner.calledByEntry(bob)).sign() + ); + assertTrue(e.getMessage().endsWith("Not authorised")); } @Test @Order(0) - public void fail_endorsing_with_member_but_wrong_signer() throws Throwable { - Hash256 tx = gov.endorseProposal(defaultProposalId, alice.getScriptHash()) - .signers(AccountSigner.calledByEntry(bob)).sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Not authorised", neow3j); + public void fail_endorsing_with_member_but_wrong_signer() { + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.endorseProposal(defaultProposalId, alice.getScriptHash()).signers( + AccountSigner.calledByEntry(bob)).sign() + ); + assertTrue(e.getMessage().endsWith("Not authorised")); } @Test @@ -305,26 +308,30 @@ public void fail_endorsing_already_endorsed_proposal() throws Throwable { // 1. Create a proposal Hash256 creationTx = createSimpleProposal(gov, alice, "fail_endorsing_already_endorsed_proposal"); Await.waitUntilTransactionIsExecuted(creationTx, neow3j); - int id = neow3j.getApplicationLog(creationTx).send().getApplicationLog().getExecutions().get(0).getStack() - .get(0).getInteger().intValue(); + int id = neow3j.getApplicationLog(creationTx).send().getApplicationLog().getExecutions().get(0).getStack().get( + 0).getInteger().intValue(); // 2. Endorse - Hash256 endorseTx = gov.endorseProposal(id, alice.getScriptHash()).signers(AccountSigner.calledByEntry(alice)) - .sign().send().getSendRawTransaction().getHash(); + Hash256 endorseTx = gov.endorseProposal(id, alice.getScriptHash()).signers( + AccountSigner.calledByEntry(alice)).sign().send().getSendRawTransaction().getHash(); Await.waitUntilTransactionIsExecuted(endorseTx, neow3j); // 3. Endorse again - Hash256 tx = gov.endorseProposal(id, alice.getScriptHash()).signers(AccountSigner.calledByEntry(alice)) - .sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Proposal already endorsed", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.endorseProposal(id, alice.getScriptHash()).signers( + AccountSigner.calledByEntry(alice)).sign() + ); + assertTrue(e.getMessage().endsWith("Proposal already endorsed")); } @Test @Order(0) - public void fail_endorsing_non_existent_proposal() throws Throwable { - Hash256 tx = gov.endorseProposal(1000, alice.getScriptHash()).signers(AccountSigner.calledByEntry(alice)) - .sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Proposal doesn't exist", neow3j); + public void fail_endorsing_non_existent_proposal() { + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.endorseProposal(1000, alice.getScriptHash()).signers( + AccountSigner.calledByEntry(alice)).sign() + ); + assertTrue(e.getMessage().endsWith("Proposal doesn't exist")); } @Test @@ -332,13 +339,15 @@ public void fail_endorsing_non_existent_proposal() throws Throwable { public void fail_endorsing_expired_proposal() throws Throwable { Hash256 creationTx = createSimpleProposal(gov, bob, "fail_endorsing_expired_proposal"); Await.waitUntilTransactionIsExecuted(creationTx, neow3j); - int id = neow3j.getApplicationLog(creationTx).send() - .getApplicationLog().getExecutions().get(0).getStack().get(0).getInteger().intValue(); + int id = neow3j.getApplicationLog(creationTx).send().getApplicationLog().getExecutions().get(0).getStack().get( + 0).getInteger().intValue(); ext.fastForwardOneBlock(PHASE_LENGTH); - Hash256 tx = gov.endorseProposal(id, alice.getScriptHash()).signers(AccountSigner.calledByEntry(alice)) - .sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Proposal expired", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.endorseProposal(id, alice.getScriptHash()).signers( + AccountSigner.calledByEntry(alice)).sign() + ); + assertTrue(e.getMessage().endsWith("Proposal expired")); } @Test @@ -347,24 +356,20 @@ public void succeed_voting() throws Throwable { // 1. Create proposal Hash256 creationTx = createSimpleProposal(gov, bob, "succeed_voting"); Await.waitUntilTransactionIsExecuted(creationTx, neow3j); - int id = neow3j.getApplicationLog(creationTx).send() - .getApplicationLog().getExecutions().get(0).getStack().get(0).getInteger().intValue(); + int id = neow3j.getApplicationLog(creationTx).send().getApplicationLog().getExecutions().get(0).getStack().get( + 0).getInteger().intValue(); // 2. Endorse - Hash256 endorseTx = gov.invokeFunction(ENDORSE, integer(id), - hash160(alice.getScriptHash())) - .signers(AccountSigner.calledByEntry(alice)) - .sign().send().getSendRawTransaction().getHash(); + Hash256 endorseTx = gov.invokeFunction(ENDORSE, integer(id), hash160(alice.getScriptHash())).signers( + AccountSigner.calledByEntry(alice)).sign().send().getSendRawTransaction().getHash(); Await.waitUntilTransactionIsExecuted(endorseTx, neow3j); // 3. Wait till review phase ends. ext.fastForwardOneBlock(PHASE_LENGTH); // 4. Vote - Hash256 voteTx = gov.invokeFunction(VOTE, integer(id), integer(-1), - hash160(charlie.getScriptHash())) - .signers(AccountSigner.calledByEntry(charlie)) - .sign().send().getSendRawTransaction().getHash(); + Hash256 voteTx = gov.invokeFunction(VOTE, integer(id), integer(-1), hash160(charlie.getScriptHash())).signers( + AccountSigner.calledByEntry(charlie)).sign().send().getSendRawTransaction().getHash(); Await.waitUntilTransactionIsExecuted(voteTx, neow3j); // 5. Test the right setting of the votes @@ -376,8 +381,8 @@ public void succeed_voting() throws Throwable { assertThat(proposal.voters.get(charlie.getAddress()), is(-1)); // 6. Test the emitted vote event - Notification ntf = neow3j.getApplicationLog(voteTx).send() - .getApplicationLog().getExecutions().get(0).getNotifications().get(0); + Notification ntf = neow3j.getApplicationLog(voteTx).send().getApplicationLog().getExecutions().get( + 0).getNotifications().get(0); assertThat(ntf.getEventName(), is(VOTED)); List state = ntf.getState().getList(); assertThat(state.get(0).getInteger().intValue(), is(id)); @@ -390,28 +395,28 @@ public void succeed_voting() throws Throwable { public void fail_voting_in_review_and_queued_phase() throws Throwable { Hash256 creationTx = createSimpleProposal(gov, bob, "fail_voting_in_review_and_queued_phase"); Await.waitUntilTransactionIsExecuted(creationTx, neow3j); - int id = neow3j.getApplicationLog(creationTx).send().getApplicationLog().getExecutions() - .get(0).getStack().get(0).getInteger().intValue(); + int id = neow3j.getApplicationLog(creationTx).send().getApplicationLog().getExecutions().get(0).getStack().get( + 0).getInteger().intValue(); // 2. Endorse - Hash256 endorseTx = gov.invokeFunction(ENDORSE, integer(id), - hash160(alice.getScriptHash())) - .signers(AccountSigner.calledByEntry(alice)) - .sign().send().getSendRawTransaction().getHash(); + Hash256 endorseTx = gov.invokeFunction(ENDORSE, integer(id), hash160(alice.getScriptHash())).signers( + AccountSigner.calledByEntry(alice)).sign().send().getSendRawTransaction().getHash(); Await.waitUntilTransactionIsExecuted(endorseTx, neow3j); // 3. Vote in review phase - Hash256 tx = gov.vote(id, -1, charlie.getScriptHash()).signers(AccountSigner.calledByEntry(charlie)) - .sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Proposal not active", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.vote(id, -1, charlie.getScriptHash()).signers(AccountSigner.calledByEntry(charlie)).sign() + ); + assertTrue(e.getMessage().endsWith("Proposal not active")); // 5. Fast-forward till after the voting phase. ext.fastForwardOneBlock(PHASE_LENGTH + PHASE_LENGTH); // 4. Vote in queued or later phase - tx = gov.vote(id, -1, charlie.getScriptHash()).signers(AccountSigner.calledByEntry(charlie)) - .sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Proposal not active", neow3j); + e = assertThrows(TransactionConfigurationException.class, + () -> gov.vote(id, -1, charlie.getScriptHash()).signers(AccountSigner.calledByEntry(charlie)).sign() + ); + assertTrue(e.getMessage().endsWith("Proposal not active")); } @Test @@ -419,30 +424,27 @@ public void fail_voting_in_review_and_queued_phase() throws Throwable { public void fail_voting_multiple_times() throws Throwable { Hash256 creationTx = createSimpleProposal(gov, bob, "fail_voting_multiple_times"); Await.waitUntilTransactionIsExecuted(creationTx, neow3j); - int id = neow3j.getApplicationLog(creationTx).send() - .getApplicationLog().getExecutions().get(0).getStack().get(0).getInteger().intValue(); + int id = neow3j.getApplicationLog(creationTx).send().getApplicationLog().getExecutions().get(0).getStack().get( + 0).getInteger().intValue(); // 2. Endorse - Hash256 endorseTx = gov.invokeFunction(ENDORSE, integer(id), - hash160(alice.getScriptHash())) - .signers(AccountSigner.calledByEntry(alice)) - .sign().send().getSendRawTransaction().getHash(); + Hash256 endorseTx = gov.invokeFunction(ENDORSE, integer(id), hash160(alice.getScriptHash())).signers( + AccountSigner.calledByEntry(alice)).sign().send().getSendRawTransaction().getHash(); Await.waitUntilTransactionIsExecuted(endorseTx, neow3j); // 3. Fast-forward to the voting phase. ext.fastForwardOneBlock(PHASE_LENGTH); // 4. Vote the first time - Hash256 voteTx = gov.invokeFunction(VOTE, integer(id), integer(-1), - hash160(charlie.getScriptHash())) - .signers(AccountSigner.calledByEntry(charlie)) - .sign().send().getSendRawTransaction().getHash(); + Hash256 voteTx = gov.invokeFunction(VOTE, integer(id), integer(-1), hash160(charlie.getScriptHash())).signers( + AccountSigner.calledByEntry(charlie)).sign().send().getSendRawTransaction().getHash(); Await.waitUntilTransactionIsExecuted(voteTx, neow3j); // 5. Vote the second time - Hash256 tx = gov.vote(id, 1, charlie.getScriptHash()).signers(AccountSigner.calledByEntry(charlie)) - .sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Already voted on this proposal", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.vote(id, 1, charlie.getScriptHash()).signers(AccountSigner.calledByEntry(charlie)).sign() + ); + assertTrue(e.getMessage().endsWith("Already voted on this proposal")); // 6. Check votes ProposalStruct proposal = gov.getProposal(id); @@ -455,37 +457,44 @@ public void fail_voting_multiple_times() throws Throwable { @Test @Order(0) - public void fail_voting_with_non_member() throws Throwable { + public void fail_voting_with_non_member() { // Vote on the default proposal. Doesn't matter in what phase it is. - Hash256 tx = gov.vote(defaultProposalId, -1, bob.getScriptHash()).signers(AccountSigner.calledByEntry(bob)) - .sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Not authorised", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.vote(defaultProposalId, -1, bob.getScriptHash()).signers( + AccountSigner.calledByEntry(bob)).sign() + ); + assertTrue(e.getMessage().endsWith("Not authorised")); } @Test @Order(0) - public void fail_voting_on_non_existent_proposal() throws Throwable { - Hash256 tx = gov.vote(1000, -1, charlie.getScriptHash()).signers(AccountSigner.calledByEntry(charlie)).sign() - .send().getSendRawTransaction().getHash(); - assertAborted(tx, "Proposal doesn't exist", neow3j); + public void fail_voting_on_non_existent_proposal() { + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.vote(1000, -1, charlie.getScriptHash()).signers(AccountSigner.calledByEntry(charlie)).sign() + ); + assertTrue(e.getMessage().endsWith("Proposal doesn't exist")); } @Test @Order(0) - public void fail_voting_on_not_endorsed_proposal() throws Throwable { + public void fail_voting_on_not_endorsed_proposal() { // Vote on the default proposal. Doesn't matter in what phase it is. - Hash256 tx = gov.vote(defaultProposalId, -1, charlie.getScriptHash()) - .signers(AccountSigner.calledByEntry(charlie)).sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Proposal not active", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.vote(defaultProposalId, -1, charlie.getScriptHash()).signers( + AccountSigner.calledByEntry(charlie)).sign() + ); + assertTrue(e.getMessage().endsWith("Proposal not active")); } @Test @Order(0) - public void fail_voting_with_invalid_vote() throws Throwable { + public void fail_voting_with_invalid_vote() { // Vote on the default proposal. Doesn't matter in what phase it is. - Hash256 tx = gov.vote(defaultProposalId, 2, charlie.getScriptHash()) - .signers(AccountSigner.calledByEntry(charlie)).sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Invalid vote", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.vote(defaultProposalId, 2, charlie.getScriptHash()).signers( + AccountSigner.calledByEntry(charlie)).sign() + ); + assertTrue(e.getMessage().endsWith("Invalid vote")); } @Test @@ -494,71 +503,74 @@ public void create_proposal_with_large_intents_and_offchainUri() throws Throwabl String offchainUri = "aabcababcababcababcabbcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcaabcabcabcabcabcabca"; Hash256 tx = gov.invokeFunction(CREATE, hash160(bob), - array( - array(NeoToken.SCRIPT_HASH, "balanceOf", array(new Hash160(defaultAccountScriptHash())), - CallFlags.ALL.getValue()), - array(NeoToken.SCRIPT_HASH, "balanceOf", array(new Hash160(defaultAccountScriptHash())), - CallFlags.ALL.getValue()), - array(NeoToken.SCRIPT_HASH, "balanceOf", array(new Hash160(defaultAccountScriptHash())), - CallFlags.ALL.getValue()), - array(NeoToken.SCRIPT_HASH, "balanceOf", array(new Hash160(defaultAccountScriptHash())), - CallFlags.ALL.getValue()), - array(NeoToken.SCRIPT_HASH, "balanceOf", array(new Hash160(defaultAccountScriptHash())), - CallFlags.ALL.getValue()), - array(NeoToken.SCRIPT_HASH, "balanceOf", array(new Hash160(defaultAccountScriptHash())), - CallFlags.ALL.getValue()), - array(NeoToken.SCRIPT_HASH, "jjsldfjklkasjdfkljalkjasdf;lkjasddfd" + - "lfjkasdflkjasdfssldfjklkasjdfkljasasdfasfasdfasdf", - array( - new Hash160(defaultAccountScriptHash()), - new Hash160(defaultAccountScriptHash()), - new Hash160(defaultAccountScriptHash()), - new Hash160(defaultAccountScriptHash()), - new Hash160(defaultAccountScriptHash()), - new Hash160(defaultAccountScriptHash()) - ), CallFlags.ALL.getValue()), - array(NeoToken.SCRIPT_HASH, "jjsldfjklkasjdfkljalkjasdf;lkjasddfd" + - "lfjkasdflkjasdfssldfjklkasjdfkljasasdfasfasdfasdf", - array( - new Hash160(defaultAccountScriptHash()), - new Hash160(defaultAccountScriptHash()), - new Hash160(defaultAccountScriptHash()), - new Hash160(defaultAccountScriptHash()), - new Hash160(defaultAccountScriptHash()), - new Hash160(defaultAccountScriptHash()), - new Hash160(defaultAccountScriptHash()), - new Hash160(defaultAccountScriptHash()) - ), CallFlags.ALL.getValue()), - array(NeoToken.SCRIPT_HASH, "jjsldfjklkasjdfkljalkjasdf;lkjasddfd" + - "lfjkasdflkjasdfssldfjklkasjdfkljasasdfasfasdfasdf", - array( - new Hash160(defaultAccountScriptHash()), - new Hash160(defaultAccountScriptHash()), - new Hash160(defaultAccountScriptHash()), - new Hash160(defaultAccountScriptHash()), - new Hash160(defaultAccountScriptHash()), - new Hash160(defaultAccountScriptHash()), - new Hash160(defaultAccountScriptHash()), - new Hash160(defaultAccountScriptHash()), - new Hash160(defaultAccountScriptHash()), - "hlksajdfiojasdofjasodjflkjasdkfjlaijsdfiojpasodm" + - "hlksajdfiojasdofjasodjflkjasdkfjlaijsdfi" + - "hlksajdfiojasdofjasodjflkjasdkfjlaijsdfi" + - "hlksajdfiojasdofjasodjflkjasdkfjlaijsdfi" + - "hlksajdfiojasdofjasodjflkjasdkfjlaijsdfi" + - "hlksajdfiojasdofjasodjflkjasdkfjlaijsdfi" - ), CallFlags.ALL.getValue()) + array(array(NeoToken.SCRIPT_HASH, "balanceOf", array(new Hash160(defaultAccountScriptHash())), + CallFlags.ALL.getValue() + ), + array(NeoToken.SCRIPT_HASH, "balanceOf", array(new Hash160(defaultAccountScriptHash())), + CallFlags.ALL.getValue() + ), + array(NeoToken.SCRIPT_HASH, "balanceOf", array(new Hash160(defaultAccountScriptHash())), + CallFlags.ALL.getValue() ), - string(offchainUri), - integer(-1)) - .signers(AccountSigner.calledByEntry(bob)) - .sign().send().getSendRawTransaction().getHash(); + array(NeoToken.SCRIPT_HASH, "balanceOf", array(new Hash160(defaultAccountScriptHash())), + CallFlags.ALL.getValue() + ), + array(NeoToken.SCRIPT_HASH, "balanceOf", array(new Hash160(defaultAccountScriptHash())), + CallFlags.ALL.getValue() + ), + array(NeoToken.SCRIPT_HASH, "balanceOf", array(new Hash160(defaultAccountScriptHash())), + CallFlags.ALL.getValue() + ), array(NeoToken.SCRIPT_HASH, + "jjsldfjklkasjdfkljalkjasdf;lkjasddfd" + + "lfjkasdflkjasdfssldfjklkasjdfkljasasdfasfasdfasdf", + array(new Hash160(defaultAccountScriptHash()), new Hash160(defaultAccountScriptHash()), + new Hash160(defaultAccountScriptHash()), + new Hash160(defaultAccountScriptHash()), + new Hash160(defaultAccountScriptHash()), + new Hash160(defaultAccountScriptHash()) + ), CallFlags.ALL.getValue() + ), + array(NeoToken.SCRIPT_HASH, + "jjsldfjklkasjdfkljalkjasdf;lkjasddfd" + + "lfjkasdflkjasdfssldfjklkasjdfkljasasdfasfasdfasdf", + array(new Hash160(defaultAccountScriptHash()), new Hash160(defaultAccountScriptHash()), + new Hash160(defaultAccountScriptHash()), + new Hash160(defaultAccountScriptHash()), + new Hash160(defaultAccountScriptHash()), + new Hash160(defaultAccountScriptHash()), + new Hash160(defaultAccountScriptHash()), + new Hash160(defaultAccountScriptHash()) + ), CallFlags.ALL.getValue() + ), + array(NeoToken.SCRIPT_HASH, + "jjsldfjklkasjdfkljalkjasdf;lkjasddfd" + + "lfjkasdflkjasdfssldfjklkasjdfkljasasdfasfasdfasdf", + array(new Hash160(defaultAccountScriptHash()), new Hash160(defaultAccountScriptHash()), + new Hash160(defaultAccountScriptHash()), + new Hash160(defaultAccountScriptHash()), + new Hash160(defaultAccountScriptHash()), + new Hash160(defaultAccountScriptHash()), + new Hash160(defaultAccountScriptHash()), + new Hash160(defaultAccountScriptHash()), + new Hash160(defaultAccountScriptHash()), + "hlksajdfiojasdofjasodjflkjasdkfjlaijsdfiojpasodm" + + "hlksajdfiojasdofjasodjflkjasdkfjlaijsdfi" + + "hlksajdfiojasdofjasodjflkjasdkfjlaijsdfi" + + "hlksajdfiojasdofjasodjflkjasdkfjlaijsdfi" + + "hlksajdfiojasdofjasodjflkjasdkfjlaijsdfi" + + "hlksajdfiojasdofjasodjflkjasdkfjlaijsdfi" + ), + CallFlags.ALL.getValue() + ) + ), string(offchainUri), integer(-1) + ).signers( + AccountSigner.calledByEntry(bob)).sign().send().getSendRawTransaction().getHash(); Await.waitUntilTransactionIsExecuted(tx, neow3j); - int id = neow3j.getApplicationLog(tx).send().getApplicationLog().getExecutions().get(0) - .getStack().get(0).getInteger().intValue(); + int id = neow3j.getApplicationLog(tx).send().getApplicationLog().getExecutions().get(0).getStack().get( + 0).getInteger().intValue(); - NeoInvokeFunction r = gov.callInvokeFunction(GET_PROPOSAL, asList(integer(id))); + NeoInvokeFunction r = gov.callInvokeFunction(GET_PROPOSAL, Collections.singletonList(integer(id))); ProposalStruct p = new ProposalStruct(r.getInvocationResult().getStack().get(0).getList()); assertThat(p.id, is(id)); assertThat(p.proposer, is(bob.getScriptHash())); @@ -574,11 +586,11 @@ public void create_proposal_with_large_intents_and_offchainUri() throws Throwabl public void succeed_creating_exact_same_proposal_that_already_exists() throws IOException { // Recreate default proposal InvocationResult result = gov.invokeFunction(CREATE, hash160(alice.getScriptHash()), - array(array(NeoToken.SCRIPT_HASH, "balanceOf", array(new Hash160(defaultAccountScriptHash())), - CallFlags.ALL.getValue())), - string("default_proposal"), - integer(-1)).signers(AccountSigner.calledByEntry(alice)) - .callInvokeScript().getInvocationResult(); + array(array(NeoToken.SCRIPT_HASH, "balanceOf", array(new Hash160(defaultAccountScriptHash())), + CallFlags.ALL.getValue() + )), string("default_proposal"), integer(-1) + ).signers( + AccountSigner.calledByEntry(alice)).callInvokeScript().getInvocationResult(); assertThat(result.getStack().get(0).getInteger().intValue(), is(not(defaultProposalId))); assertThat(result.getStack().get(0).getInteger().intValue(), is(greaterThan(0))); } @@ -586,8 +598,10 @@ public void succeed_creating_exact_same_proposal_that_already_exists() throws IO @Test @Order(0) public void get_proposals() throws Throwable { - ContractParameter intents = array(array(NeoToken.SCRIPT_HASH, "balanceOf", - array(new Hash160(defaultAccountScriptHash())), CallFlags.ALL.getValue())); + ContractParameter intents = array( + array(NeoToken.SCRIPT_HASH, "balanceOf", array(new Hash160(defaultAccountScriptHash())), + CallFlags.ALL.getValue() + )); TestHelper.createAndEndorseProposal(gov, neow3j, bob, alice, intents, "some_proposal"); ProposalPaginatedStruct page = gov.getProposals(0, 1); @@ -600,187 +614,197 @@ public void get_proposals() throws Throwable { proposal = gov.getProposals(1, 1).items.get(0); assertThat(proposal.id, is(greaterThanOrEqualTo(1))); - String exception = gov.callInvokeFunction("getProposals", asList(integer(-1), integer(1))) - .getInvocationResult().getException(); + String exception = gov.callInvokeFunction("getProposals", + asList(integer(-1), integer(1)) + ).getInvocationResult().getException(); assertThat(exception, containsString("Page number was negative")); - exception = gov.callInvokeFunction("getProposals", asList(integer(0), integer(0))) - .getInvocationResult().getException(); + exception = gov.callInvokeFunction("getProposals", + asList(integer(0), integer(0)) + ).getInvocationResult().getException(); assertThat(exception, containsString("Page number was negative or zero")); } @Test @Order(0) public void get_number_of_proposals() throws IOException { - int result = gov.callInvokeFunction(GET_PROPOSAL_COUNT) - .getInvocationResult().getStack().get(0).getInteger().intValue(); + int result = gov.callInvokeFunction(GET_PROPOSAL_COUNT).getInvocationResult().getStack().get( + 0).getInteger().intValue(); // At least one because of the default proposal from the setup method. assertThat(result, is(greaterThanOrEqualTo(1))); } @Test @Order(0) - public void fail_pausing_contract_without_members_account() throws Throwable { - Hash256 tx = gov.invokeFunction(PAUSE).signers(AccountSigner.calledByEntry(alice)).sign().send() - .getSendRawTransaction().getHash(); - assertAborted(tx, "Not authorized", neow3j); + public void fail_pausing_contract_without_members_account() { + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.invokeFunction(PAUSE).signers(AccountSigner.calledByEntry(alice)).sign() + ); + assertTrue(e.getMessage().endsWith("Not authorized")); } @Test @Order(0) - public void fail_unpausing_contract_without_members_account() throws Throwable { - Hash256 tx = gov.invokeFunction(UNPAUSE).signers(AccountSigner.calledByEntry(alice)).sign().send() - .getSendRawTransaction().getHash(); - assertAborted(tx, "Not authorized", neow3j); + public void fail_unpausing_contract_without_members_account() { + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.invokeFunction(UNPAUSE).signers(AccountSigner.calledByEntry(alice)).sign() + ); + assertTrue(e.getMessage().endsWith("Not authorized")); } // Is executed as the first test of series of test that require the contract to be paused. @Order(10) @Test public void succeed_pausing_contract() throws Throwable { - assertFalse(gov.callInvokeFunction(IS_PAUSED).getInvocationResult() - .getStack().get(0).getBoolean()); + assertFalse(gov.callInvokeFunction(IS_PAUSED).getInvocationResult().getStack().get(0).getBoolean()); Account membersAccount = createMultiSigAccount(1, alice, charlie); - Transaction tx = gov.invokeFunction(PAUSE) - .signers(AccountSigner.none(bob), AccountSigner.calledByEntry(membersAccount)) - .getUnsignedTransaction(); - Hash256 txHash = tx - .addWitness(Witness.create(tx.getHashData(), bob.getECKeyPair())) - .addMultiSigWitness(membersAccount.getVerificationScript(), alice) - .send().getSendRawTransaction().getHash(); + Transaction tx = gov.invokeFunction(PAUSE).signers(AccountSigner.none(bob), + AccountSigner.calledByEntry(membersAccount) + ).getUnsignedTransaction(); + Hash256 txHash = tx.addWitness(Witness.create(tx.getHashData(), bob.getECKeyPair())).addMultiSigWitness( + membersAccount.getVerificationScript(), alice).send().getSendRawTransaction().getHash(); Await.waitUntilTransactionIsExecuted(txHash, neow3j); - assertTrue(gov.callInvokeFunction(IS_PAUSED).getInvocationResult() - .getStack().get(0).getBoolean()); + assertTrue(gov.callInvokeFunction(IS_PAUSED).getInvocationResult().getStack().get(0).getBoolean()); } @Test @Order(0) public void fail_execute_update_contract_directly() throws Throwable { - File nefFile = new File(this.getClass().getClassLoader() - .getResource(TESTCONTRACT_NEF_FILE.toString()).toURI()); + File nefFile = new File(this.getClass().getClassLoader().getResource(TESTCONTRACT_NEF_FILE.toString()).toURI()); NefFile nef = NefFile.readFromFile(nefFile); - File manifestFile = new File(this.getClass().getClassLoader() - .getResource(TESTCONTRACT_MANIFEST_FILE.toString()).toURI()); - ContractManifest manifest = getObjectMapper() - .readValue(manifestFile, ContractManifest.class); + File manifestFile = new File( + this.getClass().getClassLoader().getResource(TESTCONTRACT_MANIFEST_FILE.toString()).toURI()); + ContractManifest manifest = getObjectMapper().readValue(manifestFile, ContractManifest.class); String manifestString = getObjectMapper().writeValueAsString(manifest); - Hash256 tx = gov.updateContract(nef.toArray(), manifestString, null).signers(AccountSigner.calledByEntry(alice)) - .sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Method only callable by the contract itself", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.updateContract(nef.toArray(), manifestString, null).signers( + AccountSigner.calledByEntry(alice)).sign() + ); + assertTrue(e.getMessage().endsWith("Method only callable by the contract itself")); } @Test @Order(0) - public void fail_create_proposal_calling_contract_management() throws Throwable { + public void fail_create_proposal_calling_contract_management() { IntentParam intent1 = IntentParam.addMemberProposal(gov.getScriptHash(), alice.getECKeyPair().getPublicKey()); IntentParam intent2 = new IntentParam(ContractManagement.SCRIPT_HASH, "destroy"); - Hash256 tx = gov.createProposal(alice.getScriptHash(), "fail_create_proposal_calling_contract_management", -1, - intent1, intent2).signers(AccountSigner.calledByEntry(alice)).sign().send() - .getSendRawTransaction().getHash(); - assertAborted(tx, "Invalid intents", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.createProposal(alice.getScriptHash(), "fail_create_proposal_calling_contract_management", -1, + intent1, intent2 + ).signers(AccountSigner.calledByEntry(alice)).sign() + ); + assertTrue(e.getMessage().endsWith("Invalid intents")); } @Order(11) @Test - public void fail_change_param_on_paused_contract() throws Throwable { - Hash256 tx = gov.invokeFunction(CHANGE_PARAM, string(MIN_ACCEPTANCE_RATE_KEY), integer(50)) - .signers(AccountSigner.calledByEntry(alice)).sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Contract is paused", neow3j); + public void fail_change_param_on_paused_contract() { + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.invokeFunction(CHANGE_PARAM, string(MIN_ACCEPTANCE_RATE_KEY), integer(50)).signers( + AccountSigner.calledByEntry(alice)).sign() + ); + assertTrue(e.getMessage().endsWith("Contract is paused")); } @Order(12) @Test - public void fail_add_member_on_paused_contract() throws Throwable { - Hash256 tx = gov.invokeFunction(ADD_MEMBER, publicKey(bob.getECKeyPair().getPublicKey().getEncoded(true))) - .signers(AccountSigner.calledByEntry(bob)).sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Contract is paused", neow3j); + public void fail_add_member_on_paused_contract() { + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.invokeFunction(ADD_MEMBER, + publicKey(bob.getECKeyPair().getPublicKey().getEncoded(true)) + ).signers( + AccountSigner.calledByEntry(bob)).sign() + ); + assertTrue(e.getMessage().endsWith("Contract is paused")); } @Order(13) @Test - public void fail_remove_member_on_paused_contract() throws Throwable { - Hash256 tx = gov.invokeFunction(REMOVE_MEMBER, publicKey(bob.getECKeyPair().getPublicKey().getEncoded(true))) - .signers(AccountSigner.calledByEntry(bob)).sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Contract is paused", neow3j); + public void fail_remove_member_on_paused_contract() { + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.invokeFunction(REMOVE_MEMBER, + publicKey(bob.getECKeyPair().getPublicKey().getEncoded(true)) + ).signers( + AccountSigner.calledByEntry(bob)).sign() + ); + assertTrue(e.getMessage().endsWith("Contract is paused")); } @Order(14) @Test - public void fail_execute_proposal_on_paused_contract() throws Throwable { - Hash256 tx = gov.execute(defaultProposalId).signers(AccountSigner.calledByEntry(bob)).sign().send() - .getSendRawTransaction().getHash(); - assertAborted(tx, "Contract is paused", neow3j); + public void fail_execute_proposal_on_paused_contract() { + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.execute(defaultProposalId).signers(AccountSigner.calledByEntry(bob)).sign() + ); + assertTrue(e.getMessage().endsWith("Contract is paused")); } @Order(15) @Test - public void fail_vote_on_proposal_on_paused_contract() throws Throwable { - Hash256 tx = gov.vote(defaultProposalId, 1, alice.getScriptHash()).signers(AccountSigner.calledByEntry(bob)) - .sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Contract is paused", neow3j); + public void fail_vote_on_proposal_on_paused_contract() { + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.vote(defaultProposalId, 1, alice.getScriptHash()).signers( + AccountSigner.calledByEntry(bob)).sign() + ); + assertTrue(e.getMessage().endsWith("Contract is paused")); } @Order(16) @Test - public void fail_endorse_proposal_on_paused_contract() throws Throwable { - Hash256 tx = gov.endorseProposal(defaultProposalId, alice.getScriptHash()) - .signers(AccountSigner.calledByEntry(bob)).sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Contract is paused", neow3j); + public void fail_endorse_proposal_on_paused_contract() { + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.endorseProposal(defaultProposalId, alice.getScriptHash()).signers( + AccountSigner.calledByEntry(bob)).sign() + ); + assertTrue(e.getMessage().endsWith("Contract is paused")); } @Order(17) @Test - public void fail_update_contract_on_paused_contract() throws Throwable { - Hash256 tx = gov.updateContract(new byte[]{0x01, 0x02, 0x03}, "the manifest", null) - .signers(AccountSigner.calledByEntry(bob)).sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Contract is paused", neow3j); + public void fail_update_contract_on_paused_contract() { + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.updateContract(new byte[]{0x01, 0x02, 0x03}, "the manifest", null).signers( + AccountSigner.calledByEntry(bob)).sign() + ); + assertTrue(e.getMessage().endsWith("Contract is paused")); } // Must be executed after all tests orderd after the test that pauses the contract. @Order(19) @Test public void succeed_unpausing_contract() throws Throwable { - assertTrue(gov.callInvokeFunction(IS_PAUSED).getInvocationResult() - .getStack().get(0).getBoolean()); + assertTrue(gov.callInvokeFunction(IS_PAUSED).getInvocationResult().getStack().get(0).getBoolean()); Account membersAccount = createMultiSigAccount(1, alice, charlie); - Transaction tx = gov.invokeFunction(UNPAUSE) - .signers(AccountSigner.none(bob), AccountSigner.calledByEntry(membersAccount)) - .getUnsignedTransaction(); - Hash256 txHash = tx - .addWitness(Witness.create(tx.getHashData(), bob.getECKeyPair())) - .addMultiSigWitness(membersAccount.getVerificationScript(), alice) - .send().getSendRawTransaction().getHash(); + Transaction tx = gov.invokeFunction(UNPAUSE).signers(AccountSigner.none(bob), + AccountSigner.calledByEntry(membersAccount) + ).getUnsignedTransaction(); + Hash256 txHash = tx.addWitness(Witness.create(tx.getHashData(), bob.getECKeyPair())).addMultiSigWitness( + membersAccount.getVerificationScript(), alice).send().getSendRawTransaction().getHash(); Await.waitUntilTransactionIsExecuted(txHash, neow3j); - assertFalse(gov.callInvokeFunction(IS_PAUSED).getInvocationResult() - .getStack().get(0).getBoolean()); + assertFalse(gov.callInvokeFunction(IS_PAUSED).getInvocationResult().getStack().get(0).getBoolean()); } @Test @Order(20) public void execute_proposal_with_update_contract() throws Throwable { - File nefFile = new File(this.getClass().getClassLoader() - .getResource(TESTCONTRACT_NEF_FILE.toString()).toURI()); + File nefFile = new File(this.getClass().getClassLoader().getResource(TESTCONTRACT_NEF_FILE.toString()).toURI()); NefFile nef = NefFile.readFromFile(nefFile); - File manifestFile = new File(this.getClass().getClassLoader() - .getResource(TESTCONTRACT_MANIFEST_FILE.toString()).toURI()); - ContractManifest manifest = getObjectMapper() - .readValue(manifestFile, ContractManifest.class); + File manifestFile = new File( + this.getClass().getClassLoader().getResource(TESTCONTRACT_MANIFEST_FILE.toString()).toURI()); + ContractManifest manifest = getObjectMapper().readValue(manifestFile, ContractManifest.class); byte[] manifestBytes = getObjectMapper().writeValueAsBytes(manifest); ContractParameter data = string("some data"); ContractParameter intents = array( - array( - gov.getScriptHash(), - UPDATE_CONTRACT, - array(nef.toArray(), manifestBytes, data), + array(gov.getScriptHash(), UPDATE_CONTRACT, array(nef.toArray(), manifestBytes, data), CallFlags.ALL.getValue() )); String offchainUri = "execute_proposal_with_update_contract"; @@ -795,13 +819,12 @@ public void execute_proposal_with_update_contract() throws Throwable { // 3. Skip till after vote and queued phase, then execute. ext.fastForwardOneBlock(PHASE_LENGTH + PHASE_LENGTH); - Hash256 tx = gov.invokeFunction(EXECUTE, integer(id)) - .signers(AccountSigner.calledByEntry(charlie)) - .sign().send().getSendRawTransaction().getHash(); + Hash256 tx = gov.invokeFunction(EXECUTE, integer(id)).signers( + AccountSigner.calledByEntry(charlie)).sign().send().getSendRawTransaction().getHash(); Await.waitUntilTransactionIsExecuted(tx, neow3j); - NeoApplicationLog.Execution execution = neow3j.getApplicationLog(tx).send() - .getApplicationLog().getExecutions().get(0); + NeoApplicationLog.Execution execution = neow3j.getApplicationLog( + tx).send().getApplicationLog().getExecutions().get(0); Notification n = execution.getNotifications().get(0); assertThat(n.getEventName(), is("UpdatingContract")); assertThat(n.getContract(), is(gov.getScriptHash())); diff --git a/src/test/java/com/axlabs/neo/grantshares/GrantSharesTreasuryTest.java b/src/test/java/com/axlabs/neo/grantshares/GrantSharesTreasuryTest.java index d9cf9ae..acef2f1 100644 --- a/src/test/java/com/axlabs/neo/grantshares/GrantSharesTreasuryTest.java +++ b/src/test/java/com/axlabs/neo/grantshares/GrantSharesTreasuryTest.java @@ -21,6 +21,7 @@ import io.neow3j.transaction.AccountSigner; import io.neow3j.transaction.Transaction; import io.neow3j.transaction.Witness; +import io.neow3j.transaction.exceptions.TransactionConfigurationException; import io.neow3j.types.CallFlags; import io.neow3j.types.ContractParameter; import io.neow3j.types.Hash160; @@ -40,22 +41,22 @@ import java.math.BigInteger; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; -import static com.axlabs.neo.grantshares.util.TestHelper.ALICE; -import static com.axlabs.neo.grantshares.util.TestHelper.BOB; -import static com.axlabs.neo.grantshares.util.TestHelper.CHARLIE; -import static com.axlabs.neo.grantshares.util.TestHelper.DENISE; -import static com.axlabs.neo.grantshares.util.TestHelper.EVE; -import static com.axlabs.neo.grantshares.util.TestHelper.EXECUTE; -import static com.axlabs.neo.grantshares.util.TestHelper.IS_PAUSED; -import static com.axlabs.neo.grantshares.util.TestHelper.PAUSE; -import static com.axlabs.neo.grantshares.util.TestHelper.PHASE_LENGTH; -import static com.axlabs.neo.grantshares.util.TestHelper.UNPAUSE; -import static com.axlabs.neo.grantshares.util.TestHelper.UPDATE_CONTRACT; -import static com.axlabs.neo.grantshares.util.TestHelper.assertAborted; +import static com.axlabs.neo.grantshares.util.TestHelper.GovernanceMethods.EXECUTE; +import static com.axlabs.neo.grantshares.util.TestHelper.GovernanceMethods.IS_PAUSED; +import static com.axlabs.neo.grantshares.util.TestHelper.GovernanceMethods.PAUSE; +import static com.axlabs.neo.grantshares.util.TestHelper.GovernanceMethods.UNPAUSE; +import static com.axlabs.neo.grantshares.util.TestHelper.GovernanceMethods.UPDATE_CONTRACT; +import static com.axlabs.neo.grantshares.util.TestHelper.Members.ALICE; +import static com.axlabs.neo.grantshares.util.TestHelper.Members.BOB; +import static com.axlabs.neo.grantshares.util.TestHelper.Members.CHARLIE; +import static com.axlabs.neo.grantshares.util.TestHelper.Members.DENISE; +import static com.axlabs.neo.grantshares.util.TestHelper.Members.EVE; +import static com.axlabs.neo.grantshares.util.TestHelper.ParameterValues.PHASE_LENGTH; import static com.axlabs.neo.grantshares.util.TestHelper.createAndEndorseProposal; import static com.axlabs.neo.grantshares.util.TestHelper.createMultiSigAccount; import static com.axlabs.neo.grantshares.util.TestHelper.prepareDeployParameter; @@ -74,6 +75,7 @@ import static org.hamcrest.Matchers.containsString; import static org.hamcrest.core.Is.is; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @ContractTest(contracts = {GrantSharesGov.class, GrantSharesTreasury.class}, @@ -134,7 +136,6 @@ public static DeployConfiguration deployConfigTreasury(DeployContext ctx) throws @BeforeAll public static void setUp() throws Throwable { neow3j = ext.getNeow3j(); - neow3j.allowTransmissionOnFault(); // contracts gov = new GrantSharesGovContract( @@ -205,34 +206,42 @@ public void succeed_voting_on_committee_member() throws Throwable { @Test @Order(0) - public void fail_calling_add_whitelisted_token_directly() throws Throwable { - Hash256 tx = treasury.addWhitelistedToken(GasToken.SCRIPT_HASH, 1).signers(AccountSigner.calledByEntry(alice)) - .sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Not authorised", neow3j); + public void fail_calling_add_whitelisted_token_directly() { + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> treasury.addWhitelistedToken(GasToken.SCRIPT_HASH, 1).signers(AccountSigner.calledByEntry(alice)) + .sign() + ); + assertTrue(e.getMessage().endsWith("Not authorised")); } @Test @Order(0) - public void fail_calling_remove_whitelisted_token_directly() throws Throwable { - Hash256 tx = treasury.removeWhitelistedToken(GasToken.SCRIPT_HASH).signers(AccountSigner.calledByEntry(alice)) - .sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Not authorised", neow3j); + public void fail_calling_remove_whitelisted_token_directly() { + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> treasury.removeWhitelistedToken(GasToken.SCRIPT_HASH).signers(AccountSigner.calledByEntry(alice)) + .sign() + ); + assertTrue(e.getMessage().endsWith("Not authorised")); } @Test @Order(0) - public void fail_calling_add_funder_directly() throws Throwable { - Hash256 tx = treasury.addFunder(alice.getScriptHash(), alice.getECKeyPair().getPublicKey()) - .signers(AccountSigner.calledByEntry(alice)).sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Not authorised", neow3j); + public void fail_calling_add_funder_directly() { + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> treasury.addFunder(alice.getScriptHash(), alice.getECKeyPair().getPublicKey()) + .signers(AccountSigner.calledByEntry(alice)).sign() + ); + assertTrue(e.getMessage().endsWith("Not authorised")); } @Test @Order(0) - public void fail_calling_remove_funder_directly() throws Throwable { - Hash256 tx = treasury.removeFunder(charlie.getScriptHash()).signers(AccountSigner.calledByEntry(alice)) - .sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Not authorised", neow3j); + public void fail_calling_remove_funder_directly() { + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> treasury.removeFunder(charlie.getScriptHash()).signers(AccountSigner.calledByEntry(alice)) + .sign() + ); + assertTrue(e.getMessage().endsWith("Not authorised")); } @Test @@ -259,9 +268,11 @@ public void fail_execute_update_contract_directly() throws Throwable { ContractParameter data = string("update contract"); - Hash256 tx = treasury.invokeFunction(UPDATE_CONTRACT, byteArray(nef.toArray()), byteArray(manifestBytes), data) - .signers(AccountSigner.calledByEntry(alice)).sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Not authorised", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> treasury.invokeFunction(UPDATE_CONTRACT, byteArray(nef.toArray()), byteArray(manifestBytes), data) + .signers(AccountSigner.calledByEntry(alice)).sign() + ); + assertTrue(e.getMessage().endsWith("Not authorised")); } @Test @@ -269,7 +280,8 @@ public void fail_execute_update_contract_directly() throws Throwable { public void fail_release_tokens_with_non_whitelisted_token() throws Throwable { final Hash160 someToken = new Hash160("1a1512528147558851b39c2cd8aa47da7418aba1"); ContractParameter intent = IntentParam.releaseTokenProposal(treasury.getScriptHash(), someToken, - alice.getScriptHash(), BigInteger.TEN); + alice.getScriptHash(), BigInteger.TEN + ); String offchainUri = "fail_release_tokens_with_non_whitelisted_token"; // 1. Create and endorse proposal @@ -281,16 +293,18 @@ public void fail_release_tokens_with_non_whitelisted_token() throws Throwable { // 3. Skip till after vote and queued phase, then execute. ext.fastForwardOneBlock(PHASE_LENGTH + PHASE_LENGTH); - Hash256 tx = gov.execute(id).signers(AccountSigner.calledByEntry(bob)).sign().send() - .getSendRawTransaction().getHash(); - assertAborted(tx, "Token not whitelisted", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.execute(id).signers(AccountSigner.calledByEntry(bob)).sign() + ); + assertTrue(e.getMessage().endsWith("Token not whitelisted")); } @Test @Order(0) public void fail_release_tokens_with_to_high_amount() throws Throwable { ContractParameter intent = IntentParam.releaseTokenProposal(treasury.getScriptHash(), GasToken.SCRIPT_HASH, - alice.getScriptHash(), GAS_MAX_AMOUNT.add(BigInteger.ONE)); + alice.getScriptHash(), GAS_MAX_AMOUNT.add(BigInteger.ONE) + ); String offchainUri = "fail_release_tokens_with_to_high_amount"; // 1. Create and endorse proposal @@ -303,24 +317,29 @@ public void fail_release_tokens_with_to_high_amount() throws Throwable { // 3. Skip till after vote and queued phase, then execute. ext.fastForwardOneBlock(PHASE_LENGTH + PHASE_LENGTH); - Hash256 tx = gov.execute(id).signers(AccountSigner.calledByEntry(bob)).sign().send() - .getSendRawTransaction().getHash(); - assertAborted(tx, "Above token's max funding amount", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.execute(id).signers(AccountSigner.calledByEntry(bob)).sign() + ); + assertTrue(e.getMessage().endsWith("Above token's max funding amount")); } @Test @Order(0) - public void fail_calling_release_tokens_directly() throws Throwable { - Hash256 tx = treasury.releaseTokens(GasToken.SCRIPT_HASH, alice.getScriptHash(), BigInteger.ONE) - .signers(AccountSigner.calledByEntry(bob)).sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Not authorised", neow3j); + public void fail_calling_release_tokens_directly() { + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> treasury.releaseTokens(GasToken.SCRIPT_HASH, alice.getScriptHash(), BigInteger.ONE) + .signers(AccountSigner.calledByEntry(bob)).sign() + ); + assertTrue(e.getMessage().endsWith("Not authorised")); } @Test @Order(0) public void fail_adding_invalid_funder() throws Throwable { ContractParameter intent = new IntentParam(treasury.getScriptHash(), "addFunder", - byteArray("3ff68d232a60f23a5805b8c40f7e61747f"), array(asList(alice.getECKeyPair().getPublicKey()))); + byteArray("3ff68d232a60f23a5805b8c40f7e61747f"), + array(Collections.singletonList(alice.getECKeyPair().getPublicKey())) + ); String offchainUri = "fail_adding_invalid_funder"; // 1. Create and endorse proposal @@ -332,9 +351,10 @@ public void fail_adding_invalid_funder() throws Throwable { // 3. Skip till after vote and queued phase, then execute. ext.fastForwardOneBlock(PHASE_LENGTH + PHASE_LENGTH); - Hash256 tx = gov.execute(id).signers(AccountSigner.calledByEntry(alice)).sign().send() - .getSendRawTransaction().getHash(); - assertAborted(tx, "Invalid funder hash", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.execute(id).signers(AccountSigner.calledByEntry(alice)).sign() + ); + assertTrue(e.getMessage().endsWith("Invalid funder hash")); } @Test @@ -352,9 +372,10 @@ public void fail_adding_funder_with_no_public_keys() throws Throwable { // 3. Skip till after vote and queued phase, then execute. ext.fastForwardOneBlock(PHASE_LENGTH + PHASE_LENGTH); - Hash256 tx = gov.execute(id).signers(AccountSigner.calledByEntry(alice)).sign().send() - .getSendRawTransaction().getHash(); - assertAborted(tx, "List of public keys is empty", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.execute(id).signers(AccountSigner.calledByEntry(alice)).sign() + ); + assertTrue(e.getMessage().endsWith("List of public keys is empty")); } @Test @@ -362,7 +383,9 @@ public void fail_adding_funder_with_no_public_keys() throws Throwable { public void fail_adding_funder_with_invalid_public_key() throws Throwable { IntentParam intent = new IntentParam(treasury.getScriptHash(), "addFunder", hash160(alice.getScriptHash()), array(publicKey(alice.getECKeyPair().getPublicKey()), - byteArray("03dab84c1243ec01ab2500e1a8c7a1546a26d734628180b0cf64e72bf776"))); + byteArray("03dab84c1243ec01ab2500e1a8c7a1546a26d734628180b0cf64e72bf776") + ) + ); String offchainUri = "fail_adding_funder_with_invalid_public_key"; // 1. Create and endorse proposal @@ -374,9 +397,10 @@ public void fail_adding_funder_with_invalid_public_key() throws Throwable { // 3. Skip till after vote and queued phase, then execute. ext.fastForwardOneBlock(PHASE_LENGTH + PHASE_LENGTH); - Hash256 tx = gov.execute(id).signers(AccountSigner.calledByEntry(alice)).sign().send() - .getSendRawTransaction().getHash(); - assertAborted(tx, "Invalid public key", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.execute(id).signers(AccountSigner.calledByEntry(alice)).sign() + ); + assertTrue(e.getMessage().endsWith("Invalid public key")); } @Test @@ -398,19 +422,22 @@ public void fail_setting_funders_multisig_threshold_ratio_with_invalid_value() t // 3. Skip till after vote and queued phase, then execute. ext.fastForwardOneBlock(PHASE_LENGTH + PHASE_LENGTH); - Hash256 tx = gov.execute(id1).signers(AccountSigner.calledByEntry(alice)).sign().send() - .getSendRawTransaction().getHash(); - assertAborted(tx, "Invalid threshold ratio", neow3j); - tx = gov.execute(id2).signers(AccountSigner.calledByEntry(alice)).sign().send() - .getSendRawTransaction().getHash(); - assertAborted(tx, "Invalid threshold ratio", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.execute(id1).signers(AccountSigner.calledByEntry(alice)).sign() + ); + assertTrue(e.getMessage().endsWith("Invalid threshold ratio")); + e = assertThrows(TransactionConfigurationException.class, + () -> gov.execute(id2).signers(AccountSigner.calledByEntry(alice)).sign() + ); + assertTrue(e.getMessage().endsWith("Invalid threshold ratio")); } @Test @Order(0) public void fail_adding_whitelisted_token_with_invalid_token() throws Throwable { ContractParameter intent = new IntentParam(treasury.getScriptHash(), "addWhitelistedToken", - byteArray("3ff68d232a60f23a5805b8c40f7e61747f"), integer(100)); + byteArray("3ff68d232a60f23a5805b8c40f7e61747f"), integer(100) + ); String offchainUri = "fail_adding_whitelisted_token_with_invalid_token"; // 1. Create and endorse proposal @@ -422,16 +449,18 @@ public void fail_adding_whitelisted_token_with_invalid_token() throws Throwable // 3. Skip till after vote and queued phase, then execute. ext.fastForwardOneBlock(PHASE_LENGTH + PHASE_LENGTH); - Hash256 tx = gov.execute(id).signers(AccountSigner.calledByEntry(alice)).sign().send() - .getSendRawTransaction().getHash(); - assertAborted(tx, "Invalid token hash", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.execute(id).signers(AccountSigner.calledByEntry(alice)).sign() + ); + assertTrue(e.getMessage().endsWith("Invalid token hash")); } @Test @Order(0) public void fail_adding_whitelisted_token_with_invalid_max_funding_amount() throws Throwable { ContractParameter intent = IntentParam.addWhitelistedTokenProposal(treasury.getScriptHash(), - NeoToken.SCRIPT_HASH, BigInteger.ONE.negate()); + NeoToken.SCRIPT_HASH, BigInteger.ONE.negate() + ); String offchainUri = "fail_adding_whitelisted_token_with_invalid_max_funding_amount"; // 1. Create and endorse proposal @@ -443,16 +472,18 @@ public void fail_adding_whitelisted_token_with_invalid_max_funding_amount() thro // 3. Skip till after vote and queued phase, then execute. ext.fastForwardOneBlock(PHASE_LENGTH + PHASE_LENGTH); - Hash256 tx = gov.execute(id).signers(AccountSigner.calledByEntry(alice)).sign().send() - .getSendRawTransaction().getHash(); - assertAborted(tx, "Invalid max funding amount", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.execute(id).signers(AccountSigner.calledByEntry(alice)).sign() + ); + assertTrue(e.getMessage().endsWith("Invalid max funding amount")); } @Test @Order(1) public void execute_proposal_with_add_single_sig_funder() throws Throwable { IntentParam intent = IntentParam.addFunderProposal(treasury.getScriptHash(), alice.getScriptHash(), - alice.getECKeyPair().getPublicKey()); + alice.getECKeyPair().getPublicKey() + ); String offchainUri = "execute_proposal_with_add_single_sig_funder"; // 1. Create and endorse proposal @@ -486,7 +517,8 @@ public void execute_proposal_with_add_multi_sig_funder() throws Throwable { Account multiSigFunder = Account.createMultiSigAccount( asList(denise.getECKeyPair().getPublicKey(), eve.getECKeyPair().getPublicKey()), 1); IntentParam intent = IntentParam.addFunderProposal(treasury.getScriptHash(), multiSigFunder.getScriptHash(), - denise.getECKeyPair().getPublicKey(), eve.getECKeyPair().getPublicKey()); + denise.getECKeyPair().getPublicKey(), eve.getECKeyPair().getPublicKey() + ); String offchainUri = "execute_proposal_with_add_multi_sig_funder"; // 1. Create and endorse proposal @@ -518,7 +550,8 @@ public void execute_proposal_with_add_multi_sig_funder() throws Throwable { @Order(3) public void fail_adding_already_added_funder() throws Throwable { ContractParameter intent = IntentParam.addFunderProposal(treasury.getScriptHash(), alice.getScriptHash(), - alice.getECKeyPair().getPublicKey()); + alice.getECKeyPair().getPublicKey() + ); String offchainUri = "fail_adding_already_added_funder"; // 1. Create and endorse proposal @@ -530,9 +563,10 @@ public void fail_adding_already_added_funder() throws Throwable { // 3. Skip till after vote and queued phase, then execute. ext.fastForwardOneBlock(PHASE_LENGTH + PHASE_LENGTH); - Hash256 tx = gov.execute(id).signers(AccountSigner.calledByEntry(alice)).sign().send() - .getSendRawTransaction().getHash(); - assertAborted(tx, "Already a funder", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.execute(id).signers(AccountSigner.calledByEntry(alice)).sign() + ); + assertTrue(e.getMessage().endsWith("Already a funder")); } @Test @@ -579,9 +613,10 @@ public void fail_removing_nonexistant_funder() throws Throwable { // 3. Skip till after vote and queued phase, then execute. ext.fastForwardOneBlock(PHASE_LENGTH + PHASE_LENGTH); - Hash256 tx = gov.execute(id).signers(AccountSigner.calledByEntry(alice)).sign().send() - .getSendRawTransaction().getHash(); - assertAborted(tx, "Not a funder", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.execute(id).signers(AccountSigner.calledByEntry(alice)).sign() + ); + assertTrue(e.getMessage().endsWith("Not a funder")); } @Test @@ -626,7 +661,8 @@ public void fail_funding_treasury_with_non_whitelisted_token() throws Throwable @Order(12) public void execute_proposal_with_add_whitelisted_token() throws Throwable { ContractParameter intent = IntentParam.addWhitelistedTokenProposal(treasury.getScriptHash(), - NeoToken.SCRIPT_HASH, NEO_MAX_AMOUNT_CHANGED); + NeoToken.SCRIPT_HASH, NEO_MAX_AMOUNT_CHANGED + ); String offchainUri = "execute_proposal_with_add_whitelisted_token"; // 1. Create and endorse proposal @@ -660,7 +696,8 @@ public void execute_proposal_with_change_whitelisted_token_max_amount() throws T assertThat(tokens.get(NeoToken.SCRIPT_HASH), is(NEO_MAX_AMOUNT_CHANGED)); ContractParameter intent = IntentParam.addWhitelistedTokenProposal(treasury.getScriptHash(), - NeoToken.SCRIPT_HASH, NEO_MAX_AMOUNT); + NeoToken.SCRIPT_HASH, NEO_MAX_AMOUNT + ); String offchainUri = "execute_proposal_with_change_whitelisted_token_max_amount"; // 1. Create and endorse proposal @@ -705,7 +742,8 @@ public void funding_treasury_with_whitelisted_token_and_funder() throws Throwabl assertThat(n.getContract(), is(GasToken.SCRIPT_HASH)); assertThat(n.getState().getList().get(0).getAddress(), is(bob.getAddress())); assertThat(n.getState().getList().get(1).getAddress(), - is(treasury.getScriptHash().toAddress())); + is(treasury.getScriptHash().toAddress()) + ); assertThat(n.getState().getList().get(2).getInteger(), is(BigInteger.ONE)); assertThat(gas.getBalanceOf(treasury.getScriptHash()).intValue(), is(initialValue + 1)); @@ -717,7 +755,8 @@ public void execute_proposal_with_release_tokens() throws Throwable { Account acc = Account.create(); final BigInteger fundingAmount = BigInteger.TEN; ContractParameter intent = IntentParam.releaseTokenProposal(treasury.getScriptHash(), GasToken.SCRIPT_HASH, - acc.getScriptHash(), fundingAmount); + acc.getScriptHash(), fundingAmount + ); String offchainUri = "execute_proposal_with_release_tokens"; // 1. Create and endorse proposal @@ -764,58 +803,70 @@ public void succeed_pausing_contract() throws Throwable { @Order(21) @Test - public void fail_add_funder_on_paused_contract() throws Throwable { - Hash256 tx = treasury.addFunder(alice.getScriptHash(), alice.getECKeyPair().getPublicKey()) - .signers(AccountSigner.calledByEntry(alice)).sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Contract is paused", neow3j); + public void fail_add_funder_on_paused_contract() { + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> treasury.addFunder(alice.getScriptHash(), alice.getECKeyPair().getPublicKey()) + .signers(AccountSigner.calledByEntry(alice)).sign() + ); + assertTrue(e.getMessage().endsWith("Contract is paused")); } @Order(22) @Test - public void fail_remove_funder_on_paused_contract() throws Throwable { - Hash256 tx = treasury.removeFunder(alice.getScriptHash()).signers(AccountSigner.calledByEntry(alice)) - .sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Contract is paused", neow3j); + public void fail_remove_funder_on_paused_contract() { + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> treasury.removeFunder(alice.getScriptHash()).signers(AccountSigner.calledByEntry(alice)).sign() + ); + assertTrue(e.getMessage().endsWith("Contract is paused")); } @Order(23) @Test - public void fail_add_whitelisted_token_on_paused_contract() throws Throwable { - Hash256 tx = treasury.addWhitelistedToken(GasToken.SCRIPT_HASH, 1).signers(AccountSigner.calledByEntry(alice)) - .sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Contract is paused", neow3j); + public void fail_add_whitelisted_token_on_paused_contract() { + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> treasury.addWhitelistedToken(GasToken.SCRIPT_HASH, 1).signers(AccountSigner.calledByEntry(alice)) + .sign() + ); + assertTrue(e.getMessage().endsWith("Contract is paused")); } @Order(24) @Test - public void fail_remove_whitelisted_token_on_paused_contract() throws Throwable { - Hash256 tx = treasury.removeWhitelistedToken(GasToken.SCRIPT_HASH).signers(AccountSigner.calledByEntry(alice)) - .sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Contract is paused", neow3j); + public void fail_remove_whitelisted_token_on_paused_contract() { + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> treasury.removeWhitelistedToken(GasToken.SCRIPT_HASH).signers(AccountSigner.calledByEntry(alice)) + .sign() + ); + assertTrue(e.getMessage().endsWith("Contract is paused")); } @Order(25) @Test - public void fail_release_tokens_on_paused_contract() throws Throwable { - Hash256 tx = treasury.releaseTokens(GasToken.SCRIPT_HASH, alice.getScriptHash(), BigInteger.ONE) - .signers(AccountSigner.calledByEntry(alice)).sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Contract is paused", neow3j); + public void fail_release_tokens_on_paused_contract() { + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> treasury.releaseTokens(GasToken.SCRIPT_HASH, alice.getScriptHash(), BigInteger.ONE) + .signers(AccountSigner.calledByEntry(alice)).sign() + ); + assertTrue(e.getMessage().endsWith("Contract is paused")); } @Order(26) @Test - public void fail_vote_on_committee_member_on_paused_contract() throws Throwable { - Hash256 tx = treasury.voteCommitteeMemberWithLeastVotes().signers(AccountSigner.calledByEntry(alice)) - .sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Contract is paused", neow3j); + public void fail_vote_on_committee_member_on_paused_contract() { + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> treasury.voteCommitteeMemberWithLeastVotes().signers(AccountSigner.calledByEntry(alice)).sign() + ); + assertTrue(e.getMessage().endsWith("Contract is paused")); } @Order(27) @Test - public void fail_update_contract_on_paused_contract() throws Throwable { - Hash256 tx = treasury.updateContract(new byte[]{0x01, 0x02, 0x03}, "the manifest", null) - .signers(AccountSigner.calledByEntry(alice)).sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Contract is paused", neow3j); + public void fail_update_contract_on_paused_contract() { + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> treasury.updateContract(new byte[]{0x01, 0x02, 0x03}, "the manifest", null) + .signers(AccountSigner.calledByEntry(alice)).sign() + ); + assertTrue(e.getMessage().endsWith("Contract is paused")); } @Order(28) @@ -863,7 +914,8 @@ public void execute_proposal_with_update_contract() throws Throwable { ContractParameter data = string("update contract"); ContractParameter intents = array(array(treasury.getScriptHash(), UPDATE_CONTRACT, - array(nef.toArray(), manifestBytes, data), CallFlags.ALL.getValue())); + array(nef.toArray(), manifestBytes, data), CallFlags.ALL.getValue() + )); String offchainUri = "execute_proposal_with_update_contract"; // 1. Create and endorse proposal diff --git a/src/test/java/com/axlabs/neo/grantshares/ProposalExecutionsTest.java b/src/test/java/com/axlabs/neo/grantshares/ProposalExecutionsTest.java index 57cf3f6..c57e213 100644 --- a/src/test/java/com/axlabs/neo/grantshares/ProposalExecutionsTest.java +++ b/src/test/java/com/axlabs/neo/grantshares/ProposalExecutionsTest.java @@ -10,6 +10,7 @@ import io.neow3j.test.DeployConfig; import io.neow3j.test.DeployConfiguration; import io.neow3j.transaction.AccountSigner; +import io.neow3j.transaction.exceptions.TransactionConfigurationException; import io.neow3j.types.CallFlags; import io.neow3j.types.ContractParameter; import io.neow3j.types.Hash256; @@ -22,20 +23,19 @@ import java.math.BigInteger; -import static com.axlabs.neo.grantshares.util.TestHelper.ALICE; -import static com.axlabs.neo.grantshares.util.TestHelper.BOB; -import static com.axlabs.neo.grantshares.util.TestHelper.CHANGE_PARAM; -import static com.axlabs.neo.grantshares.util.TestHelper.CHARLIE; -import static com.axlabs.neo.grantshares.util.TestHelper.CREATE; -import static com.axlabs.neo.grantshares.util.TestHelper.DENISE; -import static com.axlabs.neo.grantshares.util.TestHelper.EVE; -import static com.axlabs.neo.grantshares.util.TestHelper.EXECUTE; -import static com.axlabs.neo.grantshares.util.TestHelper.FLORIAN; -import static com.axlabs.neo.grantshares.util.TestHelper.MIN_ACCEPTANCE_RATE_KEY; -import static com.axlabs.neo.grantshares.util.TestHelper.PHASE_LENGTH; -import static com.axlabs.neo.grantshares.util.TestHelper.PROPOSAL_EXECUTED; -import static com.axlabs.neo.grantshares.util.TestHelper.REVIEW_LENGTH_KEY; -import static com.axlabs.neo.grantshares.util.TestHelper.assertAborted; +import static com.axlabs.neo.grantshares.util.TestHelper.Events.PROPOSAL_EXECUTED; +import static com.axlabs.neo.grantshares.util.TestHelper.GovernanceMethods.CHANGE_PARAM; +import static com.axlabs.neo.grantshares.util.TestHelper.GovernanceMethods.CREATE; +import static com.axlabs.neo.grantshares.util.TestHelper.GovernanceMethods.EXECUTE; +import static com.axlabs.neo.grantshares.util.TestHelper.Members.ALICE; +import static com.axlabs.neo.grantshares.util.TestHelper.Members.BOB; +import static com.axlabs.neo.grantshares.util.TestHelper.Members.CHARLIE; +import static com.axlabs.neo.grantshares.util.TestHelper.Members.DENISE; +import static com.axlabs.neo.grantshares.util.TestHelper.Members.EVE; +import static com.axlabs.neo.grantshares.util.TestHelper.Members.FLORIAN; +import static com.axlabs.neo.grantshares.util.TestHelper.ParameterNames.MIN_ACCEPTANCE_RATE_KEY; +import static com.axlabs.neo.grantshares.util.TestHelper.ParameterNames.REVIEW_LENGTH_KEY; +import static com.axlabs.neo.grantshares.util.TestHelper.ParameterValues.PHASE_LENGTH; import static com.axlabs.neo.grantshares.util.TestHelper.createAndEndorseProposal; import static com.axlabs.neo.grantshares.util.TestHelper.prepareDeployParameter; import static com.axlabs.neo.grantshares.util.TestHelper.voteForProposal; @@ -46,6 +46,7 @@ import static io.neow3j.types.ContractParameter.string; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @ContractTest(contracts = GrantSharesGov.class, blockTime = 1, configFile = "default.neo-express", @@ -69,14 +70,14 @@ public static DeployConfiguration deployConfig() throws Exception { DeployConfiguration config = new DeployConfiguration(); config.setDeployParam(prepareDeployParameter( ext.getAccount(ALICE), ext.getAccount(CHARLIE), ext.getAccount(DENISE), ext.getAccount(EVE), - ext.getAccount(FLORIAN))); + ext.getAccount(FLORIAN) + )); return config; } @BeforeAll public static void setUp() throws Throwable { neow3j = ext.getNeow3j(); - neow3j.allowTransmissionOnFault(); gov = new GrantSharesGovContract(ext.getDeployedContract(GrantSharesGov.class).getScriptHash(), neow3j); alice = ext.getAccount(ALICE); bob = ext.getAccount(BOB); @@ -87,21 +88,24 @@ public static void setUp() throws Throwable { } @Test - public void fail_executing_non_existent_proposal() throws Throwable { - Hash256 tx = gov.execute(1000).signers(AccountSigner.calledByEntry(alice)).sign().send() - .getSendRawTransaction().getHash(); - assertAborted(tx, "Proposal doesn't exist", neow3j); + public void fail_executing_non_existent_proposal() { + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.execute(1000).signers(AccountSigner.calledByEntry(alice)).sign() + ); + assertTrue(e.getMessage().endsWith("Proposal doesn't exist")); } @Test public void fail_executing_proposal_that_wasnt_endorsed() throws Throwable { ContractParameter intents = array(array(gov.getScriptHash(), CHANGE_PARAM, - array(MIN_ACCEPTANCE_RATE_KEY, 51), CallFlags.ALL.getValue())); + array(MIN_ACCEPTANCE_RATE_KEY, 51), CallFlags.ALL.getValue() + )); String offchainUri = "fail_executing_proposal_that_wasnt_endorsed"; // 1. Create proposal then skip till after the queued phase without endorsing. Hash256 tx = gov.invokeFunction(CREATE, hash160(bob), intents, string(offchainUri), - integer(-1)) + integer(-1) + ) .signers(AccountSigner.calledByEntry(bob)) .sign().send().getSendRawTransaction().getHash(); Await.waitUntilTransactionIsExecuted(tx, neow3j); @@ -110,16 +114,18 @@ public void fail_executing_proposal_that_wasnt_endorsed() throws Throwable { .getStack().get(0).getInteger().intValue(); // 2. Call execute - tx = gov.execute(id).signers(AccountSigner.calledByEntry(bob)) - .sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Proposal not in execution phase", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.execute(id).signers(AccountSigner.calledByEntry(bob)).sign() + ); + assertTrue(e.getMessage().endsWith("Proposal not in execution phase")); } @Test public void fail_executing_proposal_without_votes() throws Throwable { int newValue = 60; ContractParameter intents = array(array(gov.getScriptHash(), CHANGE_PARAM, - array(MIN_ACCEPTANCE_RATE_KEY, newValue), CallFlags.ALL.getValue())); + array(MIN_ACCEPTANCE_RATE_KEY, newValue), CallFlags.ALL.getValue() + )); String offchainUri = "fail_executing_proposal_without_votes"; // 1. Create and endorse proposal, then skip till after the queued phase without voting. @@ -127,15 +133,17 @@ public void fail_executing_proposal_without_votes() throws Throwable { ext.fastForwardOneBlock(PHASE_LENGTH + PHASE_LENGTH + PHASE_LENGTH); // 2. Call execute - Hash256 tx = gov.execute(id).signers(AccountSigner.calledByEntry(bob)) - .sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Quorum not reached", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.execute(id).signers(AccountSigner.calledByEntry(bob)).sign() + ); + assertTrue(e.getMessage().endsWith("Quorum not reached")); } @Test public void fail_executing_accepted_proposal_multiple_times() throws Throwable { ContractParameter intents = array(array(gov.getScriptHash(), CHANGE_PARAM, - array(MIN_ACCEPTANCE_RATE_KEY, 40), CallFlags.ALL.getValue())); + array(MIN_ACCEPTANCE_RATE_KEY, 40), CallFlags.ALL.getValue() + )); String offchainUri = "fail_executing_accepted_proposal_multiple_times"; // 1. Create and endorse proposal, then skip till voting phase. @@ -157,18 +165,22 @@ public void fail_executing_accepted_proposal_multiple_times() throws Throwable { .getNotifications().get(1).getEventName(), is(PROPOSAL_EXECUTED)); // 4. Call execute the second time and fail. - tx = gov.execute(id).signers(AccountSigner.calledByEntry(bob)) - .sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Proposal already executed", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.execute(id).signers(AccountSigner.calledByEntry(bob)).sign() + ); + assertTrue(e.getMessage().endsWith("Proposal already executed")); } @Test public void execute_proposal_with_multiple_intents() throws Throwable { ContractParameter intents = array( array(GasToken.SCRIPT_HASH, "transfer", array(alice.getScriptHash(), - bob.getScriptHash(), 1, any(null)), CallFlags.ALL.getValue()), + bob.getScriptHash(), 1, any(null) + ), CallFlags.ALL.getValue()), array(GasToken.SCRIPT_HASH, "transfer", array(alice.getScriptHash(), - bob.getScriptHash(), 1, any(null)), CallFlags.ALL.getValue())); + bob.getScriptHash(), 1, any(null) + ), CallFlags.ALL.getValue()) + ); String offchainUri = "execute_proposal_with_multiple_intents"; // 1. Create and endorse proposal @@ -213,7 +225,8 @@ public void execute_proposal_with_multiple_intents() throws Throwable { @Test public void fail_executing_proposal_quorum_reached_but_rejected() throws Throwable { ContractParameter intents = array(array(gov.getScriptHash(), CHANGE_PARAM, - array(MIN_ACCEPTANCE_RATE_KEY, 40), CallFlags.ALL.getValue())); + array(MIN_ACCEPTANCE_RATE_KEY, 40), CallFlags.ALL.getValue() + )); String offchainUri = "fail_executing_proposal_quorum_reached_but_rejected"; // 1. Create and endorse proposal, then skip till voting phase. @@ -229,15 +242,17 @@ public void fail_executing_proposal_quorum_reached_but_rejected() throws Throwab ext.fastForwardOneBlock(PHASE_LENGTH + PHASE_LENGTH); // 3. Call execute - Hash256 tx = gov.execute(id).signers(AccountSigner.calledByEntry(bob)) - .sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Proposal rejected", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.execute(id).signers(AccountSigner.calledByEntry(bob)).sign() + ); + assertTrue(e.getMessage().endsWith("Proposal rejected")); } @Test public void fail_executing_proposal_quorum_reached_but_all_abstained() throws Throwable { ContractParameter intents = array(array(gov.getScriptHash(), CHANGE_PARAM, - array(MIN_ACCEPTANCE_RATE_KEY, 40), CallFlags.ALL.getValue())); + array(MIN_ACCEPTANCE_RATE_KEY, 40), CallFlags.ALL.getValue() + )); String offchainUri = "fail_executing_proposal_quorum_reached_but_all_abstained"; // 1. Create and endorse proposal, then skip till voting phase. @@ -253,15 +268,17 @@ public void fail_executing_proposal_quorum_reached_but_all_abstained() throws Th ext.fastForwardOneBlock(PHASE_LENGTH + PHASE_LENGTH); // 3. Call execute - Hash256 tx = gov.execute(id).signers(AccountSigner.calledByEntry(bob)) - .sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Proposal rejected", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.execute(id).signers(AccountSigner.calledByEntry(bob)).sign() + ); + assertTrue(e.getMessage().endsWith("Proposal rejected")); } @Test public void fail_executing_proposal_quorum_not_reached() throws Throwable { ContractParameter intents = array(array(gov.getScriptHash(), CHANGE_PARAM, - array(MIN_ACCEPTANCE_RATE_KEY, 40), CallFlags.ALL.getValue())); + array(MIN_ACCEPTANCE_RATE_KEY, 40), CallFlags.ALL.getValue() + )); String offchainUri = "fail_executing_proposal_quorum_not_reached"; // 1. Create and endorse proposal, then skip till voting phase. @@ -274,15 +291,17 @@ public void fail_executing_proposal_quorum_not_reached() throws Throwable { ext.fastForwardOneBlock(PHASE_LENGTH + PHASE_LENGTH); // 3. Call execute - Hash256 tx = gov.execute(id).signers(AccountSigner.calledByEntry(bob)) - .sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Quorum not reached", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.execute(id).signers(AccountSigner.calledByEntry(bob)).sign() + ); + assertTrue(e.getMessage().endsWith("Quorum not reached")); } @Test public void fail_executing_proposal_with_different_quorum_not_reached() throws Throwable { ContractParameter intents = array(array(gov.getScriptHash(), CHANGE_PARAM, - array(MIN_ACCEPTANCE_RATE_KEY, 40), CallFlags.ALL.getValue())); + array(MIN_ACCEPTANCE_RATE_KEY, 40), CallFlags.ALL.getValue() + )); String offchainUri = "fail_executing_proposal_with_different_quorum_not_reached"; // 1. Create and endorse proposal, then skip till voting phase. @@ -296,15 +315,17 @@ public void fail_executing_proposal_with_different_quorum_not_reached() throws T ext.fastForwardOneBlock(PHASE_LENGTH + PHASE_LENGTH); // 3. Call execute - Hash256 tx = gov.execute(id).signers(AccountSigner.calledByEntry(bob)) - .sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Quorum not reached", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.execute(id).signers(AccountSigner.calledByEntry(bob)).sign() + ); + assertTrue(e.getMessage().endsWith("Quorum not reached")); } @Test public void fail_executing_proposal_with_different_quorum_reached_different_rate_rejected() throws Throwable { ContractParameter intents = array(array(gov.getScriptHash(), CHANGE_PARAM, - array(MIN_ACCEPTANCE_RATE_KEY, 40), CallFlags.ALL.getValue())); + array(MIN_ACCEPTANCE_RATE_KEY, 40), CallFlags.ALL.getValue() + )); String offchainUri = "fail_executing_proposal_with_different_quorum_reached_different_rate_rejected"; // 1. Create and endorse proposal, then skip till voting phase. @@ -320,15 +341,17 @@ public void fail_executing_proposal_with_different_quorum_reached_different_rate ext.fastForwardOneBlock(PHASE_LENGTH + PHASE_LENGTH); // 3. Call execute - Hash256 tx = gov.execute(id).signers(AccountSigner.calledByEntry(bob)) - .sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Proposal rejected", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.execute(id).signers(AccountSigner.calledByEntry(bob)).sign() + ); + assertTrue(e.getMessage().endsWith("Proposal rejected")); } @Test public void succeed_executing_proposal_with_different_quorum_reached_different_rate_accepted() throws Throwable { ContractParameter intents = array(array(gov.getScriptHash(), CHANGE_PARAM, - array(MIN_ACCEPTANCE_RATE_KEY, 40), CallFlags.ALL.getValue())); + array(MIN_ACCEPTANCE_RATE_KEY, 40), CallFlags.ALL.getValue() + )); String offchainUri = "succeed_executing_proposal_with_different_quorum_reached_different_rate_accepted"; // 1. Create and endorse proposal, then skip till voting phase. @@ -352,7 +375,8 @@ public void succeed_executing_proposal_with_different_quorum_reached_different_r @Test public void fail_executing_expired_proposal() throws Throwable { ContractParameter intents = array(array(gov.getScriptHash(), CHANGE_PARAM, array(REVIEW_LENGTH_KEY, 1), - CallFlags.ALL.getValue())); + CallFlags.ALL.getValue() + )); String discUrl = "fail_executing_expired_proposal"; // 1. Create and endorse proposal, then skip till after the queued phase without voting. @@ -365,8 +389,9 @@ public void fail_executing_expired_proposal() throws Throwable { ext.fastForwardOneBlock(PHASE_LENGTH + PHASE_LENGTH + PHASE_LENGTH); // skip voting, time lock, expiration phase // 2. Call execute - Hash256 tx = gov.execute(id).signers(AccountSigner.calledByEntry(bob)) - .sign().send().getSendRawTransaction().getHash(); - assertAborted(tx, "Proposal expired", neow3j); + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> gov.execute(id).signers(AccountSigner.calledByEntry(bob)).sign() + ); + assertTrue(e.getMessage().endsWith("Proposal expired")); } } diff --git a/src/test/java/com/axlabs/neo/grantshares/TreasuryMultiSigTest.java b/src/test/java/com/axlabs/neo/grantshares/TreasuryMultiSigTest.java index fef4a95..31c0bcd 100644 --- a/src/test/java/com/axlabs/neo/grantshares/TreasuryMultiSigTest.java +++ b/src/test/java/com/axlabs/neo/grantshares/TreasuryMultiSigTest.java @@ -18,6 +18,7 @@ import io.neow3j.transaction.AccountSigner; import io.neow3j.transaction.Transaction; import io.neow3j.transaction.Witness; +import io.neow3j.transaction.exceptions.TransactionConfigurationException; import io.neow3j.types.ContractParameter; import io.neow3j.types.Hash160; import io.neow3j.types.Hash256; @@ -35,15 +36,14 @@ import java.util.List; import java.util.Map; -import static com.axlabs.neo.grantshares.util.TestHelper.ALICE; -import static com.axlabs.neo.grantshares.util.TestHelper.BOB; -import static com.axlabs.neo.grantshares.util.TestHelper.CHARLIE; -import static com.axlabs.neo.grantshares.util.TestHelper.DENISE; -import static com.axlabs.neo.grantshares.util.TestHelper.EVE; -import static com.axlabs.neo.grantshares.util.TestHelper.IS_PAUSED; -import static com.axlabs.neo.grantshares.util.TestHelper.PAUSE; -import static com.axlabs.neo.grantshares.util.TestHelper.PHASE_LENGTH; -import static com.axlabs.neo.grantshares.util.TestHelper.assertAborted; +import static com.axlabs.neo.grantshares.util.TestHelper.GovernanceMethods.IS_PAUSED; +import static com.axlabs.neo.grantshares.util.TestHelper.GovernanceMethods.PAUSE; +import static com.axlabs.neo.grantshares.util.TestHelper.Members.ALICE; +import static com.axlabs.neo.grantshares.util.TestHelper.Members.BOB; +import static com.axlabs.neo.grantshares.util.TestHelper.Members.CHARLIE; +import static com.axlabs.neo.grantshares.util.TestHelper.Members.DENISE; +import static com.axlabs.neo.grantshares.util.TestHelper.Members.EVE; +import static com.axlabs.neo.grantshares.util.TestHelper.ParameterValues.PHASE_LENGTH; import static com.axlabs.neo.grantshares.util.TestHelper.createAndEndorseProposal; import static com.axlabs.neo.grantshares.util.TestHelper.createMultiSigAccount; import static com.axlabs.neo.grantshares.util.TestHelper.prepareDeployParameter; @@ -54,6 +54,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @ContractTest(contracts = {GrantSharesGov.class, GrantSharesTreasury.class}, @@ -99,9 +100,11 @@ public static DeployConfiguration deployConfigTreasury(DeployContext ctx) throws asList(denise.getECKeyPair().getPublicKey(), eve.getECKeyPair().getPublicKey()), 2); ContractParameter funders = array( array(bob.getScriptHash(), // bob - array(bob.getECKeyPair().getPublicKey())), + array(bob.getECKeyPair().getPublicKey()) + ), array(multiSigFunder.getScriptHash(), // denise, eve - array(denise.getECKeyPair().getPublicKey(), eve.getECKeyPair().getPublicKey())) + array(denise.getECKeyPair().getPublicKey(), eve.getECKeyPair().getPublicKey()) + ) ); // whitelisted tokens @@ -117,7 +120,6 @@ public static DeployConfiguration deployConfigTreasury(DeployContext ctx) throws @BeforeAll public static void setUp() throws Throwable { neow3j = ext.getNeow3j(); - neow3j.allowTransmissionOnFault(); // contracts gov = new GrantSharesGovContract( ext.getDeployedContract(GrantSharesGov.class).getScriptHash(), neow3j); @@ -182,10 +184,11 @@ public void calc_funders_multisig_address() throws Throwable { @Test @Order(0) - public void fail_execute_drain_on_unpaused_contract() throws Throwable { - Hash256 tx = treasury.drain().signers(AccountSigner.calledByEntry(alice)).sign().send() - .getSendRawTransaction().getHash(); - assertAborted(tx, "Contract is not paused", neow3j); + public void fail_execute_drain_on_unpaused_contract() { + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> treasury.drain().signers(AccountSigner.calledByEntry(alice)).sign() + ); + assertTrue(e.getMessage().endsWith("Contract is not paused")); } @Order(10) @@ -210,10 +213,11 @@ public void succeed_pausing_contract() throws Throwable { @Order(11) @Test - public void fail_execute_drain_with_non_funder() throws Throwable { - Hash256 tx = treasury.drain().signers(AccountSigner.calledByEntry(bob)).sign().send() - .getSendRawTransaction().getHash(); - assertAborted(tx, "Not authorized", neow3j); + public void fail_execute_drain_with_non_funder() { + TransactionConfigurationException e = assertThrows(TransactionConfigurationException.class, + () -> treasury.drain().signers(AccountSigner.calledByEntry(bob)).sign() + ); + assertTrue(e.getMessage().endsWith("Not authorized")); } @Order(12) diff --git a/src/test/java/com/axlabs/neo/grantshares/util/GrantSharesGovContract.java b/src/test/java/com/axlabs/neo/grantshares/util/GrantSharesGovContract.java index 24da51c..9967ae4 100644 --- a/src/test/java/com/axlabs/neo/grantshares/util/GrantSharesGovContract.java +++ b/src/test/java/com/axlabs/neo/grantshares/util/GrantSharesGovContract.java @@ -42,7 +42,8 @@ public Map getParameters() throws IOException, UnexpectedRet .getMap(); return map.entrySet().stream().collect(Collectors.toMap( i -> i.getKey().getString(), - i -> i.getValue().getInteger())); + i -> i.getValue().getInteger() + )); } public ProposalStruct getProposal(int id) throws IOException, UnexpectedReturnTypeException { @@ -78,13 +79,15 @@ public boolean isPaused() throws IOException, UnexpectedReturnTypeException { public TransactionBuilder createProposal(Hash160 proposer, String offchainUri, int linkedProposal, ContractParameter... intents) { return invokeFunction(getMethodName(), hash160(proposer), array(asList(intents)), - string(offchainUri), integer(linkedProposal)); + string(offchainUri), integer(linkedProposal) + ); } public TransactionBuilder createProposal(Hash160 proposer, String offchainUri, int linkedProposal, int acceptanceRate, int quorum, ContractParameter... intents) { return invokeFunction(getMethodName(), hash160(proposer), array(asList(intents)), - string(offchainUri), integer(linkedProposal), integer(acceptanceRate), integer(quorum)); + string(offchainUri), integer(linkedProposal), integer(acceptanceRate), integer(quorum) + ); } public TransactionBuilder endorseProposal(int id, Hash160 endorser) { diff --git a/src/test/java/com/axlabs/neo/grantshares/util/GrantSharesTreasuryContract.java b/src/test/java/com/axlabs/neo/grantshares/util/GrantSharesTreasuryContract.java index 9811791..450d96c 100644 --- a/src/test/java/com/axlabs/neo/grantshares/util/GrantSharesTreasuryContract.java +++ b/src/test/java/com/axlabs/neo/grantshares/util/GrantSharesTreasuryContract.java @@ -37,8 +37,9 @@ public Map getWhitelistedTokens() throws IOException { Map map = callInvokeFunction(getMethodName()) .getInvocationResult().getStack().get(0).getMap(); return map.entrySet().stream().collect(Collectors.toMap( - e -> Hash160.fromAddress(e.getKey().getAddress()), - e -> e.getValue().getInteger()) + e -> Hash160.fromAddress(e.getKey().getAddress()), + e -> e.getValue().getInteger() + ) ); } diff --git a/src/test/java/com/axlabs/neo/grantshares/util/IntentParam.java b/src/test/java/com/axlabs/neo/grantshares/util/IntentParam.java index d844d64..eab6f1e 100644 --- a/src/test/java/com/axlabs/neo/grantshares/util/IntentParam.java +++ b/src/test/java/com/axlabs/neo/grantshares/util/IntentParam.java @@ -24,12 +24,14 @@ public IntentParam(Hash160 targetContract, String method, ContractParameter... p public static IntentParam releaseTokenProposal(Hash160 treasury, Hash160 token, Hash160 receiver, BigInteger amount) { return new IntentParam(treasury, "releaseTokens", - hash160(token), hash160(receiver), integer(amount)); + hash160(token), hash160(receiver), integer(amount) + ); } public static IntentParam changeParamProposal(Hash160 gov, String paramName, int value) { return new IntentParam(gov, "changeParam", - string(paramName), integer(value)); + string(paramName), integer(value) + ); } public static IntentParam addMemberProposal(Hash160 gov, ECPublicKey pubKey) { diff --git a/src/test/java/com/axlabs/neo/grantshares/util/ProposalStruct.java b/src/test/java/com/axlabs/neo/grantshares/util/ProposalStruct.java index 40d3fad..ac29193 100644 --- a/src/test/java/com/axlabs/neo/grantshares/util/ProposalStruct.java +++ b/src/test/java/com/axlabs/neo/grantshares/util/ProposalStruct.java @@ -72,7 +72,8 @@ public ProposalStruct(int id, Hash160 proposer, int linkedProposal, int acceptan this.abstain = abstain; this.voters = voters.entrySet().stream().collect(Collectors.toMap( e -> e.getKey().getAddress(), - e -> e.getValue().getInteger().intValue())); + e -> e.getValue().getInteger().intValue() + )); } public static class IntentStruct { diff --git a/src/test/java/com/axlabs/neo/grantshares/util/TestHelper.java b/src/test/java/com/axlabs/neo/grantshares/util/TestHelper.java index f333620..8e63771 100644 --- a/src/test/java/com/axlabs/neo/grantshares/util/TestHelper.java +++ b/src/test/java/com/axlabs/neo/grantshares/util/TestHelper.java @@ -4,18 +4,15 @@ import io.neow3j.contract.SmartContract; import io.neow3j.crypto.ECKeyPair; import io.neow3j.protocol.Neow3j; -import io.neow3j.protocol.core.response.NeoApplicationLog; import io.neow3j.transaction.AccountSigner; import io.neow3j.transaction.TransactionBuilder; import io.neow3j.types.CallFlags; import io.neow3j.types.ContractParameter; import io.neow3j.types.Hash160; import io.neow3j.types.Hash256; -import io.neow3j.types.NeoVMStateType; import io.neow3j.utils.Await; import io.neow3j.wallet.Account; -import java.io.IOException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; @@ -28,64 +25,9 @@ import static io.neow3j.types.ContractParameter.integer; import static io.neow3j.types.ContractParameter.publicKey; import static io.neow3j.types.ContractParameter.string; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.is; public class TestHelper { - // Account names available in the neo-express config file. - public static final String ALICE = "NM7Aky765FG8NhhwtxjXRx7jEL1cnw7PBP"; - public static final String BOB = "NZpsgXn9VQQoLexpuXJsrX8BsoyAhKUyiX"; - public static final String CHARLIE = "NdbtgSku2qLuwsBBzLx3FLtmmMdm32Ktor"; - public static final String DENISE = "NerDv9t8exrQRrP11jjvZKXzSXvTnmfDTo"; - public static final String EVE = "NZ539Rd57v5NEtAdkHyFGaWj1uGt2DecUL"; - public static final String FLORIAN = "NRy5bp81kScYFZHLfMBXuubFfRyboVyu7G"; - - // GrantSharesGov contract methods - public static final String CREATE = "createProposal"; - public static final String GET_PROPOSAL = "getProposal"; - public static final String GET_PROPOSALS = "getProposals"; - public static final String GET_PARAMETER = "getParameter"; - public static final String GET_MEMBERS = "getMembers"; - public static final String GET_MEMBERS_COUNT = "getMembersCount"; - public static final String GET_PROPOSAL_COUNT = "getProposalCount"; - public static final String PAUSE = "pause"; - public static final String UNPAUSE = "unpause"; - public static final String IS_PAUSED = "isPaused"; - public static final String CALC_MEMBER_MULTI_SIG_ACC = "calcMembersMultiSigAccount"; - public static final String ENDORSE = "endorseProposal"; - public static final String VOTE = "vote"; - public static final String EXECUTE = "execute"; - public static final String CHANGE_PARAM = "changeParam"; - public static final String ADD_MEMBER = "addMember"; - public static final String REMOVE_MEMBER = "removeMember"; - public static final String UPDATE_CONTRACT = "updateContract"; - - // events - public static final String PROPOSAL_CREATED = "ProposalCreated"; - public static final String PROPOSAL_ENDORSED = "ProposalEndorsed"; - public static final String PROPOSAL_EXECUTED = "ProposalExecuted"; - public static final String VOTED = "Voted"; - public static final String MEMBER_ADDED = "MemberAdded"; - public static final String MEMBER_REMOVED = "MemberRemoved"; - public static final String PARAMETER_CHANGED = "ParameterChanged"; - - // governance parameters values - public static final int PHASE_LENGTH = 60; // seconds - public static final int MIN_ACCEPTANCE_RATE = 50; - public static final int MIN_QUORUM = 50; - public static final int MULTI_SIG_THRESHOLD_RATIO = 50; - - // parameter names - public static final String REVIEW_LENGTH_KEY = "review_len"; - public static final String VOTING_LENGTH_KEY = "voting_len"; - public static final String TIMELOCK_LENGTH_KEY = "timelock_len"; - public static final String EXPIRATION_LENGTH_KEY = "expiration_len"; - public static final String MIN_ACCEPTANCE_RATE_KEY = "min_accept_rate"; - public static final String MIN_QUORUM_KEY = "min_quorum"; - public static final String MULTI_SIG_THRESHOLD_KEY = "threshold"; - static MessageDigest hasher; static { @@ -97,103 +39,142 @@ public class TestHelper { } public static ContractParameter prepareDeployParameter(Account... members) { - return array( - array(Arrays.stream(members) - .map(m -> publicKey(m.getECKeyPair().getPublicKey().getEncoded(true))) + return array(array(Arrays.stream(members).map(m -> publicKey(m.getECKeyPair().getPublicKey().getEncoded(true))) .collect(Collectors.toList())), - array( - REVIEW_LENGTH_KEY, PHASE_LENGTH * 1000, - VOTING_LENGTH_KEY, PHASE_LENGTH * 1000, - TIMELOCK_LENGTH_KEY, PHASE_LENGTH * 1000, - EXPIRATION_LENGTH_KEY, PHASE_LENGTH * 1000, - MIN_ACCEPTANCE_RATE_KEY, MIN_ACCEPTANCE_RATE, - MIN_QUORUM_KEY, MIN_QUORUM, - MULTI_SIG_THRESHOLD_KEY, MULTI_SIG_THRESHOLD_RATIO + array(ParameterNames.REVIEW_LENGTH_KEY, ParameterValues.PHASE_LENGTH * 1000, + ParameterNames.VOTING_LENGTH_KEY, ParameterValues.PHASE_LENGTH * 1000, + ParameterNames.TIMELOCK_LENGTH_KEY, ParameterValues.PHASE_LENGTH * 1000, + ParameterNames.EXPIRATION_LENGTH_KEY, ParameterValues.PHASE_LENGTH * 1000, + ParameterNames.MIN_ACCEPTANCE_RATE_KEY, ParameterValues.MIN_ACCEPTANCE_RATE, + ParameterNames.MIN_QUORUM_KEY, ParameterValues.MIN_QUORUM, + ParameterNames.MULTI_SIG_THRESHOLD_KEY, ParameterValues.MULTI_SIG_THRESHOLD_RATIO ) ); } - public static Hash256 createSimpleProposal(SmartContract contract, Account proposer, - String offchainUri) throws Throwable { - - return contract.invokeFunction(CREATE, hash160(proposer), - array( - array( - NeoToken.SCRIPT_HASH, - "balanceOf", - array(new Hash160(defaultAccountScriptHash())), - CallFlags.ALL.getValue() - ) - ), - string(offchainUri), - integer(-1)) - .signers(AccountSigner.calledByEntry(proposer)) - .sign().send().getSendRawTransaction().getHash(); - } + public static Hash256 createSimpleProposal(SmartContract contract, Account proposer, String offchainUri) + throws Throwable { + return contract.invokeFunction(GovernanceMethods.CREATE, hash160(proposer), + array(array(NeoToken.SCRIPT_HASH, "balanceOf", array(new Hash160(defaultAccountScriptHash())), + CallFlags.ALL.getValue() + )), string(offchainUri), integer(-1) + ) + .signers(AccountSigner.calledByEntry(proposer)).sign().send().getSendRawTransaction().getHash(); + } public static int createAndEndorseProposal(GrantSharesGovContract gov, Neow3j neow3j, Account proposer, - Account endorser, ContractParameter intents, String offchainUri) throws Throwable { - TransactionBuilder b = gov.invokeFunction(CREATE, hash160(proposer), intents, string(offchainUri), - integer(-1)); + Account endorser, ContractParameter intents, String offchainUri) + throws Throwable { + TransactionBuilder b = gov.invokeFunction(GovernanceMethods.CREATE, hash160(proposer), intents, + string(offchainUri), integer(-1) + ); return sendAndEndorseProposal(gov, neow3j, proposer, endorser, b); } public static int createAndEndorseProposal(GrantSharesGovContract gov, Neow3j neow3j, Account proposer, Account endorser, ContractParameter intents, String offchainUri, int acceptanceRate, int quorum) throws Throwable { - TransactionBuilder b = gov.invokeFunction(CREATE, hash160(proposer), intents, string(offchainUri), - integer(-1), integer(acceptanceRate), integer(quorum)); + TransactionBuilder b = gov.invokeFunction(GovernanceMethods.CREATE, hash160(proposer), intents, + string(offchainUri), integer(-1), integer(acceptanceRate), integer(quorum) + ); return sendAndEndorseProposal(gov, neow3j, proposer, endorser, b); } private static int sendAndEndorseProposal(GrantSharesGovContract gov, Neow3j neow3j, Account proposer, - Account endorser, TransactionBuilder b) throws Throwable { - Hash256 tx = b.signers(AccountSigner.calledByEntry(proposer)) - .sign().send().getSendRawTransaction().getHash(); + Account endorser, TransactionBuilder b) + throws Throwable { + Hash256 tx = b.signers(AccountSigner.calledByEntry(proposer)).sign().send().getSendRawTransaction().getHash(); Await.waitUntilTransactionIsExecuted(tx, neow3j); - int id = neow3j.getApplicationLog(tx).send().getApplicationLog() - .getExecutions().get(0).getStack().get(0).getInteger().intValue(); + int id = neow3j.getApplicationLog(tx).send().getApplicationLog().getExecutions().get(0).getStack().get(0) + .getInteger().intValue(); // 2. endorse proposal - tx = gov.invokeFunction(ENDORSE, integer(id), hash160(endorser)) - .signers(AccountSigner.calledByEntry(endorser)) - .sign().send().getSendRawTransaction().getHash(); + tx = gov.invokeFunction(GovernanceMethods.ENDORSE, integer(id), hash160(endorser)) + .signers(AccountSigner.calledByEntry(endorser)).sign().send().getSendRawTransaction().getHash(); Await.waitUntilTransactionIsExecuted(tx, neow3j); return id; } - public static void voteForProposal(GrantSharesGovContract gov, Neow3j neow3j, int id, - Account endorserAndVoter) throws Throwable { - Hash256 tx = gov.invokeFunction(VOTE, integer(id), integer(1), hash160(endorserAndVoter)) - .signers(AccountSigner.calledByEntry(endorserAndVoter)) - .sign().send().getSendRawTransaction().getHash(); + public static void voteForProposal(GrantSharesGovContract gov, Neow3j neow3j, int id, Account endorserAndVoter) + throws Throwable { + Hash256 tx = gov.invokeFunction(GovernanceMethods.VOTE, integer(id), integer(1), hash160(endorserAndVoter)) + .signers(AccountSigner.calledByEntry(endorserAndVoter)).sign().send().getSendRawTransaction().getHash(); Await.waitUntilTransactionIsExecuted(tx, neow3j); } public static void voteForProposal(GrantSharesGovContract gov, Neow3j neow3j, int id, int vote, - Account endorserAndVoter) throws Throwable { - Hash256 tx = gov.invokeFunction(VOTE, integer(id), integer(vote), - hash160(endorserAndVoter)) - .signers(AccountSigner.calledByEntry(endorserAndVoter)) - .sign().send().getSendRawTransaction().getHash(); + Account endorserAndVoter) + throws Throwable { + Hash256 tx = gov.invokeFunction(GovernanceMethods.VOTE, integer(id), integer(vote), hash160(endorserAndVoter)) + .signers(AccountSigner.calledByEntry(endorserAndVoter)).sign().send().getSendRawTransaction().getHash(); Await.waitUntilTransactionIsExecuted(tx, neow3j); } public static Account createMultiSigAccount(int threshold, Account... accounts) { - List pubKeys = Arrays.stream(accounts) - .map(a -> a.getECKeyPair().getPublicKey()) + List pubKeys = Arrays.stream(accounts).map(a -> a.getECKeyPair().getPublicKey()) .collect(Collectors.toList()); return Account.createMultiSigAccount(pubKeys, threshold); } - public static void assertAborted(Hash256 tx, String expectedError, Neow3j neow3j) throws IOException { - Await.waitUntilTransactionIsExecuted(tx, neow3j); - NeoApplicationLog.Execution e = neow3j.getApplicationLog(tx).send().getApplicationLog().getExecutions().get(0); - assertThat(e.getState(), is(NeoVMStateType.FAULT)); - String exception = e.getNotifications().get(0).getState().getList().get(0).getString(); - assertThat(exception, containsString(expectedError)); + public static class Members { + // Account names available in the neo-express config file. + public static final String ALICE = "NM7Aky765FG8NhhwtxjXRx7jEL1cnw7PBP"; + public static final String BOB = "NZpsgXn9VQQoLexpuXJsrX8BsoyAhKUyiX"; + public static final String CHARLIE = "NdbtgSku2qLuwsBBzLx3FLtmmMdm32Ktor"; + public static final String DENISE = "NerDv9t8exrQRrP11jjvZKXzSXvTnmfDTo"; + public static final String EVE = "NZ539Rd57v5NEtAdkHyFGaWj1uGt2DecUL"; + public static final String FLORIAN = "NRy5bp81kScYFZHLfMBXuubFfRyboVyu7G"; + } + + public static class GovernanceMethods { + public static final String ADD_MEMBER = "addMember"; + public static final String CALC_MEMBER_MULTI_SIG_ACC = "calcMembersMultiSigAccount"; + public static final String CHANGE_PARAM = "changeParam"; + public static final String CREATE = "createProposal"; + public static final String ENDORSE = "endorseProposal"; + public static final String EXECUTE = "execute"; + public static final String GET_MEMBERS = "getMembers"; + public static final String GET_MEMBERS_COUNT = "getMembersCount"; + public static final String GET_PARAMETER = "getParameter"; + public static final String GET_PROPOSAL = "getProposal"; + public static final String GET_PROPOSALS = "getProposals"; + public static final String GET_PROPOSAL_COUNT = "getProposalCount"; + public static final String IS_PAUSED = "isPaused"; + public static final String PAUSE = "pause"; + public static final String REMOVE_MEMBER = "removeMember"; + public static final String UNPAUSE = "unpause"; + public static final String UPDATE_CONTRACT = "updateContract"; + public static final String VOTE = "vote"; + } + + public static class Events { + public static final String MEMBER_ADDED = "MemberAdded"; + public static final String MEMBER_REMOVED = "MemberRemoved"; + public static final String PARAMETER_CHANGED = "ParameterChanged"; + public static final String PROPOSAL_CREATED = "ProposalCreated"; + public static final String PROPOSAL_ENDORSED = "ProposalEndorsed"; + public static final String PROPOSAL_EXECUTED = "ProposalExecuted"; + public static final String VOTED = "Voted"; } + + public static class ParameterNames { + public static final String EXPIRATION_LENGTH_KEY = "expiration_len"; + public static final String MIN_ACCEPTANCE_RATE_KEY = "min_accept_rate"; + public static final String MIN_QUORUM_KEY = "min_quorum"; + public static final String MULTI_SIG_THRESHOLD_KEY = "threshold"; + public static final String REVIEW_LENGTH_KEY = "review_len"; + public static final String TIMELOCK_LENGTH_KEY = "timelock_len"; + public static final String VOTING_LENGTH_KEY = "voting_len"; + } + + public static class ParameterValues { + public static final int MIN_ACCEPTANCE_RATE = 50; + public static final int MIN_QUORUM = 50; + public static final int MULTI_SIG_THRESHOLD_RATIO = 50; + public static final int PHASE_LENGTH = 60; // seconds + } + }