|
| 1 | +import { assert } from "chai"; |
| 2 | +import { Account } from "../accounts"; |
| 3 | +import { SmartContractQueryResponse } from "../core"; |
| 4 | +import { Address } from "../core/address"; |
| 5 | +import { ProxyNetworkProvider } from "../networkProviders"; |
| 6 | +import { b64TopicsToBytes, MockNetworkProvider } from "../testutils"; |
| 7 | +import { KeyPair, UserSecretKey } from "../wallet"; |
| 8 | +import { GovernanceController } from "./governanceController"; |
| 9 | +import { Vote } from "./resources"; |
| 10 | + |
| 11 | +describe("test governance controller", function () { |
| 12 | + const chainID = "D"; |
| 13 | + const controller = new GovernanceController({ |
| 14 | + chainID: chainID, |
| 15 | + networkProvider: new ProxyNetworkProvider("https://devnet-gateway.multiversx.com"), |
| 16 | + }); |
| 17 | + |
| 18 | + const commitHash = "1db734c0315f9ec422b88f679ccfe3e0197b9d67"; |
| 19 | + const governanceAddress = "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqrlllsrujgla"; |
| 20 | + |
| 21 | + const aliceBech32 = "erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th"; |
| 22 | + const secretKey = UserSecretKey.fromString("413f42575f7f26fad3317a778771212fdb80245850981e48b58a4f25e344e8f9"); |
| 23 | + const keypair = new KeyPair(secretKey); |
| 24 | + const alice = Account.newFromKeypair(keypair); |
| 25 | + |
| 26 | + it("should create transaction for creating new proposal", async function () { |
| 27 | + const expectedData = `proposal@${Buffer.from(commitHash).toString("hex")}@0a@0f`; |
| 28 | + |
| 29 | + const transaction = await controller.createTransactionForNewProposal(alice, alice.getNonceThenIncrement(), { |
| 30 | + commitHash: commitHash, |
| 31 | + startVoteEpoch: 10, |
| 32 | + endVoteEpoch: 15, |
| 33 | + nativeTokenAmount: 1000_000000000000000000n, |
| 34 | + }); |
| 35 | + |
| 36 | + assert.equal(transaction.sender.toBech32(), aliceBech32); |
| 37 | + assert.equal(transaction.receiver.toBech32(), governanceAddress); |
| 38 | + assert.equal(transaction.value, 1000_000000000000000000n); |
| 39 | + assert.equal(transaction.chainID, chainID); |
| 40 | + assert.equal(transaction.gasLimit, 50_192_500n); |
| 41 | + assert.equal(transaction.data.toString(), expectedData); |
| 42 | + }); |
| 43 | + |
| 44 | + it("should create transaction for voting", async function () { |
| 45 | + const transaction = await controller.createTransactionForVoting(alice, alice.getNonceThenIncrement(), { |
| 46 | + proposalNonce: 1, |
| 47 | + vote: Vote.YES, |
| 48 | + }); |
| 49 | + |
| 50 | + assert.equal(transaction.sender.toBech32(), aliceBech32); |
| 51 | + assert.equal(transaction.receiver.toBech32(), governanceAddress); |
| 52 | + assert.equal(transaction.value, 0n); |
| 53 | + assert.equal(transaction.chainID, chainID); |
| 54 | + assert.equal(transaction.gasLimit, 5_171_000n); |
| 55 | + assert.equal(transaction.data.toString(), "vote@01@796573"); |
| 56 | + }); |
| 57 | + |
| 58 | + it("should create transaction for closing proposal", async function () { |
| 59 | + const transaction = await controller.createTransactionForClosingProposal(alice, alice.getNonceThenIncrement(), { |
| 60 | + proposalNonce: 1, |
| 61 | + }); |
| 62 | + |
| 63 | + assert.equal(transaction.sender.toBech32(), aliceBech32); |
| 64 | + assert.equal(transaction.receiver.toBech32(), governanceAddress); |
| 65 | + assert.equal(transaction.value, 0n); |
| 66 | + assert.equal(transaction.chainID, chainID); |
| 67 | + assert.equal(transaction.gasLimit, 50_074_000n); |
| 68 | + assert.equal(transaction.data.toString(), "closeProposal@01"); |
| 69 | + }); |
| 70 | + |
| 71 | + it("should create transaction for clearing ended proposals", async function () { |
| 72 | + const expectedData = |
| 73 | + "clearEndedProposals@0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1@8049d639e5a6980d1cd2392abcce41029cda74a1563523a202f09641cc2618f8"; |
| 74 | + |
| 75 | + const transaction = await controller.createTransactionForClearingEndedProposals( |
| 76 | + alice, |
| 77 | + alice.getNonceThenIncrement(), |
| 78 | + { |
| 79 | + proposers: [ |
| 80 | + alice.address, |
| 81 | + Address.newFromBech32("erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx"), |
| 82 | + ], |
| 83 | + }, |
| 84 | + ); |
| 85 | + |
| 86 | + assert.equal(transaction.sender.toBech32(), aliceBech32); |
| 87 | + assert.equal(transaction.receiver.toBech32(), governanceAddress); |
| 88 | + assert.equal(transaction.value, 0n); |
| 89 | + assert.equal(transaction.chainID, chainID); |
| 90 | + assert.equal(transaction.gasLimit, 150_273_500n); |
| 91 | + assert.equal(transaction.data.toString(), expectedData); |
| 92 | + }); |
| 93 | + |
| 94 | + it("should create transaction for claiming accumulated fees", async function () { |
| 95 | + const transaction = await controller.createTransactionForClaimingAccumulatedFees( |
| 96 | + alice, |
| 97 | + alice.getNonceThenIncrement(), |
| 98 | + {}, |
| 99 | + ); |
| 100 | + |
| 101 | + assert.equal(transaction.sender.toBech32(), aliceBech32); |
| 102 | + assert.equal(transaction.receiver.toBech32(), governanceAddress); |
| 103 | + assert.equal(transaction.value, 0n); |
| 104 | + assert.equal(transaction.chainID, chainID); |
| 105 | + assert.equal(transaction.gasLimit, 1_080_000n); |
| 106 | + assert.equal(transaction.data.toString(), "claimAccumulatedFees"); |
| 107 | + }); |
| 108 | + |
| 109 | + it("should create transaction for changing config", async function () { |
| 110 | + const expectedData = |
| 111 | + "changeConfig@31303030303030303030303030303030303030303030@3130303030303030303030303030303030303030@35303030@33303030@36303030"; |
| 112 | + |
| 113 | + const transaction = await controller.createTransactionForChangingConfig(alice, alice.getNonceThenIncrement(), { |
| 114 | + proposalFee: 1000000000000000000000n, |
| 115 | + lastProposalFee: 10000000000000000000n, |
| 116 | + minQuorum: 5000, |
| 117 | + minVetoThreshold: 3000, |
| 118 | + minPassThreshold: 6000, |
| 119 | + }); |
| 120 | + |
| 121 | + assert.equal(transaction.sender.toBech32(), aliceBech32); |
| 122 | + assert.equal(transaction.receiver.toBech32(), governanceAddress); |
| 123 | + assert.equal(transaction.value, 0n); |
| 124 | + assert.equal(transaction.chainID, chainID); |
| 125 | + assert.equal(transaction.gasLimit, 50_237_500n); |
| 126 | + assert.equal(transaction.data.toString(), expectedData); |
| 127 | + }); |
| 128 | + |
| 129 | + it("should get voting power", async function () { |
| 130 | + const provider = new MockNetworkProvider(); |
| 131 | + const controller = new GovernanceController({ |
| 132 | + chainID: chainID, |
| 133 | + networkProvider: provider, |
| 134 | + }); |
| 135 | + |
| 136 | + provider.mockQueryContractOnFunction( |
| 137 | + "viewVotingPower", |
| 138 | + new SmartContractQueryResponse({ |
| 139 | + returnDataParts: [Buffer.from("878678326eac900000", "hex")], |
| 140 | + returnCode: "ok", |
| 141 | + returnMessage: "", |
| 142 | + function: "viewVotingPower", |
| 143 | + }), |
| 144 | + ); |
| 145 | + |
| 146 | + const votingPower = await controller.getVotingPower(alice.address); |
| 147 | + assert.equal(votingPower, 2500_000000000000000000n); |
| 148 | + }); |
| 149 | + |
| 150 | + it("should get config", async function () { |
| 151 | + const provider = new MockNetworkProvider(); |
| 152 | + const controller = new GovernanceController({ |
| 153 | + chainID: chainID, |
| 154 | + networkProvider: provider, |
| 155 | + }); |
| 156 | + |
| 157 | + provider.mockQueryContractOnFunction( |
| 158 | + "viewConfig", |
| 159 | + new SmartContractQueryResponse({ |
| 160 | + returnDataParts: [ |
| 161 | + Buffer.from("1000000000000000000000"), |
| 162 | + Buffer.from("0.2000"), |
| 163 | + Buffer.from("0.5000"), |
| 164 | + Buffer.from("0.3300"), |
| 165 | + Buffer.from("1"), |
| 166 | + ], |
| 167 | + returnCode: "ok", |
| 168 | + returnMessage: "", |
| 169 | + function: "viewConfig", |
| 170 | + }), |
| 171 | + ); |
| 172 | + |
| 173 | + const config = await controller.getConfig(); |
| 174 | + assert.equal(config.proposalFee, 1000_000000000000000000n); |
| 175 | + assert.equal(config.minQuorum, 0.2); |
| 176 | + assert.equal(config.minPassThreshold, 0.5); |
| 177 | + assert.equal(config.minVetoThreshold, 0.33); |
| 178 | + assert.equal(config.lastProposalNonce, 1); |
| 179 | + }); |
| 180 | + |
| 181 | + it("should get proposal", async function () { |
| 182 | + const provider = new MockNetworkProvider(); |
| 183 | + const controller = new GovernanceController({ |
| 184 | + chainID: chainID, |
| 185 | + networkProvider: provider, |
| 186 | + }); |
| 187 | + |
| 188 | + provider.mockQueryContractOnFunction( |
| 189 | + "viewProposal", |
| 190 | + new SmartContractQueryResponse({ |
| 191 | + returnDataParts: b64TopicsToBytes([ |
| 192 | + "NjXJrcXeoAAA", |
| 193 | + "MWRiNzM0YzAzMTVmOWVjNDIyYjg4ZjY3OWNjZmUzZTAxOTdiOWQ2Nw==", |
| 194 | + "AQ==", |
| 195 | + "ATlHLv9ohncamC8wg9pdQh8kwpGB5jiIIo3IHKYNaeE=", |
| 196 | + "NQ==", |
| 197 | + "Nw==", |
| 198 | + "", |
| 199 | + "", |
| 200 | + "", |
| 201 | + "", |
| 202 | + "", |
| 203 | + "ZmFsc2U=", |
| 204 | + "ZmFsc2U=", |
| 205 | + ]), |
| 206 | + returnCode: "ok", |
| 207 | + returnMessage: "", |
| 208 | + function: "viewProposal", |
| 209 | + }), |
| 210 | + ); |
| 211 | + |
| 212 | + const proposal = await controller.getProposal(1); |
| 213 | + assert.equal(proposal.cost, 1000_000000000000000000n); |
| 214 | + assert.equal(proposal.commitHash, "1db734c0315f9ec422b88f679ccfe3e0197b9d67"); |
| 215 | + assert.equal(proposal.nonce, 1); |
| 216 | + assert.equal(proposal.issuer.toBech32(), aliceBech32); |
| 217 | + assert.equal(proposal.startVoteEpoch, 53); |
| 218 | + assert.equal(proposal.endVoteEpoch, 55); |
| 219 | + assert.equal(proposal.quorumStake, 0n); |
| 220 | + assert.equal(proposal.numYesVotes, 0n); |
| 221 | + assert.equal(proposal.numNoVotes, 0n); |
| 222 | + assert.equal(proposal.numVetoVotes, 0n); |
| 223 | + assert.equal(proposal.numAbstainVotes, 0n); |
| 224 | + assert.equal(proposal.isClosed, false); |
| 225 | + assert.equal(proposal.isPassed, false); |
| 226 | + }); |
| 227 | +}); |
0 commit comments