From 5e0379f1021ab26a7a396bffd3387440afecc7f2 Mon Sep 17 00:00:00 2001 From: 0surface Date: Thu, 5 Nov 2020 09:16:36 +0000 Subject: [PATCH 01/12] use const, refactor out validation, optimise --- app/js/app.js | 125 +++++++++++++++++++++++++------------------------- 1 file changed, 62 insertions(+), 63 deletions(-) diff --git a/app/js/app.js b/app/js/app.js index a77bf1f..c9a2e72 100644 --- a/app/js/app.js +++ b/app/js/app.js @@ -5,7 +5,6 @@ const $ = require("jquery"); const splitterJson = require("../../build/contracts/Splitter.json"); require("file-loader?name=../index.html!../index.html"); -let accounts = []; let wallets = []; if (typeof web3 !== "undefined") { @@ -21,47 +20,18 @@ const Splitter = truffleContract(splitterJson); Splitter.setProvider(web3.currentProvider); const split = async function () { - const gas = 2000000; - let deployed; - - $("#senderHelp").html(""); - $("#receiver1Help").html(""); - $("#receiver2Help").html(""); - $("#amountHelp").html(""); + validateSplit(); + const gas = 2000000; const sender = $("input[id='sender']"); const _receiver1 = $("input[id='receiver1']"); const _receiver2 = $("input[id='receiver2']"); const amount = $("input[id='amount']"); - let hasValidationError = false; - - if (!$("#sender").val()) { - $("#senderHelp").html("Sender address is required").css("color", "red"); - hasValidationError = true; - } - if (!$("#receiver1").val()) { - $("#receiver1Help").html("First receiver address is required").css("color", "red"); - hasValidationError = true; - } - if (!_receiver2.val()) { - $("#receiver2Help").html("Second receiver address is required").css("color", "red"); - hasValidationError = true; - } - - if (!amount.val()) { - $("#amountHelp").html("Second receiver address is required").css("color", "red"); - hasValidationError = true; - } - - if (hasValidationError) { - return; - } - - deployed = await Splitter.deployed(); + const deployed = await Splitter.deployed(); const { split } = deployed; - let tranParamsObj = { + const tranParamsObj = { from: sender.val(), value: web3.utils.toWei(amount.val(), "ether"), gas: gas, @@ -76,7 +46,7 @@ const split = async function () { throw new Error("The split transaction will fail anyway, not sending"); } - let txObj = await split + const txObj = await split .sendTransaction(_receiver1.val(), _receiver2.val(), tranParamsObj) .on("transactionHash", (txHash) => $("#status").html("Transaction on the way " + txHash)); @@ -87,6 +57,37 @@ const split = async function () { updateUI(txObj); }; +const validateSplit = async function () { + $("#senderHelp").html(""); + $("#receiver1Help").html(""); + $("#receiver2Help").html(""); + $("#amountHelp").html(""); + + let hasValidationError = false; + + if (!$("#sender").val()) { + $("#senderHelp").html("Sender address is required").css("color", "red"); + hasValidationError = true; + } + if (!$("#receiver1").val()) { + $("#receiver1Help").html("First receiver address is required").css("color", "red"); + hasValidationError = true; + } + if (!_receiver2.val()) { + $("#receiver2Help").html("Second receiver address is required").css("color", "red"); + hasValidationError = true; + } + + if (!amount.val()) { + $("#amountHelp").html("Second receiver address is required").css("color", "red"); + hasValidationError = true; + } + + if (hasValidationError) { + return; + } +}; + const withdraw = async function () { const gas = 2000000; const withdrawer = $("input[id='withdrawer']"); @@ -97,25 +98,25 @@ const withdraw = async function () { return; } - let balanceInWei = await web3.eth.getBalance(withdrawer.val()); + const balanceInWei = await web3.eth.getBalance(withdrawer.val()); if (balanceInWei < gas) { window.alert("You don't have sufficient funds in your balance"); return; } - let _deployed = await Splitter.deployed(); + const _deployed = await Splitter.deployed(); const { withdraw } = _deployed; - let transParamObj = { from: withdrawer.val(), gas: gas }; + const transParamObj = { from: withdrawer.val(), gas: gas }; const okToSend = await withdraw.call(transParamObj).catch((err) => { $("#status").html("The Withdraw transaction will fail. Please check your account balance/ split amount."); flashRedError("status", 3); flashRedError("withdrawHeader", 3); - return; + return false; }); if (okToSend) { - let txReceipt = await withdraw + const txReceipt = await withdraw .sendTransaction(transParamObj) .on("transactionHash", (txHash) => $("#status").html("Transaction on the way " + txHash)); @@ -141,26 +142,23 @@ const showBalance = async function (wallet) { }; const showDappBalance = async function (wallet) { - let _deployed = await Splitter.deployed(); - let { accountBalances } = _deployed; + const _deployed = await Splitter.deployed(); + const { accountBalances } = _deployed; - let dappBalanceElement = document.getElementById(`address${wallet.i}DappBalance`); + const dappBalanceElement = document.getElementById(`address${wallet.i}DappBalance`); return accountBalances .call(wallet.address) .then((dappBalance) => { - let etherBalance = web3.utils.fromWei(dappBalance, "ether"); - dappBalanceElement.innerHTML = etherBalance; + dappBalanceElement.innerHTML = web3.utils.fromWei(dappBalance, "ether"); }) .catch(console.error); }; const showContractBalance = async function () { Splitter.deployed() - .then((instance) => instance) .then((contract) => { - let _contractAddress = contract.address; - return web3.eth.getBalance(_contractAddress); + return web3.eth.getBalance(contract.address); }) .then((balance) => { $("#contractBalance").html(web3.utils.fromWei(balance, "ether").toString(10)); @@ -169,32 +167,32 @@ const showContractBalance = async function () { }; const updateUI = function (txObj) { - const receipt = txObj.receipt; - if (!receipt.status) { + if (!txObj.receipt.status) { console.error("Wrong status"); - console.error(receipt); + console.error(txObj.receipt); $("#status").html("There was an error in the tx execution, status not 1"); - } else if (receipt.logs.length == 0) { + } else if (txObj.receipt.logs.length == 0) { console.error("Empty logs"); - console.error(receipt); + console.error(txObj.receipt); $("#status").html("There was an error in the tx execution, missing expected event"); } else { $("#status").html("Transfer executed"); } showContractBalance(); - wallets.slice(0, 5).map((w) => showBalance(w)); - wallets.slice(0, 5).map((w) => showDappBalance(w)); + wallets.slice(0, 5).map((w) => { + showBalance(w); + showDappBalance(w); + }); }; const flashRedError = function (elementIdTag, seconds) { - let $el = $(`#${elementIdTag}`); - let x = seconds * 1000; - let originalColor = $el.css("background"); + const $el = $(`#${elementIdTag}`); + const originalColor = $el.css("background"); $el.css("background", "#FF5733"); setTimeout(function () { $el.css("background", originalColor); - }, x); + }, seconds * 1000); }; window.addEventListener("load", function () { @@ -202,9 +200,8 @@ window.addEventListener("load", function () { .getAccounts() .then((accounts) => { if (accounts.length == 0) { - throw new Error("No account with which to transact"); + throw new Error("No accounts with which to transact"); } - this.accounts = accounts; window.account = accounts[0]; return accounts; }) @@ -213,8 +210,10 @@ window.addEventListener("load", function () { let address = accountList[i]; wallets.push({ i, address }); } - wallets.slice(0, 5).map((w) => showBalance(w)); - wallets.slice(0, 5).map((w) => showDappBalance(w)); + wallets.slice(0, 5).map((w) => { + showBalance(w); + showDappBalance(w); + }); }) .catch(console.error); From ce0cdf465ddb8c33ad0ba8f725256569a47b5f3d Mon Sep 17 00:00:00 2001 From: 0surface Date: Thu, 5 Nov 2020 09:44:26 +0000 Subject: [PATCH 02/12] refactor 'done' from promises --- test/splitter_split_tests.js | 24 +++++++++--------------- test/splitter_withdraw_tests.js | 16 ++++++---------- 2 files changed, 15 insertions(+), 25 deletions(-) diff --git a/test/splitter_split_tests.js b/test/splitter_split_tests.js index b916a00..0b06822 100644 --- a/test/splitter_split_tests.js +++ b/test/splitter_split_tests.js @@ -49,9 +49,9 @@ contract("Splitter", (accounts) => { .catch(done); }); - it("contract address has the sent amount value", (done) => { + it("contract address has the sent amount value", () => { const _sentAmount = 20; - splitter.contract.methods + return splitter.contract.methods .split(receiver_1, receiver_2) .send({ from: fundSender, @@ -63,16 +63,14 @@ contract("Splitter", (accounts) => { }) .then((splitterBalance) => { assert.equal(splitterBalance, _sentAmount, "contract balance doesn't have sent value"); - done(); - }) - .catch(done); + }); }); - it("splits even number sent value exactly into two", (done) => { + it("splits even number sent value exactly into two", () => { const _sentAmount = 20; const _splitAmount = 10; - splitter.contract.methods + return splitter.contract.methods .split(receiver_1, receiver_2) .send({ from: fundSender, @@ -91,15 +89,13 @@ contract("Splitter", (accounts) => { }) .then((fundSenderBalance) => { assert.equal(fundSenderBalance.toString(10), 0, "fund sender is assigned a value"); - done(); - }) - .catch(done); + }); }); - it("Assigns 1 wei back to sender when sent odd value", (done) => { + it("Assigns 1 wei back to sender when sent odd value", () => { const _sentAmount = 21; - splitter.contract.methods + return splitter.contract.methods .split(receiver_1, receiver_2) .send({ from: fundSender, @@ -111,9 +107,7 @@ contract("Splitter", (accounts) => { .then((fundSenderBalance) => { const assignedValue = fundSenderBalance.toString(10); assert.equal(assignedValue, 1, "fundSender not assigned 1 wei"); - done(); - }) - .catch(done); + }); }); it("reverts when a receiver null address", async () => { diff --git a/test/splitter_withdraw_tests.js b/test/splitter_withdraw_tests.js index c7876d7..264eca6 100644 --- a/test/splitter_withdraw_tests.js +++ b/test/splitter_withdraw_tests.js @@ -23,10 +23,10 @@ contract("Splitter", (accounts) => { assert.equal(await web3.eth.getBalance(splitter.address), 0, "contract has no funds on deployment"); }); - it("should emit event on successful withdrawal", (done) => { + it("should emit event on successful withdrawal", () => { let _fundBeforeWithdrawal = 0; - splitter.contract.methods + return splitter.contract.methods .split(receiver_1, receiver_2) .send({ from: fundSender, @@ -41,9 +41,7 @@ contract("Splitter", (accounts) => { }) .then((txObj) => { assert.isTrue(typeof txObj.events.LogFundWithdrawn !== "undefined", "LogFundWithdrawn event was not emmited"); - done(); - }) - .catch(done); + }); }); it("withdrawer should get their allocated money", async () => { @@ -107,8 +105,8 @@ contract("Splitter", (accounts) => { await truffleAssert.reverts(splitter.contract.methods.withdraw().send({ from: randomAddress }), "No funds to withdraw"); }); - it("should reset receiver's assigned funds back to zero on withdrawal", (done) => { - splitter.contract.methods + it("should reset receiver's assigned funds back to zero on withdrawal", () => { + return splitter.contract.methods .split(receiver_1, receiver_2) .send({ from: fundSender, @@ -120,8 +118,6 @@ contract("Splitter", (accounts) => { }) .then((receiver1Balance) => { assert.equal(receiver1Balance.toString(10), 0, "receiver balance record is NOT set to zero after withdrwal"); - done(); - }) - .catch(done); + }); }); }); From 34a65fcd8b3353c4377aff89832ed800883fc6be Mon Sep 17 00:00:00 2001 From: 0surface Date: Thu, 5 Nov 2020 09:59:54 +0000 Subject: [PATCH 03/12] use assert.isDefined, optimise --- test/splitter_split_tests.js | 18 +++++------------ test/splitter_withdraw_tests.js | 34 +++++++++++++++------------------ 2 files changed, 20 insertions(+), 32 deletions(-) diff --git a/test/splitter_split_tests.js b/test/splitter_split_tests.js index 0b06822..a468c70 100644 --- a/test/splitter_split_tests.js +++ b/test/splitter_split_tests.js @@ -24,19 +24,16 @@ contract("Splitter", (accounts) => { assert.strictEqual(parseInt(balance), 0, "contract shouldn't have funds on deployment"); }); - it("split method emits event", (done) => { + it("split method emits event", () => { const _sentAmount = 21; - splitter.contract.methods + return splitter.contract.methods .split(receiver_1, receiver_2) .send({ from: fundSender, value: _sentAmount, }) .then((txObj) => { - assert.isTrue( - typeof txObj.events.LogSplitSuccessful.returnValues !== "undefined", - "LogSplitSuccessful event was not emmited" - ); + assert.isDefined(txObj.events.LogSplitSuccessful.returnValues, "LogSplitSuccessful event was not emmited"); return txObj.events.LogSplitSuccessful.returnValues; }) .then((eventValues) => { @@ -44,9 +41,7 @@ contract("Splitter", (accounts) => { assert.strictEqual(eventValues.receiver1, receiver_1, "receiver_1 is not same"); assert.strictEqual(eventValues.receiver2, receiver_2, "receiver_2 is not same"); assert.strictEqual(eventValues.sentAmount, _sentAmount.toString(), "Sent Amount is not equal to expected"); - done(); - }) - .catch(done); + }); }); it("contract address has the sent amount value", () => { @@ -88,7 +83,7 @@ contract("Splitter", (accounts) => { return splitter.accountBalances.call(fundSender); }) .then((fundSenderBalance) => { - assert.equal(fundSenderBalance.toString(10), 0, "fund sender is assigned a value"); + assert.equal(fundSenderBalance.toString(10), 0, "fund sender is incorrectly assigned a value"); }); }); @@ -129,7 +124,4 @@ contract("Splitter", (accounts) => { "Invalid minimum amount" ); }); - - //TODO: - //it("reverts on overflow math calcuations", () => {}); }); diff --git a/test/splitter_withdraw_tests.js b/test/splitter_withdraw_tests.js index 264eca6..6d36f71 100644 --- a/test/splitter_withdraw_tests.js +++ b/test/splitter_withdraw_tests.js @@ -14,8 +14,6 @@ contract("Splitter", (accounts) => { it("TestRPC must have adequate number of addresses", () => { assert.isTrue(accounts.length >= 5, "Test has enough addresses"); }); - - splitter = await artifacts.require("Splitter.sol").new(); }); beforeEach("deploy a fresh contract ", async () => { @@ -24,23 +22,25 @@ contract("Splitter", (accounts) => { }); it("should emit event on successful withdrawal", () => { - let _fundBeforeWithdrawal = 0; - + const _amountSent = 20; + const _amountToWithdraw = 10; return splitter.contract.methods .split(receiver_1, receiver_2) .send({ from: fundSender, - value: 20, - }) - .then(() => { - return splitter.accountBalances.call(receiver_1); + value: _amountSent, }) - .then((receiver1Balance) => { - _fundBeforeWithdrawal = receiver1Balance; + .then((splitTxObj) => { + assert.isDefined(splitTxObj.events.LogSplitSuccessful, "Split failed prior to withdraw"); return splitter.contract.methods.withdraw().send({ from: receiver_1 }); }) - .then((txObj) => { - assert.isTrue(typeof txObj.events.LogFundWithdrawn !== "undefined", "LogFundWithdrawn event was not emmited"); + .then((withdrawTxObj) => { + assert.isDefined(withdrawTxObj.events.LogFundWithdrawn, "Withdraw function failed"); + return withdrawTxObj.events.LogFundWithdrawn.returnValues; + }) + .then((eventValues) => { + assert.strictEqual(eventValues.withdrawer, receiver_1, "withdrawer address is not equal to expectede"); + assert.strictEqual(eventValues.withdrawn, _amountToWithdraw.toString(), "Withdrawn amount is not equal to expected"); }); }); @@ -78,20 +78,16 @@ contract("Splitter", (accounts) => { }); it("should withdraw exact amount assigned in storage", async () => { - //split await splitter.contract.methods.split(receiver_1, receiver_2).send({ from: fundSender, value: 20, }); - //fetch before withdrawal - let _fundBeforeWithdrawal = await splitter.accountBalances.call(receiver_1); + const _fundBeforeWithdrawal = await splitter.accountBalances.call(receiver_1); - //withdraw - let txObj = await splitter.contract.methods.withdraw().send({ from: receiver_1 }); + const txObj = await splitter.contract.methods.withdraw().send({ from: receiver_1 }); - //fetch logged withdrawn - let { withdrawn } = txObj.events.LogFundWithdrawn.returnValues; + const { withdrawn } = txObj.events.LogFundWithdrawn.returnValues; assert.strictEqual(_fundBeforeWithdrawal.toString(10), withdrawn, "withdrawn is not equal to amount before Withdrawal"); }); From 9c048dc5fedeeb410d74a230033d24a09e3b7ef9 Mon Sep 17 00:00:00 2001 From: 0surface Date: Thu, 5 Nov 2020 10:46:36 +0000 Subject: [PATCH 04/12] add test, verify recipient balance on many splits --- test/splitter_split_tests.js | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/test/splitter_split_tests.js b/test/splitter_split_tests.js index a468c70..591304e 100644 --- a/test/splitter_split_tests.js +++ b/test/splitter_split_tests.js @@ -1,5 +1,6 @@ const Splitter = artifacts.require("Splitter"); const truffleAssert = require("truffle-assertions"); +const BigNumber = require("bignumber.js"); contract("Splitter", (accounts) => { before(async () => { @@ -105,6 +106,31 @@ contract("Splitter", (accounts) => { }); }); + it("Recipient get owed amount compounded on multiple splits", () => { + const _sentAmount = 20; + const _splitAmount = 10; + const splitCount = 3; + + return splitter.contract.methods + .split(receiver_1, receiver_2) + .send({ from: fundSender, value: _sentAmount }) + .then(() => { + return splitter.contract.methods.split(receiver_1, receiver_2).send({ from: fundSender, value: _sentAmount }); + }) + .then(() => { + return splitter.contract.methods.split(receiver_1, receiver_2).send({ from: fundSender, value: _sentAmount }); + }) + .then(() => { + return splitter.accountBalances.call(receiver_1); + }) + .then((receiver1Balance) => { + const expected = new BigNumber(splitCount * _splitAmount); + const actual = new BigNumber(receiver1Balance); + assert.isTrue(actual.isEqualTo(expected), "First receiver has expected owed balance"); + assert.strictEqual(actual.toString(10), expected.toString(10), "First receiver did not get owed split values"); + }); + }); + it("reverts when a receiver null address", async () => { await truffleAssert.reverts( splitter.contract.methods.split(nullAddress, receiver_2).send({ From 8c10fcf10f87e7d002caa3c874045a0a412b5d14 Mon Sep 17 00:00:00 2001 From: 0surface Date: Thu, 5 Nov 2020 11:13:29 +0000 Subject: [PATCH 05/12] fix gas price sourcing --- test/splitter_withdraw_tests.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/splitter_withdraw_tests.js b/test/splitter_withdraw_tests.js index 6d36f71..f6e2b19 100644 --- a/test/splitter_withdraw_tests.js +++ b/test/splitter_withdraw_tests.js @@ -52,12 +52,12 @@ contract("Splitter", (accounts) => { await splitter.contract.methods.split(receiver_1, receiver_2).send({ from: fundSender, value: _sentAmount }); - const _gasPrice = await web3.eth.getGasPrice(); - const withdrawTxObj = await splitter.contract.methods.withdraw().send({ from: receiver_2 }); - const _gasAmount = withdrawTxObj.gasUsed; + const withdrawTx = await web3.eth.getTransaction(withdrawTxObj.transactionHash); + const _gasPrice = withdrawTx.gasPrice; + const weiAfterWithdraw = await web3.eth.getBalance(receiver_2); const bn_gasPrice = new BigNumber(_gasPrice); From 1a9cc473782fccc98b7b4f72e556a07ff11d2fbf Mon Sep 17 00:00:00 2001 From: 0surface Date: Thu, 5 Nov 2020 11:46:36 +0000 Subject: [PATCH 06/12] use chai-bn --- package-lock.json | 194 +++++++++++++++++++++++++++++++- package.json | 3 + test/splitter_split_tests.js | 13 ++- test/splitter_withdraw_tests.js | 24 ++-- 4 files changed, 217 insertions(+), 17 deletions(-) diff --git a/package-lock.json b/package-lock.json index facaf16..019ddda 100644 --- a/package-lock.json +++ b/package-lock.json @@ -57,6 +57,13 @@ "@ethersproject/logger": "^5.0.5", "@ethersproject/rlp": "^5.0.3", "bn.js": "^4.4.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } } }, "@ethersproject/base64": { @@ -75,6 +82,13 @@ "@ethersproject/bytes": "^5.0.4", "@ethersproject/logger": "^5.0.5", "bn.js": "^4.4.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } } }, "@ethersproject/bytes": { @@ -653,6 +667,13 @@ "inherits": "^2.0.1", "minimalistic-assert": "^1.0.0", "safer-buffer": "^2.1.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } } }, "assert": { @@ -866,9 +887,10 @@ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" }, "bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", - "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.3.tgz", + "integrity": "sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==", + "dev": true }, "body-parser": { "version": "1.19.0", @@ -1000,6 +1022,13 @@ "requires": { "bn.js": "^4.1.0", "randombytes": "^2.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } } }, "browserify-sign": { @@ -1237,6 +1266,26 @@ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" }, + "chai": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", + "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "pathval": "^1.1.0", + "type-detect": "^4.0.5" + } + }, + "chai-bn": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/chai-bn/-/chai-bn-0.2.1.tgz", + "integrity": "sha512-01jt2gSXAw7UYFPT5K8d7HYjdXj2vyeIuE+0T/34FWzlNcVbs1JkPxRu7rYMfQnJhrHT8Nr6qjSf5ZwwLU2EYg==", + "dev": true + }, "chalk": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", @@ -1247,6 +1296,12 @@ "supports-color": "^7.1.0" } }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true + }, "chokidar": { "version": "3.4.2", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.2.tgz", @@ -1621,6 +1676,13 @@ "requires": { "bn.js": "^4.1.0", "elliptic": "^6.5.3" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } } }, "create-hash": { @@ -1836,6 +1898,15 @@ } } }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, "deep-equal": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", @@ -2056,6 +2127,13 @@ "bn.js": "^4.1.0", "miller-rabin": "^4.0.0", "randombytes": "^2.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } } }, "dns-equal": { @@ -2137,6 +2215,13 @@ "inherits": "^2.0.1", "minimalistic-assert": "^1.0.0", "minimalistic-crypto-utils": "^1.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } } }, "emoji-regex": { @@ -2410,6 +2495,13 @@ "servify": "^0.1.12", "ws": "^3.0.0", "xhr-request-promise": "^0.1.2" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } } }, "ethereum-bloom-filters": { @@ -2489,6 +2581,13 @@ "ethereum-cryptography": "^0.1.3", "ethjs-util": "0.1.6", "rlp": "^2.2.3" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } } }, "ethers": { @@ -2507,6 +2606,11 @@ "xmlhttprequest": "1.8.0" }, "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + }, "js-sha3": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", @@ -3062,6 +3166,12 @@ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true + }, "get-intrinsic": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.1.tgz", @@ -4275,6 +4385,13 @@ "requires": { "bn.js": "^4.0.0", "brorand": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } } }, "mime": { @@ -5025,6 +5142,12 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, + "pathval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", + "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", + "dev": true + }, "pbkdf2": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz", @@ -5227,6 +5350,13 @@ "parse-asn1": "^5.0.0", "randombytes": "^2.0.1", "safe-buffer": "^5.1.2" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } } }, "pump": { @@ -5555,6 +5685,13 @@ "integrity": "sha512-HAfAmL6SDYNWPUOJNrM500x4Thn4PZsEy5pijPh40U9WfNk0z15hUYzO9xVIMAdIHdFtD8CBDHd75Td1g36Mjg==", "requires": { "bn.js": "^4.11.1" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } } }, "run-queue": { @@ -6775,6 +6912,11 @@ "web3": "1.2.1" }, "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + }, "web3": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/web3/-/web3-1.2.1.tgz", @@ -6821,6 +6963,12 @@ "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, "type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -7598,6 +7746,13 @@ "bn.js": "^4.11.6", "elliptic": "^6.4.0", "xhr-request-promise": "^0.1.2" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } } } } @@ -7641,6 +7796,13 @@ "requires": { "bn.js": "^4.11.9", "web3-utils": "1.3.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } } }, "web3-eth-personal": { @@ -7722,6 +7884,11 @@ "utf8": "3.0.0" }, "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + }, "eth-lib": { "version": "0.2.8", "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.8.tgz", @@ -7862,6 +8029,13 @@ "brorand": "^1.0.1", "hash.js": "^1.0.0", "inherits": "^2.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } } }, "ethers": { @@ -7879,6 +8053,13 @@ "setimmediate": "1.0.4", "uuid": "2.0.1", "xmlhttprequest": "1.8.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } } }, "js-sha3": { @@ -7919,6 +8100,13 @@ "bn.js": "^4.11.6", "elliptic": "^6.4.0", "xhr-request-promise": "^0.1.2" + }, + "dependencies": { + "bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + } } }, "semver": { diff --git a/package.json b/package.json index aa74910..721c066 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,9 @@ "license": "MIT", "devDependencies": { "bignumber.js": "^9.0.1", + "bn.js": "^5.1.3", + "chai": "^4.2.0", + "chai-bn": "^0.2.1", "create-html": "^4.1.0", "file-loader": "^6.2.0", "truffle": "^5.1.50", diff --git a/test/splitter_split_tests.js b/test/splitter_split_tests.js index 591304e..f6d3700 100644 --- a/test/splitter_split_tests.js +++ b/test/splitter_split_tests.js @@ -1,6 +1,10 @@ const Splitter = artifacts.require("Splitter"); const truffleAssert = require("truffle-assertions"); -const BigNumber = require("bignumber.js"); +const chai = require("chai"); +const BN = require("bn.js"); + +// Enable and inject BN dependency +chai.use(require("chai-bn")(BN)); contract("Splitter", (accounts) => { before(async () => { @@ -124,9 +128,10 @@ contract("Splitter", (accounts) => { return splitter.accountBalances.call(receiver_1); }) .then((receiver1Balance) => { - const expected = new BigNumber(splitCount * _splitAmount); - const actual = new BigNumber(receiver1Balance); - assert.isTrue(actual.isEqualTo(expected), "First receiver has expected owed balance"); + const expected = new BN(splitCount * _splitAmount); + const actual = new BN(receiver1Balance); + + assert.isTrue(actual.eq(expected), "First receiver has expected owed balance"); assert.strictEqual(actual.toString(10), expected.toString(10), "First receiver did not get owed split values"); }); }); diff --git a/test/splitter_withdraw_tests.js b/test/splitter_withdraw_tests.js index f6e2b19..16d78a8 100644 --- a/test/splitter_withdraw_tests.js +++ b/test/splitter_withdraw_tests.js @@ -1,6 +1,10 @@ const Splitter = artifacts.require("Splitter"); -const BigNumber = require("bignumber.js"); const truffleAssert = require("truffle-assertions"); +const chai = require("chai"); +const BN = require("bn.js"); + +// Enable and inject BN dependency +chai.use(require("chai-bn")(BN)); contract("Splitter", (accounts) => { let splitter; @@ -60,18 +64,18 @@ contract("Splitter", (accounts) => { const weiAfterWithdraw = await web3.eth.getBalance(receiver_2); - const bn_gasPrice = new BigNumber(_gasPrice); - const bn_gasAmount = new BigNumber(_gasAmount); - const gasCost = bn_gasPrice.times(bn_gasAmount); + const bn_gasPrice = new BN(_gasPrice); + const bn_gasAmount = new BN(_gasAmount); + const gasCost = bn_gasPrice.mul(bn_gasAmount); - const owed = new BigNumber(_owedAmount); - const beforeBalance = new BigNumber(weiBeforeWithdraw); - const afterBalance = new BigNumber(weiAfterWithdraw); + const owed = new BN(_owedAmount); + const beforeBalance = new BN(weiBeforeWithdraw); + const afterBalance = new BN(weiAfterWithdraw); - const expectedAfterBalance = beforeBalance.plus(owed).minus(gasCost); + const expectedAfterBalance = beforeBalance.add(owed).sub(gasCost); - //Use BigNumber methods - assert.isTrue(afterBalance.isEqualTo(expectedAfterBalance), "withdrawer didn't get their exact owed amount"); + //Use chai-bn + assert.isTrue(afterBalance.eq(expectedAfterBalance), "withdrawer didn't get their exact owed amount"); //Direct comparision assert.strictEqual(expectedAfterBalance.toString(10), afterBalance.toString(10), "withdrawer didn't get exact owed amount"); From d45322b35e048f6194a1e2da81a874c339dbe589 Mon Sep 17 00:00:00 2001 From: 0surface Date: Thu, 5 Nov 2020 17:20:24 +0000 Subject: [PATCH 07/12] use, assert with chai & chai BN --- package-lock.json | 6 ------ package.json | 1 - test/splitter_split_tests.js | 7 +++---- test/splitter_withdraw_tests.js | 9 +++------ 4 files changed, 6 insertions(+), 17 deletions(-) diff --git a/package-lock.json b/package-lock.json index 019ddda..25efde7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -886,12 +886,6 @@ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" }, - "bn.js": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.3.tgz", - "integrity": "sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==", - "dev": true - }, "body-parser": { "version": "1.19.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", diff --git a/package.json b/package.json index 721c066..5ef7128 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,6 @@ "license": "MIT", "devDependencies": { "bignumber.js": "^9.0.1", - "bn.js": "^5.1.3", "chai": "^4.2.0", "chai-bn": "^0.2.1", "create-html": "^4.1.0", diff --git a/test/splitter_split_tests.js b/test/splitter_split_tests.js index f6d3700..2efd6f0 100644 --- a/test/splitter_split_tests.js +++ b/test/splitter_split_tests.js @@ -1,10 +1,11 @@ const Splitter = artifacts.require("Splitter"); const truffleAssert = require("truffle-assertions"); const chai = require("chai"); -const BN = require("bn.js"); +const { BN } = web3.utils.BN; // Enable and inject BN dependency chai.use(require("chai-bn")(BN)); +const { assert } = chai; contract("Splitter", (accounts) => { before(async () => { @@ -130,9 +131,7 @@ contract("Splitter", (accounts) => { .then((receiver1Balance) => { const expected = new BN(splitCount * _splitAmount); const actual = new BN(receiver1Balance); - - assert.isTrue(actual.eq(expected), "First receiver has expected owed balance"); - assert.strictEqual(actual.toString(10), expected.toString(10), "First receiver did not get owed split values"); + chai.expect(actual).to.be.a.bignumber.that.equals(expected); }); }); diff --git a/test/splitter_withdraw_tests.js b/test/splitter_withdraw_tests.js index 16d78a8..a03010e 100644 --- a/test/splitter_withdraw_tests.js +++ b/test/splitter_withdraw_tests.js @@ -1,10 +1,11 @@ const Splitter = artifacts.require("Splitter"); const truffleAssert = require("truffle-assertions"); const chai = require("chai"); -const BN = require("bn.js"); +const { BN } = web3.utils.BN; // Enable and inject BN dependency chai.use(require("chai-bn")(BN)); +const { assert } = chai; contract("Splitter", (accounts) => { let splitter; @@ -74,11 +75,7 @@ contract("Splitter", (accounts) => { const expectedAfterBalance = beforeBalance.add(owed).sub(gasCost); - //Use chai-bn - assert.isTrue(afterBalance.eq(expectedAfterBalance), "withdrawer didn't get their exact owed amount"); - - //Direct comparision - assert.strictEqual(expectedAfterBalance.toString(10), afterBalance.toString(10), "withdrawer didn't get exact owed amount"); + chai.expect(afterBalance).to.be.a.bignumber.that.equals(expectedAfterBalance); }); it("should withdraw exact amount assigned in storage", async () => { From 52a00bbc60ed270cc5035bd510529df523c42fca Mon Sep 17 00:00:00 2001 From: 0surface Date: Thu, 5 Nov 2020 18:13:56 +0000 Subject: [PATCH 08/12] add Pausable contract --- .gitignore | 1 + contracts/Pausable.sol | 44 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 contracts/Pausable.sol diff --git a/.gitignore b/.gitignore index b686266..11d0447 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ build/contracts/SafeMath.json build/contracts/Owned.json build/app/index.html build/app/js/app.js +build/contracts/Pausable.json diff --git a/contracts/Pausable.sol b/contracts/Pausable.sol new file mode 100644 index 0000000..ca2b58a --- /dev/null +++ b/contracts/Pausable.sol @@ -0,0 +1,44 @@ +pragma solidity 0.5.16; + +import "./Owned.sol"; + +contract Pausable is Owned { + + event LogContractPaused(); + event LogContractUnpaused(); + + bool public paused = false; + + + /** + * @dev Modifier to make a function callable only when the contract is not paused. + */ + modifier whenNotPaused() { + require(!paused, "Contract is paused"); + _; + } + + /** + * @dev Modifier to make a function callable only when the contract is paused. + */ + modifier whenPaused() { + require(paused, "Contract is not paused"); + _; + } + + /** + * @dev called by the owner to pause, triggers stopped state + */ + function pause() onlyOwner whenNotPaused public { + paused = true; + emit LogContractPaused(); + } + + /** + * @dev called by the owner to unpause, returns to normal state + */ + function unpause() onlyOwner whenPaused public { + paused = false; + emit LogContractUnpaused(); + } +} \ No newline at end of file From 674ec44e585ee0c56477652f73e302895d170d6f Mon Sep 17 00:00:00 2001 From: 0surface Date: Thu, 5 Nov 2020 18:14:17 +0000 Subject: [PATCH 09/12] implement Pauseable on Splitter contract --- contracts/Owned.sol | 4 ++-- contracts/Splitter.sol | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/contracts/Owned.sol b/contracts/Owned.sol index 038a8c6..d027494 100644 --- a/contracts/Owned.sol +++ b/contracts/Owned.sol @@ -9,7 +9,7 @@ contract Owned { event LogOwnerChanged(address indexed oldOwner, address indexed newOwner); - modifier isOwner() { + modifier onlyOwner() { require(msg.sender == owner, "Caller is not owner"); _; } @@ -26,7 +26,7 @@ contract Owned { * @dev Change owner * @param newOwner address of new owner */ - function changeOwner(address newOwner) public isOwner { + function changeOwner(address newOwner) public onlyOwner { require(newOwner != address(0), "Can't assign ownership to null address"); owner = newOwner; emit LogOwnerChanged(owner, newOwner); diff --git a/contracts/Splitter.sol b/contracts/Splitter.sol index 4472278..81557c8 100644 --- a/contracts/Splitter.sol +++ b/contracts/Splitter.sol @@ -2,13 +2,13 @@ pragma solidity 0.5.16; import "./SafeMath.sol"; -import "./Owned.sol"; +import "./Pausable.sol"; /* @title Splitter @dev split balance of sender into two & make funds available for withdrawal */ -contract Splitter is Owned { +contract Splitter is Pausable { using SafeMath for uint; mapping(address => uint256) public accountBalances; @@ -26,7 +26,7 @@ contract Splitter is Owned { /* @dev split funds and record in storage */ - function split(address _receiver1, address _receiver2) public payable { + function split(address _receiver1, address _receiver2) public whenNotPaused payable { require( _receiver1 != address(0) && _receiver2 != address(0), "Can't split money to null address" @@ -46,7 +46,7 @@ contract Splitter is Owned { /* @dev Allow fund receiver to withdraw */ - function withdraw() public { + function withdraw() whenNotPaused public { uint256 withdrawerBalance = accountBalances[msg.sender]; require(withdrawerBalance > 0, "No funds to withdraw"); From 43afcfc80ef005e8374cf983efab67d9ec7d1b34 Mon Sep 17 00:00:00 2001 From: 0surface Date: Thu, 5 Nov 2020 18:15:44 +0000 Subject: [PATCH 10/12] test methods revert when contract is paused --- test/splitter_split_tests.js | 21 +++++++++++++++++++++ test/splitter_withdraw_tests.js | 15 +++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/test/splitter_split_tests.js b/test/splitter_split_tests.js index 2efd6f0..ee4c812 100644 --- a/test/splitter_split_tests.js +++ b/test/splitter_split_tests.js @@ -30,6 +30,27 @@ contract("Splitter", (accounts) => { assert.strictEqual(parseInt(balance), 0, "contract shouldn't have funds on deployment"); }); + it("should revert split method call while contract is paused", async () => { + return splitter.contract.methods + .pause() + .send({ from: deployer }) + .then(() => { + return splitter.paused.call(); + }) + .then((paused) => { + assert.isTrue(paused, "contract failed to pause"); + }) + .then(() => { + truffleAssert.reverts( + splitter.contract.methods.split(receiver_1, receiver_2).send({ + from: fundSender, + value: 21, + }), + "Contract is paused" + ); + }); + }); + it("split method emits event", () => { const _sentAmount = 21; return splitter.contract.methods diff --git a/test/splitter_withdraw_tests.js b/test/splitter_withdraw_tests.js index a03010e..cc6cd52 100644 --- a/test/splitter_withdraw_tests.js +++ b/test/splitter_withdraw_tests.js @@ -117,4 +117,19 @@ contract("Splitter", (accounts) => { assert.equal(receiver1Balance.toString(10), 0, "receiver balance record is NOT set to zero after withdrwal"); }); }); + + it("should revert withdraw method call while contract is paused", async () => { + return splitter.contract.methods + .pause() + .send({ from: deployer }) + .then(() => { + return splitter.paused.call(); + }) + .then((paused) => { + assert.isTrue(paused, "contract failed to pause"); + }) + .then(() => { + truffleAssert.reverts(splitter.contract.methods.withdraw().send({ from: receiver_1 }), "Contract is paused"); + }); + }); }); From 707cdbabe2fc8ece6665ceea41403713dae9c5ea Mon Sep 17 00:00:00 2001 From: 0surface Date: Thu, 5 Nov 2020 20:01:19 +0000 Subject: [PATCH 11/12] simplify expressions --- test/splitter_split_tests.js | 4 ++-- test/splitter_withdraw_tests.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/splitter_split_tests.js b/test/splitter_split_tests.js index ee4c812..a64ec1c 100644 --- a/test/splitter_split_tests.js +++ b/test/splitter_split_tests.js @@ -5,7 +5,7 @@ const { BN } = web3.utils.BN; // Enable and inject BN dependency chai.use(require("chai-bn")(BN)); -const { assert } = chai; +const { assert, expect } = chai; contract("Splitter", (accounts) => { before(async () => { @@ -152,7 +152,7 @@ contract("Splitter", (accounts) => { .then((receiver1Balance) => { const expected = new BN(splitCount * _splitAmount); const actual = new BN(receiver1Balance); - chai.expect(actual).to.be.a.bignumber.that.equals(expected); + expect(actual).to.be.a.bignumber.that.equals(expected); }); }); diff --git a/test/splitter_withdraw_tests.js b/test/splitter_withdraw_tests.js index cc6cd52..8ced40f 100644 --- a/test/splitter_withdraw_tests.js +++ b/test/splitter_withdraw_tests.js @@ -5,7 +5,7 @@ const { BN } = web3.utils.BN; // Enable and inject BN dependency chai.use(require("chai-bn")(BN)); -const { assert } = chai; +const { assert, expect } = chai; contract("Splitter", (accounts) => { let splitter; @@ -75,7 +75,7 @@ contract("Splitter", (accounts) => { const expectedAfterBalance = beforeBalance.add(owed).sub(gasCost); - chai.expect(afterBalance).to.be.a.bignumber.that.equals(expectedAfterBalance); + expect(afterBalance).to.be.a.bignumber.that.equals(expectedAfterBalance); }); it("should withdraw exact amount assigned in storage", async () => { From 3bf0628cc7d8f7c15f822cb74177b29872110d9a Mon Sep 17 00:00:00 2001 From: 0surface Date: Thu, 5 Nov 2020 20:42:49 +0000 Subject: [PATCH 12/12] ensure contract is paused, before testing revert --- test/splitter_split_tests.js | 3 ++- test/splitter_withdraw_tests.js | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/test/splitter_split_tests.js b/test/splitter_split_tests.js index a64ec1c..20a16a2 100644 --- a/test/splitter_split_tests.js +++ b/test/splitter_split_tests.js @@ -34,7 +34,8 @@ contract("Splitter", (accounts) => { return splitter.contract.methods .pause() .send({ from: deployer }) - .then(() => { + .then((txObj) => { + assert.isDefined(txObj.events.LogContractPaused, "pause call did not get mined"); return splitter.paused.call(); }) .then((paused) => { diff --git a/test/splitter_withdraw_tests.js b/test/splitter_withdraw_tests.js index 8ced40f..adb0025 100644 --- a/test/splitter_withdraw_tests.js +++ b/test/splitter_withdraw_tests.js @@ -122,7 +122,8 @@ contract("Splitter", (accounts) => { return splitter.contract.methods .pause() .send({ from: deployer }) - .then(() => { + .then((txObj) => { + assert.isDefined(txObj.events.LogContractPaused, "pause call did not get mined"); return splitter.paused.call(); }) .then((paused) => {