Skip to content

Commit

Permalink
inherit pausable from OZ
Browse files Browse the repository at this point in the history
  • Loading branch information
HristiyanG committed Dec 4, 2020
1 parent 31debf0 commit e80ec13
Show file tree
Hide file tree
Showing 5 changed files with 279 additions and 13 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,7 @@ node_modules
.idea/

#Test Coverage
coverage*
coverage*

#Personal Preferences
.vscode
19 changes: 16 additions & 3 deletions contracts/Cashier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ pragma solidity >=0.6.6 <0.7.0;

import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/Access/Ownable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Pausable.sol";
import "./VoucherKernel.sol";
import "./usingHelpers.sol";

Expand All @@ -14,7 +15,7 @@ import "./usingHelpers.sol";
* @dev Warning: the contract hasn't been audited yet!
* Roughly following OpenZeppelin's Escrow at https://github.com/OpenZeppelin/openzeppelin-solidity/contracts/payment/
*/
contract Cashier is usingHelpers, ReentrancyGuard, Ownable {
contract Cashier is usingHelpers, ReentrancyGuard, Ownable, Pausable {
using Address for address payable;
using SafeMath for uint;

Expand Down Expand Up @@ -77,7 +78,16 @@ contract Cashier is usingHelpers, ReentrancyGuard, Ownable {
voucherKernel = VoucherKernel(_voucherKernel);
}


function pause() external onlyOwner {
_pause();
voucherKernel.pause();
}

function unpause() external onlyOwner {
_unpause();
voucherKernel.unpause();
}

/**
* @notice Issuer/Seller offers promises as supply tokens and needs to escrow the deposit
@param _assetTitle Name of the asset
Expand All @@ -99,6 +109,7 @@ contract Cashier is usingHelpers, ReentrancyGuard, Ownable {
)
external
payable
whenNotPaused
{
bytes32 promiseId;

Expand Down Expand Up @@ -133,6 +144,7 @@ contract Cashier is usingHelpers, ReentrancyGuard, Ownable {
external
payable
nonReentrant
whenNotPaused
{
uint256 weiReceived = msg.value;

Expand All @@ -159,6 +171,7 @@ contract Cashier is usingHelpers, ReentrancyGuard, Ownable {
function withdraw(uint256[] calldata _tokenIdVouchers)
external
nonReentrant
whenNotPaused
{
//TODO: more checks
//TODO: check to pass 2 diff holders and how the amounts will be distributed
Expand Down
18 changes: 15 additions & 3 deletions contracts/VoucherKernel.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
pragma solidity >=0.6.6 <0.7.0;

import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/Access/Ownable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Pausable.sol";
import "./ERC1155ERC721.sol";
import "./usingHelpers.sol";

Expand All @@ -17,7 +18,7 @@ import "./usingHelpers.sol";
* - The usage of block.timestamp is honored since vouchers are defined with day-precision and the demo app is not covering all edge cases.
* See: https://ethereum.stackexchange.com/questions/5924/how-do-ethereum-mining-nodes-maintain-a-time-consistent-with-the-network/5931#5931
*/
contract VoucherKernel is Ownable, usingHelpers {
contract VoucherKernel is Ownable, Pausable, usingHelpers {
using Address for address;
//using Counters for Counters.Counter;
//Counters.Counter private voucherTokenId; //unique IDs for voucher tokens
Expand Down Expand Up @@ -163,7 +164,14 @@ contract VoucherKernel is Ownable, usingHelpers {
complainPeriod = 7 * 1 days;
cancelFaultPeriod = 7 * 1 days;
}


function pause() external onlyFromCashier {
_pause();
}

function unpause() external onlyFromCashier {
_unpause();
}

/**
* @notice Creating a new promise for goods or services.
Expand Down Expand Up @@ -357,6 +365,7 @@ contract VoucherKernel is Ownable, usingHelpers {
*/
function redeem(uint256 _tokenIdVoucher)
external
whenNotPaused
onlyVoucherOwner(_tokenIdVoucher)
{
//check status
Expand Down Expand Up @@ -385,6 +394,7 @@ contract VoucherKernel is Ownable, usingHelpers {
*/
function refund(uint256 _tokenIdVoucher)
external
whenNotPaused
onlyVoucherOwner(_tokenIdVoucher)
{
require(isStateCommitted(vouchersStatus[_tokenIdVoucher].status), "INAPPLICABLE_STATUS"); //hex"18" FISSION.code(FISSION.Category.Permission, FISSION.Status.NotApplicatableToCurrentState)
Expand All @@ -405,6 +415,7 @@ contract VoucherKernel is Ownable, usingHelpers {
*/
function complain(uint256 _tokenIdVoucher)
external
whenNotPaused
onlyVoucherOwner(_tokenIdVoucher)
{
require(!isStatus(vouchersStatus[_tokenIdVoucher].status, idxComplain), "ALREADY_COMPLAINED"); //hex"48" FISSION.code(FISSION.Category.Availability, FISSION.Status.AlreadyDone)
Expand Down Expand Up @@ -461,6 +472,7 @@ contract VoucherKernel is Ownable, usingHelpers {
*/
function cancelOrFault(uint256 _tokenIdVoucher)
external
whenNotPaused
{
require(getVoucherIssuer(_tokenIdVoucher) == msg.sender,"UNAUTHORIZED_COF"); //hex"10" FISSION.code(FISSION.Category.Permission, FISSION.Status.Disallowed_Stop)

Expand Down
238 changes: 238 additions & 0 deletions test/5_pausing_contracts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
const chai = require('chai')
let chaiAsPromised = require("chai-as-promised")
chai.use(chaiAsPromised)
const assert = chai.assert

const BN = web3.utils.BN
const Utils = require('../testHelpers/utils')
let utils

const ERC1155ERC721 = artifacts.require("ERC1155ERC721")
const VoucherKernel = artifacts.require("VoucherKernel")
const Cashier = artifacts.require("Cashier")

const helpers = require("../testHelpers/constants")
const timemachine = require('../testHelpers/timemachine')
const truffleAssert = require('truffle-assertions')

let TOKEN_SUPPLY_ID
let VOUCHER_ID

contract("Cashier withdrawals ", async accounts => {

let Deployer = accounts[0] //0xD9995BAE12FEe327256FFec1e3184d492bD94C31
let Seller = accounts[1] //0xd4Fa489Eacc52BA59438993f37Be9fcC20090E39
let Buyer = accounts[2] //0x760bf27cd45036a6C486802D30B5D90CfFBE31FE
let Attacker = accounts[3] //0x56A32fFf5E5A8B40d6A21538579fB8922DF5258c

let contractERC1155ERC721, contractVoucherKernel, contractCashier
let timestamp

async function deployContracts() {
contractERC1155ERC721 = await ERC1155ERC721.new()
contractVoucherKernel = await VoucherKernel.new(contractERC1155ERC721.address)
contractCashier = await Cashier.new(contractVoucherKernel.address)

await contractERC1155ERC721.setApprovalForAll(contractVoucherKernel.address, 'true')
await contractERC1155ERC721.setVoucherKernelAddress(contractVoucherKernel.address)
await contractVoucherKernel.setCashierAddress(contractCashier.address)

await contractVoucherKernel.setComplainPeriod(60); //60 seconds
await contractVoucherKernel.setCancelFaultPeriod(60); //60 seconds

utils = Utils.getInstance(contractERC1155ERC721, contractVoucherKernel, contractCashier)
timestamp = await Utils.getCurrTimestamp()
}


describe('Pausing Scenarios', function () {

describe.only("CASHIER", () => {

before(async () => {
await deployContracts();
})


it("Should not be paused on deployment", async () => {
const isPaused = await contractCashier.paused();
assert.isFalse(isPaused)
});

it("Owner should pause the contract", async () => {
await contractCashier.pause();

const isPaused = await contractCashier.paused();
assert.isTrue(isPaused)
});

it("Owner should unpause the contract", async () => {
await contractCashier.pause();
await contractCashier.unpause();

const isPaused = await contractCashier.paused();
assert.isFalse(isPaused)
});

it("[NEGATIVE] Attacker should not be able to pause the contract", async () => {
await truffleAssert.reverts(
contractCashier.pause({ from: Attacker }),
truffleAssert.ErrorType.REVERT
)
});

it("[NEGATIVE] Attacker should not be able to unpause the contract", async () => {
await contractCashier.pause();

await truffleAssert.reverts(
contractCashier.unpause({ from: Attacker }),
truffleAssert.ErrorType.REVERT
)
});

it("[NEGATIVE] Should not create voucher supply when contract is paused", async () => {
await contractCashier.pause();

await truffleAssert.reverts(
utils.requestCreateOrder(Seller, timestamp, timestamp + helpers.SECONDS_IN_DAY),
truffleAssert.ErrorType.REVERT
)
})

it("Should create voucher supply when contract is unpaused", async () => {
TOKEN_SUPPLY_ID = await utils.requestCreateOrder(Seller, timestamp, timestamp + helpers.SECONDS_IN_DAY)

assert.isNotEmpty(TOKEN_SUPPLY_ID)
})

//TODO When all tests are run below 3 will fail, but this will be fixed from PR#16 when get merged
xit("[NEGATIVE] Should not create voucherID from Buyer when paused", async () => {
TOKEN_SUPPLY_ID = await utils.requestCreateOrder(Seller, timestamp, timestamp + helpers.SECONDS_IN_DAY)

await contractCashier.pause();

await truffleAssert.reverts(
utils.commitToBuy(Buyer, Seller, TOKEN_SUPPLY_ID),
truffleAssert.ErrorType.REVERT
)
})

xit("[NEGATIVE] Should not process withdrawals when paused", async () => {
TOKEN_SUPPLY_ID = await utils.requestCreateOrder(Seller, timestamp, timestamp + helpers.SECONDS_IN_DAY)

const voucherID = await utils.commitToBuy(Buyer, Seller, TOKEN_SUPPLY_ID)
await utils.refund(voucherID, Buyer)

await timemachine.advanceTimeSeconds(60)
await utils.finalize(voucherID, Deployer)

await contractCashier.pause();

await truffleAssert.reverts(
utils.withdraw(voucherID, Deployer),
truffleAssert.ErrorType.REVERT
)
})

})

describe.only("VOUCHER KERNEL", () => {

before(async () => {
await deployContracts();

// Create Voucher Supply of 10
TOKEN_SUPPLY_ID = await utils.requestCreateOrder(Seller, timestamp, timestamp + helpers.SECONDS_IN_DAY)
})

it("Should not be paused on deployment", async () => {
const isPaused = await contractVoucherKernel.paused();
assert.isFalse(isPaused)
});

it("Should be paused from cashier", async () => {
await contractCashier.pause();

const isPaused = await contractVoucherKernel.paused();
assert.isTrue(isPaused)
});

it("Should be unpaused from cashier", async () => {
await contractCashier.pause();
await contractCashier.unpause();

const isPaused = await contractVoucherKernel.paused();
assert.isFalse(isPaused)
});

it("[NEGATIVE] Pause should not be called directly", async () => {
await truffleAssert.reverts(
contractVoucherKernel.pause(),
truffleAssert.ErrorType.REVERT
)
});

it("[NEGATIVE] Pause should not be called directly", async () => {
await truffleAssert.reverts(
contractVoucherKernel.unpause(),
truffleAssert.ErrorType.REVERT
)
});

it("[NEGATIVE] Should not process refund when paused", async () => {
VOUCHER_ID = await utils.commitToBuy(Buyer, Seller, TOKEN_SUPPLY_ID)

await contractCashier.pause();

await truffleAssert.reverts(
utils.refund(VOUCHER_ID, Buyer),
truffleAssert.ErrorType.REVERT
)
})

it("[NEGATIVE] Should not process complain when paused", async () => {
VOUCHER_ID = await utils.commitToBuy(Buyer, Seller, TOKEN_SUPPLY_ID)

await utils.refund(VOUCHER_ID, Buyer)

await contractCashier.pause();

await truffleAssert.reverts(
utils.complain(VOUCHER_ID, Buyer),
truffleAssert.ErrorType.REVERT
)
})

it("[NEGATIVE] Should not process redeem when paused", async () => {
VOUCHER_ID = await utils.commitToBuy(Buyer, Seller, TOKEN_SUPPLY_ID)

await contractCashier.pause();

await truffleAssert.reverts(
utils.redeem(VOUCHER_ID, Buyer),
truffleAssert.ErrorType.REVERT
)
})

it("[NEGATIVE] Should not process cancel when paused", async () => {
VOUCHER_ID = await utils.commitToBuy(Buyer, Seller, TOKEN_SUPPLY_ID);
await utils.redeem(VOUCHER_ID, Buyer)

await contractCashier.pause();

await truffleAssert.reverts(
utils.cancel(VOUCHER_ID, Seller),
truffleAssert.ErrorType.REVERT
)
})
})

afterEach(async () => {
const isPaused = await contractCashier.paused();
if (isPaused) {
await contractCashier.unpause();
}
})
})
})

12 changes: 6 additions & 6 deletions truffle-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,13 +115,13 @@ module.exports = {
solc: {
version: '0.6.6', // Fetch exact version from solc-bin (default: truffle's version)
// docker: true, // Use "0.5.1" you've installed locally with docker (default: false)
// settings: { // See the solidity docs for advice about optimization and evmVersion
// optimizer: {
// enabled: false,
// runs: 200
// },
settings: { // See the solidity docs for advice about optimization and evmVersion
optimizer: {
enabled: true,
runs: 200
},
// evmVersion: "byzantium"
// }
}
},
},
};
Expand Down

0 comments on commit e80ec13

Please sign in to comment.