diff --git a/.gitignore b/.gitignore index a56ca6cb..a595f181 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ node_modules /build .etherlime-store /localDeploy +/run # Secrets .secret @@ -21,8 +22,8 @@ node_modules *.ipr .idea/ -#Test Coverage +# Test Coverage coverage* -#Personal Preferences +# Personal Preferences .vscode \ No newline at end of file diff --git a/Gemfile b/Gemfile index a356e4b0..e5517651 100644 --- a/Gemfile +++ b/Gemfile @@ -1,3 +1,5 @@ source 'https://rubygems.org' gem 'rake', '~> 13.0' +gem 'random-port', '~> 0.5' +gem 'childprocess', '~> 4.0' diff --git a/Gemfile.lock b/Gemfile.lock index 3bd69323..923be140 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,13 +1,17 @@ GEM remote: https://rubygems.org/ specs: + childprocess (4.0.0) rake (13.0.3) + random-port (0.5.1) PLATFORMS x86_64-darwin-19 DEPENDENCIES + childprocess (~> 4.0) rake (~> 13.0) + random-port (~> 0.5) BUNDLED WITH 2.2.6 diff --git a/Rakefile b/Rakefile index f6c80b11..0304c906 100644 --- a/Rakefile +++ b/Rakefile @@ -1,8 +1,61 @@ +require 'random-port' +require 'childprocess' + task :default => :"contracts:compile" +namespace :ganache do + task :start, [:port] do |_, args| + port = args.port.to_s + + puts "Starting ganache on port #{port}..." + process = ChildProcess.build( + './node_modules/.bin/ganache-cli', + '--allowUnlimitedContractSize', + '-p', port) + # process.io.inherit! + process.leader = true + process.detach = true + process.start + + FileUtils.mkdir_p('run/pid') + File.open("run/pid/ganache-#{port}.pid", "w") do |pidfile| + pidfile.write(process.pid) + end + end + + task :stop, [:port] do |_, args| + port = args.port.to_s + + puts "Stopping ganache on port #{port}..." + pid = File.read("run/pid/ganache-#{port}.pid").to_i + + Process.kill('INT', pid) + File.unlink("run/pid/ganache-#{port}.pid") + end +end + namespace :contracts do desc "Compile all contracts" task :compile do sh('npm run compile') end end + +namespace :test do + desc "Run all contract integration tests" + task :integration do + RandomPort::Pool.new.acquire do |port| + begin + Rake::Task[:'ganache:start'].invoke(port) + + puts "Running integration tests against node listening on #{port}..." + sh({ + "HOST" => "127.0.0.1", + "PORT" => "#{port}" + }, 'npm run test:integration') + ensure + Rake::Task[:'ganache:stop'].invoke(port) + end + end + end +end diff --git a/migrations/2_deploy_contracts.js b/migrations/2_deploy_contracts.js index 85b0dd4c..164a21e0 100644 --- a/migrations/2_deploy_contracts.js +++ b/migrations/2_deploy_contracts.js @@ -40,12 +40,8 @@ module.exports = function(deployer, network, accounts) { console.log("Boson Token Deposit Contract Address: ", BosonTokenDeposit.address); }) }) - }); - }) }) }); - - }; diff --git a/package.json b/package.json index 2641d9b8..32ba2c36 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ }, "scripts": { "compile": "truffle compile --all", - "test:unit": "truffle test", + "test:integration": "truffle test --network test", "coverage": "node --max-old-space-size=4096 ./node_modules/.bin/truffle run coverage --network coverage", "migrate-dev": "truffle migrate --network=rinkeby", "verify-dev": "truffle run verify ERC1155ERC721 VoucherKernel Cashier BosonTokenPrice BosonTokenDeposit --network rinkeby" diff --git a/test/1_test_fullpath.js b/test/1_test_fullpath.js index db61a2b8..5eded716 100644 --- a/test/1_test_fullpath.js +++ b/test/1_test_fullpath.js @@ -1,442 +1,608 @@ -const helpers = require("../testHelpers/constants"); -const timemachine = require('../testHelpers/timemachine'); -const truffleAssert = require('truffle-assertions'); -//later consider using https://github.com/OpenZeppelin/openzeppelin-test-helpers - -const ERC1155ERC721 = artifacts.require("ERC1155ERC721"); -const VoucherKernel = artifacts.require("VoucherKernel"); -const Cashier = artifacts.require("Cashier"); -const FundLimitsOracle = artifacts.require('FundLimitsOracle'); - -const config = require('../testHelpers/config.json') +const truffleAssert = require('truffle-assertions') +// later consider using +// https://github.com/OpenZeppelin/openzeppelin-test-helpers +const constants = require("../testHelpers/constants") +const timemachine = require('../testHelpers/timemachine') const Utils = require('../testHelpers/utils') -let snapshot; - -contract("Voucher tests", async accounts => { - let Seller = config.accounts.seller.address - let Buyer = config.accounts.buyer.address - let Attacker = config.accounts.attacker.address - - let contractERC1155ERC721, contractVoucherKernel, contractCashier, contractFundLimitsOracle; - let promiseKey1, promiseKey2; - let order1payment, order1depositSe, order1depositBu; - let ordersCount; - let tokenSupplyKey1, tokenSupplyKey2, tokenVoucherKey1, tokenVoucherKey2; - - before('setup contracts for tests', async () => { - snapshot = await timemachine.takeSnapshot(); - - const timestamp = await Utils.getCurrTimestamp() - helpers.PROMISE_VALID_FROM = timestamp - helpers.PROMISE_VALID_TO = timestamp + 2 * helpers.SECONDS_IN_DAY; - - contractFundLimitsOracle = await FundLimitsOracle.new() - contractERC1155ERC721 = await ERC1155ERC721.new(); - contractVoucherKernel = await VoucherKernel.new(contractERC1155ERC721.address); - contractCashier = await Cashier.new(contractVoucherKernel.address, contractERC1155ERC721.address, contractFundLimitsOracle.address); - - await contractERC1155ERC721.setApprovalForAll(contractVoucherKernel.address, 'true'); - await contractERC1155ERC721.setVoucherKernelAddress(contractVoucherKernel.address); - await contractVoucherKernel.setCashierAddress(contractCashier.address); - - console.log("Seller: " + Seller); - console.log("Buyer: " + Buyer); - console.log("Attacker: " + Attacker + "\n"); +const Accounts = require('../testHelpers/accounts') + +const ERC1155ERC721 = artifacts.require("ERC1155ERC721") +const VoucherKernel = artifacts.require("VoucherKernel") +const Cashier = artifacts.require("Cashier") +const FundLimitsOracle = artifacts.require('FundLimitsOracle') + +let snapshot + +contract("Voucher tests", async accountSet => { + const accounts = new Accounts(accountSet) + + let contractERC1155ERC721, + contractVoucherKernel, + contractCashier, + contractFundLimitsOracle + let tokenSupplyKey1, + tokenSupplyKey2, + tokenVoucherKey1, + tokenVoucherKey2 + + before('setup contracts for tests', async () => { + snapshot = await timemachine.takeSnapshot() + + const timestamp = await Utils.getCurrTimestamp() + constants.PROMISE_VALID_FROM = timestamp + constants.PROMISE_VALID_TO = timestamp + 2 * constants.SECONDS_IN_DAY + + contractFundLimitsOracle = await FundLimitsOracle.new() + contractERC1155ERC721 = await ERC1155ERC721.new() + contractVoucherKernel = await VoucherKernel.new( + contractERC1155ERC721.address) + contractCashier = await Cashier.new( + contractVoucherKernel.address, + contractERC1155ERC721.address, + contractFundLimitsOracle.address) + + await contractERC1155ERC721.setApprovalForAll( + contractVoucherKernel.address, 'true') + await contractERC1155ERC721.setVoucherKernelAddress( + contractVoucherKernel.address) + await contractVoucherKernel.setCashierAddress( + contractCashier.address) + + console.log("Seller: " + accounts.seller) + console.log("Buyer: " + accounts.buyer) + console.log("Attacker: " + accounts.attacker + "\n") + }) + + describe('Direct minting', function () { + it("must fail: unauthorized minting ERC-1155", async () => { + await truffleAssert.reverts( + contractERC1155ERC721.mint(accounts.attacker, 666, 1, []), + truffleAssert.ErrorType.REVERT + ) }) - - describe('Direct minting', function() { - - it("must fail: unauthorized minting ERC-1155", async () => { - await truffleAssert.reverts(contractERC1155ERC721.mint(Attacker, 666, 1, []), - truffleAssert.ErrorType.REVERT - ); - }); - - it("must fail: unauthorized minting ERC-721", async () => { - await truffleAssert.reverts(contractERC1155ERC721.mint(Attacker, 666), - truffleAssert.ErrorType.REVERT - ); - }); - }) - - -//in the prototype, the creation of a promise is merged into creating an order - // describe('Promises (aka offers)', function() { - - // it("adding one new promise", async () => { - // // console.log("helpers.PROMISE_VALID_FROM: ", helpers.PROMISE_VALID_FROM, ", helpers.PROMISE_VALID_TO: ", helpers.PROMISE_VALID_TO); - // await contractVoucherKernel.createTokenSupplyID(helpers.ASSET_TITLE, helpers.ASSET_PIN1, helpers.ASSET_QR1, helpers.PROMISE_VALID_FROM, helpers.PROMISE_VALID_TO, helpers.PROMISE_PRICE1, helpers.PROMISE_DEPOSITSE1, helpers.PROMISE_DEPOSITBU1, helpers.PROMISE_CHALLENGE_PERIOD, helpers.PROMISE_CANCELORFAULT_PERIOD); - - // promiseKey1 = await contractVoucherKernel.promiseKeys.call(0); - - // assert.notEqual(promiseKey1, helpers.ZERO_ADDRESS, "promise not added"); - // }); - - // it("adding second new promise", async () => { - // await contractVoucherKernel.createTokenSupplyID(helpers.ASSET_TITLE2, helpers.ASSET_PIN2, helpers.ASSET_QR2, helpers.PROMISE_VALID_FROM, helpers.PROMISE_VALID_TO, helpers.PROMISE_PRICE2, helpers.PROMISE_DEPOSITSE2, helpers.PROMISE_DEPOSITBU2, helpers.PROMISE_CHALLENGE_PERIOD, helpers.PROMISE_CANCELORFAULT_PERIOD); - - // promiseKey2 = await contractVoucherKernel.promiseKeys.call(1); - - // assert.notEqual(promiseKey2, helpers.ZERO_ADDRESS, "second promise not added"); - // }); - - // it("must fail: adding new promise with invalid validity", async () => { - // await truffleAssert.reverts(contractVoucherKernel.createTokenSupplyID(helpers.ASSET_TITLE, helpers.ASSET_PIN1, helpers.ASSET_QR1, helpers.PROMISE_VALID_FROM, helpers.PROMISE_VALID_FROM - 1, helpers.PROMISE_PRICE1, helpers.PROMISE_DEPOSITSE1, helpers.PROMISE_DEPOSITBU1, helpers.PROMISE_CHALLENGE_PERIOD, helpers.PROMISE_CANCELORFAULT_PERIOD), - // truffleAssert.ErrorType.REVERT - // ); - // }); - - // }) - - - describe('Orders (aka supply tokens - ERC1155)', function() { - - it("adding one new order / promise", async () => { - - let txOrder = await contractCashier.requestCreateOrder_ETH_ETH([helpers.PROMISE_VALID_FROM, helpers.PROMISE_VALID_TO, helpers.PROMISE_PRICE1, helpers.PROMISE_DEPOSITSE1, helpers.PROMISE_DEPOSITBU1, helpers.ORDER_QUANTITY1], {from: Seller, to: contractCashier.address, value: helpers.PROMISE_DEPOSITSE1}); - - //would need truffle-events as the event emitted is from a nested contract, so truffle-assert doesn't detect it - // truffleAssert.eventEmitted(txOrder, 'LogOrderCreated', (ev) => { - // tokenSupplyKey = ev._tokenIdSupply; - // return ev._seller === Seller; - // }, "order1 not created successfully"); - - // //instead, we check that the escrow increased for the seller - // let escrowAmount = await contractCashier.getEscrowAmount.call(Seller); - // assert.isAbove(escrowAmount.toNumber(), 0, "seller's escrowed deposit should be more than zero"); - - //move events from VoucherKernel to Cashier: - truffleAssert.eventEmitted(txOrder, 'LogOrderCreated', (ev) => { - tokenSupplyKey1 = ev._tokenIdSupply; - return ev._seller === Seller; - }, "order1 not created successfully"); - - }); - - it("adding second order", async () => { - - let txOrder = await contractCashier.requestCreateOrder_ETH_ETH([helpers.PROMISE_VALID_FROM, helpers.PROMISE_VALID_TO, helpers.PROMISE_PRICE2, helpers.PROMISE_DEPOSITSE2, helpers.PROMISE_DEPOSITBU2, helpers.ORDER_QUANTITY2], {from: Seller, to: contractCashier.address, value: helpers.PROMISE_DEPOSITSE2}); - - truffleAssert.eventEmitted(txOrder, 'LogOrderCreated', (ev) => { - tokenSupplyKey2 = ev._tokenIdSupply; - return ev._seller === Seller; - }, "order2 not created successfully"); - - }); - - - it("fill one order (aka buy a voucher)", async () => { - - let txFillOrder = await contractCashier.requestVoucher_ETH_ETH(tokenSupplyKey1, Seller, {from: Buyer, to: contractCashier.address, value: helpers.PROMISE_PRICE1 + helpers.PROMISE_DEPOSITBU1}); - let internalTx = (await truffleAssert.createTransactionResult(contractVoucherKernel, txFillOrder.tx)) - - truffleAssert.eventEmitted(internalTx, 'LogVoucherDelivered', (ev) => { - return ev._issuer === Seller; - }, "order1 not created successfully"); - - let filtered = internalTx.logs.filter(e => e.event == 'LogVoucherDelivered')[0] - tokenVoucherKey1 = filtered.returnValues['_tokenIdVoucher'] - }); - - - it("fill second order (aka buy a voucher)", async () => { - - let txFillOrder = await contractCashier.requestVoucher_ETH_ETH(tokenSupplyKey2, Seller, {from: Buyer, to: contractCashier.address, value: helpers.PROMISE_PRICE2 + helpers.PROMISE_DEPOSITBU2}); - let internalTx = (await truffleAssert.createTransactionResult(contractVoucherKernel, txFillOrder.tx)) - - truffleAssert.eventEmitted(internalTx, 'LogVoucherDelivered', (ev) => { - tokenVoucherKey2 = ev._tokenIdVoucher; - return ev._tokenIdSupply.toString() === tokenSupplyKey2.toString(); - }, "order1 not filled successfully"); - }); - - //in prototype, everyone can create an order - // it("must fail: unauthorized adding of new order", async () => { - - // await truffleAssert.reverts(contractCashier.requestCreateOrder_ETH_ETH(promiseKey1, helpers.ORDER_QUANTITY1, {from: Attacker, to: contractCashier.address, value: helpers.PROMISE_DEPOSITSE1}), - // truffleAssert.ErrorType.REVERT - // ); - - // }); - - - it("must fail: adding new order with incorrect value sent", async () => { - - await truffleAssert.reverts(contractCashier.requestCreateOrder_ETH_ETH([helpers.PROMISE_VALID_FROM, helpers.PROMISE_VALID_TO, helpers.PROMISE_PRICE1, helpers.PROMISE_DEPOSITSE1, helpers.PROMISE_DEPOSITBU1, helpers.ORDER_QUANTITY1], {from: Seller, to: contractCashier.address, value: 0}), - truffleAssert.ErrorType.REVERT - ); - - }); - - it("must fail: fill an order with incorrect value", async () => { - - await truffleAssert.reverts(contractCashier.requestVoucher_ETH_ETH(tokenSupplyKey1, Seller, {from: Buyer, to: contractCashier.address, value: 0}), - truffleAssert.ErrorType.REVERT - ); - - }); - - }) - - describe('Voucher tokens', function() { - - it("redeeming one voucher", async () => { - let txRedeem = await contractVoucherKernel.redeem(tokenVoucherKey1, {from: Buyer}); - - truffleAssert.eventEmitted(txRedeem, 'LogVoucherRedeemed', (ev) => { - return ev._tokenIdVoucher.toString() === tokenVoucherKey1.toString(); - }, "voucher not redeemed successfully"); - }); - - - it("mark non-redeemed voucher as expired", async () => { - let statusBefore = await contractVoucherKernel.getVoucherStatus.call(tokenVoucherKey2); //[1000.0000] = hex"80" = 128 = COMMITTED - assert.equal(web3.utils.toHex(statusBefore[0]), web3.utils.numberToHex(128), "initial voucher status not as expected (COMMITTED)"); - - await timemachine.advanceTimeSeconds(helpers.SECONDS_IN_DAY*365); //fast-forward for a year - await contractVoucherKernel.triggerExpiration(tokenVoucherKey2); - - let statusAfter = await contractVoucherKernel.getVoucherStatus.call(tokenVoucherKey2); //[1001.0000] = hex"90" = 144 = EXPIRED - assert.equal(web3.utils.toHex(statusAfter[0]), web3.utils.numberToHex(144), "end voucher status not as expected (EXPIRED)"); - }); - - - it("mark voucher as finalized", async () => { - let txFinalize = await contractVoucherKernel.triggerFinalizeVoucher(tokenVoucherKey1, {from: Buyer}); - - truffleAssert.eventEmitted(txFinalize, 'LogFinalizeVoucher', (ev) => { - return ev._tokenIdVoucher.toString() === tokenVoucherKey1.toString(); - }, "voucher not finalized successfully"); - }); - - - it("must fail: unauthorized redemption", async () => { - await truffleAssert.reverts(contractVoucherKernel.redeem(tokenVoucherKey1, {from: Attacker}), - truffleAssert.ErrorType.REVERT - ); - }); - - }) - - - describe('Withdrawals', function() { - - it("withdraw the escrowed payment from one redeemed voucher", async () => { - let escrowedBefore = await contractCashier.getEscrowAmount.call(Buyer); - - await contractCashier.withdraw(tokenVoucherKey1); - - let escrowedAfter = await contractCashier.getEscrowAmount.call(Buyer); - - assert.isBelow(escrowedAfter.toNumber(), escrowedBefore.toNumber(), "escrowed amount not decreased"); - }); - - - // it("must fail: unauthorized withdrawal of escrowed pool", async () => { - // await truffleAssert.reverts(contractCashier.withdrawPool({from: Attacker}), - // truffleAssert.ErrorType.REVERT - // ); - // }); - - }) - - - - after(async () => { - await timemachine.revertToSnapShot(snapshot.id) - }) - -}); - - - - - - -contract("Voucher tests - UNHAPPY PATH", async accounts => { - - let Seller = accounts[0]; - let Buyer = accounts[1]; - let Attacker = accounts[2]; - - let contractERC1155ERC721, contractVoucherKernel, contractCashier, contractFundLimitsOracle; - let promiseKey1, promiseKey2; - let order1payment, order1depositSe, order1depositBu; - let ordersCount; - let tokenSupplyKey1, tokenSupplyKey2, tokenVoucherKey1, tokenVoucherKey2; - - before('setup promise dates based on the block timestamp', async () => { - snapshot = await timemachine.takeSnapshot(); - - const timestamp = await Utils.getCurrTimestamp() - - helpers.PROMISE_VALID_FROM = timestamp - helpers.PROMISE_VALID_TO = timestamp + 2 * helpers.SECONDS_IN_DAY; - }) - - beforeEach('setup contracts for tests', async () => { - - contractFundLimitsOracle = await FundLimitsOracle.new() - contractERC1155ERC721 = await ERC1155ERC721.new(); - contractVoucherKernel = await VoucherKernel.new(contractERC1155ERC721.address); - contractCashier = await Cashier.new(contractVoucherKernel.address, contractERC1155ERC721.address, contractFundLimitsOracle.address); - - await contractERC1155ERC721.setApprovalForAll(contractVoucherKernel.address, 'true'); - await contractERC1155ERC721.setVoucherKernelAddress(contractVoucherKernel.address); - await contractVoucherKernel.setCashierAddress(contractCashier.address); - - - //INIT - // await contractVoucherKernel.createTokenSupplyID(helpers.ASSET_TITLE, helpers.ASSET_PIN1, helpers.ASSET_QR1, helpers.PROMISE_VALID_FROM, helpers.PROMISE_VALID_TO, helpers.PROMISE_PRICE1, helpers.PROMISE_DEPOSITSE1, helpers.PROMISE_DEPOSITBU1, helpers.PROMISE_CHALLENGE_PERIOD * helpers.SECONDS_IN_DAY, helpers.PROMISE_CANCELORFAULT_PERIOD * helpers.SECONDS_IN_DAY); - - // promiseKey1 = await contractVoucherKernel.promiseKeys.call(0); - - // assert.notEqual(promiseKey1, helpers.ZERO_ADDRESS, "promise not added"); - - let txOrder = await contractCashier.requestCreateOrder_ETH_ETH( [helpers.PROMISE_VALID_FROM, helpers.PROMISE_VALID_TO, helpers.PROMISE_PRICE1, helpers.PROMISE_DEPOSITSE1, helpers.PROMISE_DEPOSITBU1, helpers.ORDER_QUANTITY1], {from: Seller, to: contractCashier.address, value: helpers.PROMISE_DEPOSITSE1}); - - truffleAssert.eventEmitted(txOrder, 'LogOrderCreated', (ev) => { - tokenSupplyKey1 = ev._tokenIdSupply; - return ev._seller === Seller; - }, "order1 not created successfully"); - - let txFillOrder = await contractCashier.requestVoucher_ETH_ETH(tokenSupplyKey1, Seller, {from: Buyer, to: contractCashier.address, value: helpers.PROMISE_PRICE1 + helpers.PROMISE_DEPOSITBU1}); - let internalTx = (await truffleAssert.createTransactionResult(contractVoucherKernel, txFillOrder.tx)) - - truffleAssert.eventEmitted(internalTx, 'LogVoucherDelivered', (ev) => { - tokenVoucherKey1 = ev._tokenIdVoucher - return ev._issuer === Seller; - }, "order1 not created successfully"); - - //\INIT + it("must fail: unauthorized minting ERC-721", async () => { + await truffleAssert.reverts( + contractERC1155ERC721.mint(accounts.attacker, 666), + truffleAssert.ErrorType.REVERT + ) }) + }) + + describe('Orders (aka supply tokens - ERC1155)', () => { + it("adding one new order / promise", async () => { + const txOrder = await contractCashier + .requestCreateOrder_ETH_ETH([ + constants.PROMISE_VALID_FROM, + constants.PROMISE_VALID_TO, + constants.PROMISE_PRICE1, + constants.PROMISE_DEPOSITSE1, + constants.PROMISE_DEPOSITBU1, + constants.ORDER_QUANTITY1 + ], { + from: accounts.buyer, + to: contractCashier.address, + value: constants.PROMISE_DEPOSITSE1 + }) + + // // would need truffle-events as the event emitted is from a nested + // // contract, so truffle-assert doesn't detect it + // truffleAssert.eventEmitted(txOrder, 'LogOrderCreated', (ev) => { + // tokenSupplyKey = ev._tokenIdSupply; + // return ev._seller === Seller; + // }, "order1 not created successfully"); + + // // instead, we check that the escrow increased for the seller + // let escrowAmount = await contractCashier.getEscrowAmount.call(Seller); + // assert.isAbove(escrowAmount.toNumber(), 0, + // "seller's escrowed deposit should be more than zero"); + + // move events from VoucherKernel to Cashier: + truffleAssert.eventEmitted( + txOrder, + 'LogOrderCreated', + (ev) => { + tokenSupplyKey1 = ev._tokenIdSupply + return ev._seller === accounts.buyer + }, "order1 not created successfully") + }) - describe('Wait periods', function() { - it("change complain period", async () => { - let txChangePeriod = await contractVoucherKernel.setComplainPeriod(helpers.PROMISE_CHALLENGE_PERIOD * helpers.SECONDS_IN_DAY); - - truffleAssert.eventEmitted(txChangePeriod, 'LogComplainPeriodChanged', (ev) => { - return ev._newComplainPeriod.toString() === (helpers.PROMISE_CHALLENGE_PERIOD * helpers.SECONDS_IN_DAY).toString(); - }, "complain period not changed successfully"); - }); - - - it("must fail: unauthorized change of complain period", async () => { - await truffleAssert.reverts(contractVoucherKernel.setComplainPeriod(helpers.PROMISE_CHALLENGE_PERIOD * helpers.SECONDS_IN_DAY, {from: Attacker}), - truffleAssert.ErrorType.REVERT - ); - }); - - - it("change cancelOrFault period", async () => { - let txChangePeriod = await contractVoucherKernel.setCancelFaultPeriod(helpers.PROMISE_CANCELORFAULT_PERIOD * helpers.SECONDS_IN_DAY); - - await truffleAssert.eventEmitted(txChangePeriod, 'LogCancelFaultPeriodChanged', (ev) => { - return ev._newCancelFaultPeriod.toString() === (helpers.PROMISE_CANCELORFAULT_PERIOD * helpers.SECONDS_IN_DAY).toString(); - }, "complain period not changed successfully"); - }); - - - it("must fail: unauthorized change of cancelOrFault period", async () => { - await truffleAssert.reverts(contractVoucherKernel.setCancelFaultPeriod(helpers.PROMISE_CANCELORFAULT_PERIOD * helpers.SECONDS_IN_DAY, {from: Attacker}), - truffleAssert.ErrorType.REVERT - ); - }); - - }) - - - describe('Refunds ...', function() { - - it("refunding one voucher", async () => { - let txRefund = await contractVoucherKernel.refund(tokenVoucherKey1, {from: Buyer}); - - let statusAfter = await contractVoucherKernel.getVoucherStatus.call(tokenVoucherKey1); //[1010.0000] = hex"A0" = 160 = REFUND - assert.equal(web3.utils.toHex(statusAfter[0]), web3.utils.numberToHex(160), "end voucher status not as expected (REFUNDED)"); - }); + it("adding second order", async () => { + const txOrder = await contractCashier + .requestCreateOrder_ETH_ETH([ + constants.PROMISE_VALID_FROM, + constants.PROMISE_VALID_TO, + constants.PROMISE_PRICE2, + constants.PROMISE_DEPOSITSE2, + constants.PROMISE_DEPOSITBU2, + constants.ORDER_QUANTITY2 + ], { + from: accounts.buyer, + to: contractCashier.address, + value: constants.PROMISE_DEPOSITSE2 + }) + + truffleAssert.eventEmitted( + txOrder, + 'LogOrderCreated', + (ev) => { + tokenSupplyKey2 = ev._tokenIdSupply + return ev._seller === accounts.buyer + }, "order2 not created successfully") + }) + it("fill one order (aka buy a voucher)", async () => { + const txFillOrder = await contractCashier + .requestVoucher_ETH_ETH( + tokenSupplyKey1, + accounts.buyer, { + from: accounts.buyer, + to: contractCashier.address, + value: constants.PROMISE_PRICE1 + constants.PROMISE_DEPOSITBU1 + }) + const internalTx = await truffleAssert + .createTransactionResult(contractVoucherKernel, txFillOrder.tx) + + truffleAssert.eventEmitted( + internalTx, + 'LogVoucherDelivered', + (ev) => { + return ev._issuer === accounts.buyer + }, "order1 not created successfully") + + const filtered = internalTx.logs + .filter(e => e.event === 'LogVoucherDelivered')[0] + + tokenVoucherKey1 = filtered.returnValues['_tokenIdVoucher'] + }) - it("refunding one voucher, then complain", async () => { - let txRefund = await contractVoucherKernel.refund(tokenVoucherKey1, {from: Buyer}); - let txComplain = await contractVoucherKernel.complain(tokenVoucherKey1, {from: Buyer}); + it("fill second order (aka buy a voucher)", async () => { + const txFillOrder = await contractCashier + .requestVoucher_ETH_ETH( + tokenSupplyKey2, + accounts.buyer, { + from: accounts.buyer, + to: contractCashier.address, + value: constants.PROMISE_PRICE2 + constants.PROMISE_DEPOSITBU2 + }) + const internalTx = await truffleAssert + .createTransactionResult(contractVoucherKernel, txFillOrder.tx) + + truffleAssert.eventEmitted( + internalTx, + 'LogVoucherDelivered', + (ev) => { + tokenVoucherKey2 = ev._tokenIdVoucher + return ev._tokenIdSupply.toString() === tokenSupplyKey2.toString() + }, "order1 not filled successfully") + }) - let statusAfter = await contractVoucherKernel.getVoucherStatus.call(tokenVoucherKey1); //[1010.1000] = hex"A8" = 168 = REFUND_COMPLAIN - assert.equal(web3.utils.toHex(statusAfter[0]), web3.utils.numberToHex(168), "end voucher status not as expected (REFUNDED_COMPLAINED)"); - }); + it("must fail: adding new order with incorrect value sent", + async () => { + await truffleAssert.reverts( + contractCashier.requestCreateOrder_ETH_ETH([ + constants.PROMISE_VALID_FROM, + constants.PROMISE_VALID_TO, + constants.PROMISE_PRICE1, + constants.PROMISE_DEPOSITSE1, + constants.PROMISE_DEPOSITBU1, + constants.ORDER_QUANTITY1 + ], { + from: accounts.buyer, + to: contractCashier.address, + value: 0 + }), + truffleAssert.ErrorType.REVERT + ) + }) + + it("must fail: fill an order with incorrect value", async () => { + await truffleAssert.reverts( + contractCashier.requestVoucher_ETH_ETH( + tokenSupplyKey1, + accounts.buyer, { + from: accounts.buyer, + to: contractCashier.address, + value: 0 + }), + truffleAssert.ErrorType.REVERT + ) + }) + }) + + describe('Voucher tokens', function () { + it("redeeming one voucher", async () => { + const txRedeem = await contractVoucherKernel + .redeem(tokenVoucherKey1, { from: accounts.buyer }) + + truffleAssert.eventEmitted( + txRedeem, + 'LogVoucherRedeemed', + (ev) => { + return ev._tokenIdVoucher.toString() === tokenVoucherKey1.toString() + }, "voucher not redeemed successfully") + }) + it("mark non-redeemed voucher as expired", async () => { + const statusBefore = await contractVoucherKernel + .getVoucherStatus.call(tokenVoucherKey2) + + // [1000.0000] = hex"80" = 128 = COMMITTED + assert.equal( + web3.utils.toHex(statusBefore[0]), + web3.utils.numberToHex(128), + "initial voucher status not as expected (COMMITTED)") + + // fast-forward for a year + await timemachine.advanceTimeSeconds( + constants.SECONDS_IN_DAY * 365) + await contractVoucherKernel.triggerExpiration(tokenVoucherKey2) + + const statusAfter = await contractVoucherKernel + .getVoucherStatus.call(tokenVoucherKey2) + + //[1001.0000] = hex"90" = 144 = EXPIRED + assert.equal( + web3.utils.toHex(statusAfter[0]), + web3.utils.numberToHex(144), + "end voucher status not as expected (EXPIRED)") + }) - it("refunding one voucher, then complain, then cancel/fault", async () => { - let txRefund = await contractVoucherKernel.refund(tokenVoucherKey1, {from: Buyer}); - let txComplain = await contractVoucherKernel.complain(tokenVoucherKey1, {from: Buyer}); - let txCoF = await contractVoucherKernel.cancelOrFault(tokenVoucherKey1, {from: Seller}); + it("mark voucher as finalized", async () => { + const txFinalize = await contractVoucherKernel + .triggerFinalizeVoucher(tokenVoucherKey1, { from: accounts.buyer }) - let statusAfter = await contractVoucherKernel.getVoucherStatus.call(tokenVoucherKey1); //[1010.1100] = hex"AC" = 172 = REFUND_COMPLAIN_COF - assert.equal(web3.utils.toHex(statusAfter[0]), web3.utils.numberToHex(172), "end voucher status not as expected (REFUNDED_COMPLAINED_CANCELORFAULT)"); - }); + truffleAssert.eventEmitted( + txFinalize, + 'LogFinalizeVoucher', + (ev) => { + return ev._tokenIdVoucher.toString() === tokenVoucherKey1.toString() + }, "voucher not finalized successfully") + }) + it("must fail: unauthorized redemption", async () => { + await truffleAssert.reverts( + contractVoucherKernel.redeem( + tokenVoucherKey1, { from: accounts.attacker }), + truffleAssert.ErrorType.REVERT + ) + }) + }) - it("must fail: refund then try to redeem", async () => { - let txRefund = await contractVoucherKernel.refund(tokenVoucherKey1, {from: Buyer}); + describe('Withdrawals', function () { + it("withdraw the escrowed payment from one redeemed voucher", + async () => { + const escrowedBefore = await contractCashier + .getEscrowAmount.call(accounts.buyer) - await truffleAssert.reverts(contractVoucherKernel.redeem(tokenVoucherKey1, {from: Buyer}), - truffleAssert.ErrorType.REVERT - ); - }); + await contractCashier.withdraw(tokenVoucherKey1) - }) + const escrowedAfter = await contractCashier + .getEscrowAmount.call(accounts.buyer) + assert.isBelow( + escrowedAfter.toNumber(), + escrowedBefore.toNumber(), + "escrowed amount not decreased") + }) - describe('Cancel/Fault by the seller ...', function() { + // it("must fail: unauthorized withdrawal of escrowed pool", async () => { + // await truffleAssert.reverts( + // contractCashier.withdrawPool({from: Attacker}), + // truffleAssert.ErrorType.REVERT + // ); + // }); - it("canceling one voucher", async () => { - let txCoF = await contractVoucherKernel.cancelOrFault(tokenVoucherKey1, {from: Seller}); + }) - let statusAfter = await contractVoucherKernel.getVoucherStatus.call(tokenVoucherKey1); //[1000.0100] = hex"84" = 132 = CANCELORFAULT - assert.equal(web3.utils.toHex(statusAfter[0]), web3.utils.numberToHex(132), "end voucher status not as expected (CANCELORFAULT)"); - }); + after(async () => { + await timemachine.revertToSnapShot(snapshot.id) + }) +}) +contract("Voucher tests - UNHAPPY PATH", async accountSet => { + const accounts = new Accounts(accountSet) - it("must fail: cancel/fault then try to redeem", async () => { - let txCoF = await contractVoucherKernel.cancelOrFault(tokenVoucherKey1, {from: Seller}); + let contractERC1155ERC721, + contractVoucherKernel, + contractCashier, + contractFundLimitsOracle + let tokenSupplyKey1, + tokenVoucherKey1 - await truffleAssert.reverts(contractVoucherKernel.redeem(tokenVoucherKey1, {from: Buyer}), - truffleAssert.ErrorType.REVERT - ); - }); + before('setup promise dates based on the block timestamp', + async () => { + snapshot = await timemachine.takeSnapshot() - }) + const timestamp = await Utils.getCurrTimestamp() + constants.PROMISE_VALID_FROM = timestamp + constants.PROMISE_VALID_TO = timestamp + 2 * constants.SECONDS_IN_DAY + }) - describe('Expirations (one universal test) ...', function() { + beforeEach('setup contracts for tests', async () => { + contractFundLimitsOracle = await FundLimitsOracle.new() + contractERC1155ERC721 = await ERC1155ERC721.new() + contractVoucherKernel = await VoucherKernel.new( + contractERC1155ERC721.address) + contractCashier = await Cashier.new( + contractVoucherKernel.address, + contractERC1155ERC721.address, + contractFundLimitsOracle.address) + + await contractERC1155ERC721.setApprovalForAll( + contractVoucherKernel.address, 'true') + await contractERC1155ERC721.setVoucherKernelAddress( + contractVoucherKernel.address) + await contractVoucherKernel.setCashierAddress( + contractCashier.address) + + const txOrder = await contractCashier + .requestCreateOrder_ETH_ETH([ + constants.PROMISE_VALID_FROM, + constants.PROMISE_VALID_TO, + constants.PROMISE_PRICE1, + constants.PROMISE_DEPOSITSE1, + constants.PROMISE_DEPOSITBU1, + constants.ORDER_QUANTITY1 + ], { + from: accounts.seller, + to: contractCashier.address, + value: constants.PROMISE_DEPOSITSE1 + }) + + truffleAssert.eventEmitted( + txOrder, + 'LogOrderCreated', + (ev) => { + tokenSupplyKey1 = ev._tokenIdSupply + return ev._seller === accounts.seller + }, "order1 not created successfully") + + const txFillOrder = await contractCashier + .requestVoucher_ETH_ETH( + tokenSupplyKey1, + accounts.seller, + { + from: accounts.buyer, + to: contractCashier.address, + value: constants.PROMISE_PRICE1 + constants.PROMISE_DEPOSITBU1 + }) + const internalTx = await truffleAssert + .createTransactionResult(contractVoucherKernel, txFillOrder.tx) + + truffleAssert.eventEmitted( + internalTx, + 'LogVoucherDelivered', + (ev) => { + tokenVoucherKey1 = ev._tokenIdVoucher + return ev._issuer === accounts.seller + }, "order1 not created successfully") + }) + + describe('Wait periods', () => { + it("change complain period", async () => { + const complainPeriodSeconds = + constants.PROMISE_CHALLENGE_PERIOD * constants.SECONDS_IN_DAY + + const txChangePeriod = await contractVoucherKernel + .setComplainPeriod(complainPeriodSeconds) + + truffleAssert.eventEmitted( + txChangePeriod, + 'LogComplainPeriodChanged', + (ev) => { + return ev._newComplainPeriod.toString() === + complainPeriodSeconds.toString() + }, "complain period not changed successfully") + }) - it("Expired, then complain, then Cancel/Fault, then try to redeem", async () => { - await timemachine.advanceTimeSeconds(helpers.SECONDS_IN_DAY*3); //fast-forward for three days - await contractVoucherKernel.triggerExpiration(tokenVoucherKey1); + it("must fail: unauthorized change of complain period", + async () => { + const complainPeriodSeconds = + constants.PROMISE_CHALLENGE_PERIOD * constants.SECONDS_IN_DAY + + await truffleAssert.reverts( + contractVoucherKernel.setComplainPeriod( + complainPeriodSeconds, { from: accounts.attacker }), + truffleAssert.ErrorType.REVERT + ) + }) + + it("change cancelOrFault period", async () => { + const cancelFaultPeriodSeconds = + constants.PROMISE_CANCELORFAULT_PERIOD * constants.SECONDS_IN_DAY + const txChangePeriod = await contractVoucherKernel + .setCancelFaultPeriod(cancelFaultPeriodSeconds) + + await truffleAssert.eventEmitted( + txChangePeriod, + 'LogCancelFaultPeriodChanged', + (ev) => { + return ev._newCancelFaultPeriod.toString() === + cancelFaultPeriodSeconds.toString() + }, "complain period not changed successfully") + }) - let statusAfter = await contractVoucherKernel.getVoucherStatus.call(tokenVoucherKey1); //[1001.0000] = hex"90" = 144 = EXPIRED - let txComplain = await contractVoucherKernel.complain(tokenVoucherKey1, {from: Buyer}); + it("must fail: unauthorized change of cancelOrFault period", + async () => { + const cancelFaultPeriodSeconds = + constants.PROMISE_CANCELORFAULT_PERIOD * constants.SECONDS_IN_DAY + await truffleAssert.reverts( + contractVoucherKernel.setCancelFaultPeriod( + cancelFaultPeriodSeconds, { from: accounts.attacker }), + truffleAssert.ErrorType.REVERT + ) + }) + }) + + describe('Refunds ...', function () { + it("refunding one voucher", async () => { + const txRefund = await contractVoucherKernel.refund( + tokenVoucherKey1, { + from: accounts.buyer + }) + + const statusAfter = await contractVoucherKernel + .getVoucherStatus.call(tokenVoucherKey1) + + // [1010.0000] = hex"A0" = 160 = REFUND + assert.equal( + web3.utils.toHex(statusAfter[0]), + web3.utils.numberToHex(160), + "end voucher status not as expected (REFUNDED)") + }) - statusAfter = await contractVoucherKernel.getVoucherStatus.call(tokenVoucherKey1); //[1001.1000] = hex"98" = 152 = EXPIRED_COMPLAIN - assert.equal(web3.utils.toHex(statusAfter[0]), web3.utils.numberToHex(152), "end voucher status not as expected (EXPIRED_COMPLAINED)"); + it("refunding one voucher, then complain", async () => { + const txRefund = await contractVoucherKernel.refund( + tokenVoucherKey1, { + from: accounts.buyer + }) + const txComplain = await contractVoucherKernel.complain( + tokenVoucherKey1, { + from: accounts.buyer + }) + + const statusAfter = await contractVoucherKernel + .getVoucherStatus.call(tokenVoucherKey1) + + // [1010.1000] = hex"A8" = 168 = REFUND_COMPLAIN + assert.equal( + web3.utils.toHex(statusAfter[0]), + web3.utils.numberToHex(168), + "end voucher status not as expected (REFUNDED_COMPLAINED)") + }) - //in the same test, because the EVM time machine is funky ... - let txCoF = await contractVoucherKernel.cancelOrFault(tokenVoucherKey1, {from: Seller}); - statusAfter = await contractVoucherKernel.getVoucherStatus.call(tokenVoucherKey1); //[1001.1000] = hex"9C" = 156 = EXPIRED_COMPLAINED_CANCELORFAULT - assert.equal(web3.utils.toHex(statusAfter[0]), web3.utils.numberToHex(156), "end voucher status not as expected (EXPIRED_COMPLAINED_CANCELORFAULT)"); + it("refunding one voucher, then complain, then cancel/fault", + async () => { + const txRefund = await contractVoucherKernel.refund( + tokenVoucherKey1, { + from: accounts.buyer + }) + const txComplain = await contractVoucherKernel.complain( + tokenVoucherKey1, { + from: accounts.buyer + }) + const txCoF = await contractVoucherKernel.cancelOrFault( + tokenVoucherKey1, { + from: accounts.seller + }) + + const statusAfter = await contractVoucherKernel + .getVoucherStatus.call(tokenVoucherKey1) + + // [1010.1100] = hex"AC" = 172 = REFUND_COMPLAIN_COF + assert.equal( + web3.utils.toHex(statusAfter[0]), + web3.utils.numberToHex(172), + "end voucher status not as expected " + + "(REFUNDED_COMPLAINED_CANCELORFAULT)") + }) + + it("must fail: refund then try to redeem", async () => { + const txRefund = await contractVoucherKernel.refund( + tokenVoucherKey1, { + from: accounts.buyer + }) + + await truffleAssert.reverts( + contractVoucherKernel.redeem( + tokenVoucherKey1, { from: accounts.buyer }), + truffleAssert.ErrorType.REVERT + ) + }) + }) + + describe('Cancel/Fault by the seller ...', () => { + it("canceling one voucher", async () => { + const txCoF = await contractVoucherKernel + .cancelOrFault( + tokenVoucherKey1, { + from: accounts.seller + }) + + const statusAfter = await contractVoucherKernel + .getVoucherStatus.call(tokenVoucherKey1) + + // [1000.0100] = hex"84" = 132 = CANCELORFAULT + assert.equal( + web3.utils.toHex(statusAfter[0]), + web3.utils.numberToHex(132), + "end voucher status not as expected (CANCELORFAULT)") + }) - //in the same test, because the EVM time machine is funky ... - await truffleAssert.reverts(contractVoucherKernel.redeem(tokenVoucherKey1, {from: Buyer}), - truffleAssert.ErrorType.REVERT - ); - }); - - after(async () => { - await timemachine.revertToSnapShot(snapshot.id) - }) + it("must fail: cancel/fault then try to redeem", async () => { + const txCoF = await contractVoucherKernel + .cancelOrFault( + tokenVoucherKey1, { + from: accounts.seller + }) + + await truffleAssert.reverts( + contractVoucherKernel.redeem( + tokenVoucherKey1, { from: accounts.buyer }), + truffleAssert.ErrorType.REVERT + ) + }) - }) - -}); \ No newline at end of file + }) + + describe('Expirations (one universal test) ...', () => { + it("Expired, then complain, then Cancel/Fault, then try to redeem", + async () => { + // fast-forward for three days + const secondsInThreeDays = constants.SECONDS_IN_DAY * 3 + await timemachine.advanceTimeSeconds(secondsInThreeDays) + + await contractVoucherKernel.triggerExpiration(tokenVoucherKey1) + + let statusAfter = await contractVoucherKernel + .getVoucherStatus.call(tokenVoucherKey1) + + // [1001.0000] = hex"90" = 144 = EXPIRED + assert.equal( + web3.utils.toHex(statusAfter[0]), + web3.utils.numberToHex(144), + "end voucher status not as expected (EXPIRED)") + + const txComplain = await contractVoucherKernel + .complain(tokenVoucherKey1, { from: accounts.buyer }) + + statusAfter = await contractVoucherKernel + .getVoucherStatus.call(tokenVoucherKey1) + + // [1001.1000] = hex"98" = 152 = EXPIRED_COMPLAIN + assert.equal( + web3.utils.toHex(statusAfter[0]), + web3.utils.numberToHex(152), + "end voucher status not as expected (EXPIRED_COMPLAINED)") + + // in the same test, because the EVM time machine is funky ... + const txCoF = await contractVoucherKernel + .cancelOrFault(tokenVoucherKey1, { from: accounts.seller }) + + statusAfter = await contractVoucherKernel + .getVoucherStatus.call(tokenVoucherKey1) + + // [1001.1000] = hex"9C" = 156 = EXPIRED_COMPLAINED_CANCELORFAULT + assert.equal( + web3.utils.toHex(statusAfter[0]), + web3.utils.numberToHex(156), + "end voucher status not as expected " + + "(EXPIRED_COMPLAINED_CANCELORFAULT)") + + // in the same test, because the EVM time machine is funky ... + await truffleAssert.reverts( + contractVoucherKernel.redeem( + tokenVoucherKey1, { from: accounts.buyer }), + truffleAssert.ErrorType.REVERT + ) + }) + + after(async () => { + await timemachine.revertToSnapShot(snapshot.id) + }) + }) +}) diff --git a/testHelpers/accounts.js b/testHelpers/accounts.js new file mode 100644 index 00000000..d7801d23 --- /dev/null +++ b/testHelpers/accounts.js @@ -0,0 +1,19 @@ +class Accounts { + constructor(accountSet) { + this.accountSet = accountSet + } + + get seller() { + return this.accountSet[1] + } + + get buyer() { + return this.accountSet[2] + } + + get attacker() { + return this.accountSet[3] + } +} + +module.exports = Accounts diff --git a/testHelpers/constants.js b/testHelpers/constants.js index c51c8cf2..9a94a92c 100644 --- a/testHelpers/constants.js +++ b/testHelpers/constants.js @@ -1,90 +1,88 @@ -//common -const SECONDS_IN_DAY = 86400; -const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"; +// common +const SECONDS_IN_DAY = 86400 +const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000" -//asset -const ASSET_VERSION = "0x3132"; -const ASSET_TITLE = "Dragon wizard hat"; -const ASSET_TITLE2 = "T-shirt dragons"; -const ASSET_TITLE3 = "T-shirt goblins"; -const ASSET_PIN1 = "I3DESK"; -const ASSET_PIN2 = "QBSOS"; -const ASSET_QR1 = "XYZ12"; -const ASSET_QR2 = "QWY43"; -const ASSET_DESCRIPTION = "mighty wizard hat, universal size"; -const CATEGORY1 = "entertainment.games.swag"; -const CATEGORY2 = "entertainment.games.shield"; +// asset +const ASSET_VERSION = "0x3132" +const ASSET_TITLE = "Dragon wizard hat" +const ASSET_TITLE2 = "T-shirt dragons" +const ASSET_TITLE3 = "T-shirt goblins" +const ASSET_PIN1 = "I3DESK" +const ASSET_PIN2 = "QBSOS" +const ASSET_QR1 = "XYZ12" +const ASSET_QR2 = "QWY43" +const ASSET_DESCRIPTION = "mighty wizard hat, universal size" +const CATEGORY1 = "entertainment.games.swag" +const CATEGORY2 = "entertainment.games.shield" -//promise -const PROMISE_VALID_FROM = ''; // evaluated based on the current block timestamp -const PROMISE_VALID_TO = ''; // evaluated based on the PROMISE_VALID_FROM + 2 * SECONDS_IN_DAY -const PROMISE_PRICE1 = 10; -const PROMISE_PRICE2 = 21; -const PROMISE_DEPOSITSE1 = 1; -const PROMISE_DEPOSITSE2 = 5; -const PROMISE_DEPOSITBU1 = 1; -const PROMISE_DEPOSITBU2 = 2; -const PROMISE_CHALLENGE_PERIOD = 8; -const PROMISE_CANCELORFAULT_PERIOD = 8; +// promise +const PROMISE_VALID_FROM = '' // evaluated based on the current block timestamp +const PROMISE_VALID_TO = '' // evaluated based on the PROMISE_VALID_FROM + 2 * SECONDS_IN_DAY +const PROMISE_PRICE1 = 10 +const PROMISE_PRICE2 = 21 +const PROMISE_DEPOSITSE1 = 1 +const PROMISE_DEPOSITSE2 = 5 +const PROMISE_DEPOSITBU1 = 1 +const PROMISE_DEPOSITBU2 = 2 +const PROMISE_CHALLENGE_PERIOD = 8 +const PROMISE_CANCELORFAULT_PERIOD = 8 -//order -const ORDER_QUANTITY1 = 1; -const ORDER_QUANTITY2 = 1; +// order +const ORDER_QUANTITY1 = 1 +const ORDER_QUANTITY2 = 1 - -const buyer_deposit = '40000000000000000'; // 0.04 -const buyer_incorrect_deposit = '4000000000000000'; // 0.004 -const seller_deposit = '50000000000000000'; // 0.05 -const product_price = '300000000000000000'; // 0.3 -const incorrect_product_price = '30000000000000000'; // 0.03 +const buyer_deposit = '40000000000000000' // 0.04 +const buyer_incorrect_deposit = '4000000000000000' // 0.004 +const seller_deposit = '50000000000000000' // 0.05 +const product_price = '300000000000000000' // 0.3 +const incorrect_product_price = '30000000000000000' // 0.03 const QTY_10 = 10 const QTY_20 = 20 const QTY_1 = 1 -//fund limits -const ETHER_LIMIT = (5 * 10 ** 18).toString(); -const ABOVE_ETH_LIMIT = (10 * 10 ** 18).toString(); +// fund limits +const ETHER_LIMIT = (5 * 10 ** 18).toString() +const ABOVE_ETH_LIMIT = (10 * 10 ** 18).toString() -const TOKEN_LIMIT = (5 * 10 ** 18).toString(); -const ABOVE_TOKEN_LIMIT = (10 * 10 ** 18).toString(); +const TOKEN_LIMIT = (5 * 10 ** 18).toString() +const ABOVE_TOKEN_LIMIT = (10 * 10 ** 18).toString() module.exports = { - ASSET_VERSION, - ASSET_TITLE, - ASSET_TITLE2, - ASSET_TITLE3, - ASSET_PIN1, - ASSET_PIN2, - ASSET_QR1, - ASSET_QR2, - ASSET_DESCRIPTION, - CATEGORY1, - CATEGORY2, - PROMISE_VALID_FROM, - PROMISE_VALID_TO, - PROMISE_PRICE1, - PROMISE_PRICE2, - PROMISE_DEPOSITSE1, - PROMISE_DEPOSITSE2, - PROMISE_DEPOSITBU1, - PROMISE_DEPOSITBU2, - PROMISE_CHALLENGE_PERIOD, - PROMISE_CANCELORFAULT_PERIOD, - ORDER_QUANTITY1, - ORDER_QUANTITY2, - SECONDS_IN_DAY, - ZERO_ADDRESS, - buyer_deposit, - buyer_incorrect_deposit, - seller_deposit, - product_price, - incorrect_product_price, - QTY_1, - QTY_10, - QTY_1, - QTY_20, - ETHER_LIMIT, - ABOVE_ETH_LIMIT, - TOKEN_LIMIT, - ABOVE_TOKEN_LIMIT + ASSET_VERSION, + ASSET_TITLE, + ASSET_TITLE2, + ASSET_TITLE3, + ASSET_PIN1, + ASSET_PIN2, + ASSET_QR1, + ASSET_QR2, + ASSET_DESCRIPTION, + CATEGORY1, + CATEGORY2, + PROMISE_VALID_FROM, + PROMISE_VALID_TO, + PROMISE_PRICE1, + PROMISE_PRICE2, + PROMISE_DEPOSITSE1, + PROMISE_DEPOSITSE2, + PROMISE_DEPOSITBU1, + PROMISE_DEPOSITBU2, + PROMISE_CHALLENGE_PERIOD, + PROMISE_CANCELORFAULT_PERIOD, + ORDER_QUANTITY1, + ORDER_QUANTITY2, + SECONDS_IN_DAY, + ZERO_ADDRESS, + buyer_deposit, + buyer_incorrect_deposit, + seller_deposit, + product_price, + incorrect_product_price, + QTY_1, + QTY_10, + QTY_20, + ETHER_LIMIT, + ABOVE_ETH_LIMIT, + TOKEN_LIMIT, + ABOVE_TOKEN_LIMIT } \ No newline at end of file diff --git a/testHelpers/permitUtils.js b/testHelpers/permitUtils.js index 448c747f..8d89b745 100644 --- a/testHelpers/permitUtils.js +++ b/testHelpers/permitUtils.js @@ -1,106 +1,128 @@ - const { - hexlify, - getAddress, - keccak256, - defaultAbiCoder, - toUtf8Bytes, - solidityPack, - AbiCoder, - Interface, -} = require('ethers').utils; - + keccak256, + defaultAbiCoder, + toUtf8Bytes, + solidityPack, + AbiCoder, + Interface +} = require('ethers').utils const PERMIT_TYPEHASH = keccak256( - toUtf8Bytes('Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)') -); + toUtf8Bytes( + 'Permit(' + + 'address owner,' + + 'address spender,' + + 'uint256 value,' + + 'uint256 nonce,' + + 'uint256 deadline)') +) const toWei = (value) => { - return value + '0'.repeat(18); -}; + return value + '0'.repeat(18) +} -async function getApprovalDigest( - token, - owner, - spender, - value, - nonce, - deadline +async function getApprovalDigest ( + token, + owner, + spender, + value, + nonce, + deadline ) { - const name = await token.name(); - const DOMAIN_SEPARATOR = getDomainSeparator(name, token.address); - - return keccak256( - solidityPack( - ['bytes1', 'bytes1', 'bytes32', 'bytes32'], + const name = await token.name() + const DOMAIN_SEPARATOR = getDomainSeparator(name, token.address) + + return keccak256( + solidityPack( + [ 'bytes1', 'bytes1', 'bytes32', 'bytes32' ], + [ + '0x19', + '0x01', + DOMAIN_SEPARATOR, + keccak256( + defaultAbiCoder.encode( + [ + 'bytes32', + 'address', + 'address', + 'uint256', + 'uint256', + 'uint256' + ], [ - '0x19', - '0x01', - DOMAIN_SEPARATOR, - keccak256( - defaultAbiCoder.encode( - ['bytes32', 'address', 'address', 'uint256', 'uint256', 'uint256'], - [PERMIT_TYPEHASH, owner, spender, value.toString(), nonce.toString(), deadline] - ) - ) + PERMIT_TYPEHASH, + owner, + spender, + value.toString(), + nonce.toString(), + deadline ] + ) ) + ] ) + ) } -function getDomainSeparator(name, tokenAddress) { - return keccak256( - defaultAbiCoder.encode( - ['bytes32', 'bytes32', 'bytes32', 'uint256', 'address'], - [ - keccak256(toUtf8Bytes('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)')), - keccak256(toUtf8Bytes(name)), - keccak256(toUtf8Bytes('1')), - 1, - tokenAddress - ] - ) +function getDomainSeparator (name, tokenAddress) { + return keccak256( + defaultAbiCoder.encode( + [ 'bytes32', 'bytes32', 'bytes32', 'uint256', 'address' ], + [ + keccak256(toUtf8Bytes( + 'EIP712Domain(' + + 'string name,' + + 'string version,' + + 'uint256 chainId,' + + 'address verifyingContract)')), + keccak256(toUtf8Bytes(name)), + keccak256(toUtf8Bytes('1')), + 1, + tokenAddress + ] ) + ) } -async function getEncodedTopic(receipt, abi, eventName) { - const interface = new Interface(abi) - for (const log in receipt.logs) { - const topics = receipt.logs[log].topics; - for (const index in topics) { +async function getEncodedTopic (receipt, abi, eventName) { + const interface = new Interface(abi) + for (const log in receipt.logs) { + const topics = receipt.logs[log].topics + for (const index in topics) { - const encodedTopic = topics[index]; + const encodedTopic = topics[index] - try { - // CHECK IF TOPIC CORRESPONDS TO THE EVENT GIVEN TO FN - let event = await interface.getEvent(encodedTopic); + try { + // CHECK IF TOPIC CORRESPONDS TO THE EVENT GIVEN TO FN + let event = await interface.getEvent(encodedTopic) - if (event.name == eventName) return encodedTopic - } catch (error) { - // breaks silently as we do not need to do anything if the there is not such an event - } - - } + if (event.name === eventName) return encodedTopic + } catch (error) { + // breaks silently as we do not need to do anything if the there is not + // such an event + } } + } - - return '' + return '' } -async function decodeData(receipt, encodedTopic, paramsArr) { - const decoder = new AbiCoder(); +async function decodeData (receipt, encodedTopic, paramsArr) { + const decoder = new AbiCoder() - const encodedData = receipt.logs.filter(e => e.topics.includes(encodedTopic))[0].data - return decoder.decode(paramsArr, encodedData) + const encodedData = receipt + .logs + .filter(e => e.topics.includes(encodedTopic))[0] + .data + return decoder.decode(paramsArr, encodedData) } - module.exports = { - PERMIT_TYPEHASH, - toWei, - getApprovalDigest, - getEncodedTopic, - decodeData + PERMIT_TYPEHASH, + toWei, + getApprovalDigest, + getEncodedTopic, + decodeData } \ No newline at end of file diff --git a/testHelpers/timemachine.js b/testHelpers/timemachine.js index faa7a289..00a6fbf8 100644 --- a/testHelpers/timemachine.js +++ b/testHelpers/timemachine.js @@ -1,56 +1,55 @@ -function advanceTimeBlocks(_blocks) { - return new Promise(function(resolve) { - web3.currentProvider.send({ - jsonrpc: "2.0", - method: "evm_mine", - params: [_blocks], - id: new Date().getTime() - }, resolve); - }); -}; +function advanceTimeBlocks (_blocks) { + return new Promise(function (resolve) { + web3.currentProvider.send({ + jsonrpc: "2.0", + method: "evm_mine", + params: [ _blocks ], + id: new Date().getTime() + }, resolve) + }) +} -function advanceTimeSeconds(_seconds) { - return new Promise(function(resolve) { - web3.currentProvider.send({ - jsonrpc: "2.0", - method: "evm_increaseTime", - params: [_seconds], - id: new Date().getTime() - }, resolve); - }); -}; +function advanceTimeSeconds (_seconds) { + return new Promise(function (resolve) { + web3.currentProvider.send({ + jsonrpc: "2.0", + method: "evm_increaseTime", + params: [ _seconds ], + id: new Date().getTime() + }, resolve) + }) +} function takeSnapshot () { - return new Promise((resolve, reject) => { - web3.currentProvider.send({ - jsonrpc: '2.0', - method: 'evm_snapshot', - id: new Date().getTime() - }, (err, snapshotId) => { - if (err) { return reject(err) } - return resolve(snapshotId) - }) + return new Promise((resolve, reject) => { + web3.currentProvider.send({ + jsonrpc: '2.0', + method: 'evm_snapshot', + id: new Date().getTime() + }, (err, snapshotId) => { + if (err) { return reject(err) } + return resolve(snapshotId) }) + }) } -function revertToSnapShot (id) { - return new Promise((resolve, reject) => { - web3.currentProvider.send({ - jsonrpc: '2.0', - method: 'evm_revert', - params: [id], - id: new Date().getTime() - }, (err, result) => { - if (err) { return reject(err) } - return resolve(result) - }) +function revertToSnapShot (id) { + return new Promise((resolve, reject) => { + web3.currentProvider.send({ + jsonrpc: '2.0', + method: 'evm_revert', + params: [ id ], + id: new Date().getTime() + }, (err, result) => { + if (err) { return reject(err) } + return resolve(result) }) + }) } - Object.assign(exports, { - advanceTimeBlocks, - advanceTimeSeconds, - takeSnapshot, - revertToSnapShot -}); \ No newline at end of file + advanceTimeBlocks, + advanceTimeSeconds, + takeSnapshot, + revertToSnapShot +}) diff --git a/testHelpers/utils.js b/testHelpers/utils.js index 9437f04c..02c56e91 100644 --- a/testHelpers/utils.js +++ b/testHelpers/utils.js @@ -1,438 +1,549 @@ - const helpers = require('./constants') -const config = require('./config.json') const BN = web3.utils.BN const truffleAssert = require('truffle-assertions') -const { ecsign } = require('ethereumjs-util'); +const { ecsign } = require('ethereumjs-util') const { - PERMIT_TYPEHASH, - toWei, - getApprovalDigest -} = require('../testHelpers/permitUtils'); + toWei, + getApprovalDigest +} = require('../testHelpers/permitUtils') class Utils { - - constructor() { - this.createOrder = '' - this.commitToBuy = '' - this.deadline = toWei(1) - } - - setContracts(erc1155721, voucherKernel, cashier, bsnTokenPrice, bsnTokenDeposit) { - this.contractERC1155ERC721 = erc1155721 - this.contractVoucherKernel = voucherKernel - this.contractCashier = cashier - this.contractBSNTokenPrice = bsnTokenPrice - this.contractBSNTokenDeposit = bsnTokenDeposit - this.contractBSNTokenSAME = bsnTokenPrice - } - - async requestCreateOrder_ETH_ETH(seller, from, to, sellerDeposit, qty, returnTx = false) { - const txValue = new BN(sellerDeposit).mul(new BN(qty)) - - let txOrder = await this.contractCashier.requestCreateOrder_ETH_ETH( - [from, - to, - helpers.product_price, - sellerDeposit, - helpers.buyer_deposit, - qty], - { - from: seller.address, - value: txValue - } - ); - - return returnTx ? txOrder: (txOrder.logs[0].args._tokenIdSupply).toString() - } - - async requestCreateOrder_TKN_TKN_Same_WithPermit(seller, from, to, sellerDeposit, qty) { - const txValue = new BN(sellerDeposit).mul(new BN(qty)) - - const nonce = await this.contractBSNTokenSAME.nonces(seller.address); - - const digest = await getApprovalDigest( - this.contractBSNTokenSAME, - seller.address, - this.contractCashier.address, - txValue, - nonce, - this.deadline - ) - - const { v, r, s } = ecsign( - Buffer.from(digest.slice(2), 'hex'), - Buffer.from(seller.pk.slice(2), 'hex')); - - let txOrder = await this.contractCashier.requestCreateOrder_TKN_TKN_WithPermit( - this.contractBSNTokenSAME.address, - this.contractBSNTokenSAME.address, - txValue, - this.deadline, - v,r,s, - [ - from, - to, - helpers.product_price, - sellerDeposit, - helpers.buyer_deposit, - qty - ], - { - from: seller.address - } - ); - - return (txOrder.logs[0].args._tokenIdSupply).toString() - } - - - async requestCreateOrder_TKN_TKN_WithPermit(seller, from, to, sellerDeposit, qty) { - const txValue = new BN(sellerDeposit).mul(new BN(qty)) - - const nonce = await this.contractBSNTokenDeposit.nonces(seller.address); - - const digest = await getApprovalDigest( - this.contractBSNTokenDeposit, - seller.address, - this.contractCashier.address, - txValue, - nonce, - this.deadline - ) - - const { v, r, s } = ecsign( - Buffer.from(digest.slice(2), 'hex'), - Buffer.from(seller.pk.slice(2), 'hex')); - - let txOrder = await this.contractCashier.requestCreateOrder_TKN_TKN_WithPermit( - this.contractBSNTokenPrice.address, - this.contractBSNTokenDeposit.address, - txValue, - this.deadline, - v,r,s, - [ - from, - to, - helpers.product_price, - sellerDeposit, - helpers.buyer_deposit, - qty - ], - { - from: seller.address - } - ); - - return (txOrder.logs[0].args._tokenIdSupply).toString() - } - - async requestCreateOrder_ETH_TKN_WithPermit(seller, from, to, sellerDeposit, qty, returnTx = false) { - const txValue = new BN(sellerDeposit).mul(new BN(qty)); - const nonce = await this.contractBSNTokenDeposit.nonces(seller.address); - - const digest = await getApprovalDigest( - this.contractBSNTokenDeposit, - seller.address, - this.contractCashier.address, - txValue, - nonce, - this.deadline - ) - - const { v, r, s } = ecsign( - Buffer.from(digest.slice(2), 'hex'), - Buffer.from(seller.pk.slice(2), 'hex')); - - - let txOrder = await this.contractCashier.requestCreateOrder_ETH_TKN_WithPermit( - this.contractBSNTokenDeposit.address, - txValue, - this.deadline, - v, r, s, - [ - from, - to, - helpers.product_price, - sellerDeposit, - helpers.buyer_deposit, - qty - ], - { - from: seller.address - } - ); - - return returnTx ? txOrder : (txOrder.logs[0].args._tokenIdSupply).toString() - } - - async requestCreateOrder_TKN_ETH(seller, from, to, sellerDeposit, qty) { - const txValue = new BN(sellerDeposit).mul(new BN(qty)); - - let txOrder = await this.contractCashier.requestCreateOrder_TKN_ETH( - this.contractBSNTokenPrice.address, - [ - from, - to, - helpers.product_price, - sellerDeposit, - helpers.buyer_deposit, - qty - ], - { - from: seller.address, - value: txValue - } - ); - - return (txOrder.logs[0].args._tokenIdSupply).toString() - } - - async commitToBuy_TKN_TKN_WithPermit(buyer, seller, tokenSupplyId) { - const txValue = new BN(helpers.buyer_deposit).add(new BN(helpers.product_price)) - const nonce1 = await this.contractBSNTokenDeposit.nonces(buyer.address); - - const digestDeposit = await getApprovalDigest( - this.contractBSNTokenDeposit, - buyer.address, - this.contractCashier.address, - helpers.buyer_deposit, - nonce1, - this.deadline - ) - - let VRS_DEPOSIT = ecsign( - Buffer.from(digestDeposit.slice(2), 'hex'), - Buffer.from(buyer.pk.slice(2), 'hex')); - - let vDeposit = VRS_DEPOSIT.v - let rDeposit = VRS_DEPOSIT.r - let sDeposit = VRS_DEPOSIT.s - - const nonce2 = await this.contractBSNTokenPrice.nonces(buyer.address); - - const digestPrice = await getApprovalDigest( - this.contractBSNTokenPrice, - buyer.address, - this.contractCashier.address, - helpers.product_price, - nonce2, - this.deadline - ) - - let VRS_PRICE = ecsign( - Buffer.from(digestPrice.slice(2), 'hex'), - Buffer.from(buyer.pk.slice(2), 'hex')); - - let vPrice = VRS_PRICE.v - let rPrice = VRS_PRICE.r - let sPrice = VRS_PRICE.s - - let CommitTx = await this.contractCashier.requestVoucher_TKN_TKN_WithPermit( - tokenSupplyId, - seller.address, - txValue, - this.deadline, - vPrice, rPrice, sPrice, - vDeposit, rDeposit, sDeposit, - { from: buyer.address }); - - let nestedValue = (await truffleAssert.createTransactionResult(this.contractVoucherKernel, CommitTx.tx)).logs - - let filtered = nestedValue.filter(e => e.event == 'LogVoucherDelivered')[0] - return filtered.returnValues['_tokenIdVoucher'] - } - - async commitToBuy_TKN_TKN_Same_WithPermit(buyer, seller, tokenSupplyId) { - const txValue = new BN(helpers.buyer_deposit).add(new BN(helpers.product_price)) - const nonce = await this.contractBSNTokenSAME.nonces(buyer.address); - - const digestTxValue = await getApprovalDigest( - this.contractBSNTokenSAME, - buyer.address, - this.contractCashier.address, - txValue, - nonce, - this.deadline - ) - - let VRS_TX_VALUE = ecsign( - Buffer.from(digestTxValue.slice(2), 'hex'), - Buffer.from(buyer.pk.slice(2), 'hex')); - - let v = VRS_TX_VALUE.v - let r = VRS_TX_VALUE.r - let s = VRS_TX_VALUE.s - - let CommitTx = await this.contractCashier.requestVoucher_TKN_TKN_Same_WithPermit( - tokenSupplyId, - seller.address, - txValue, - this.deadline, - v, r, s, - { from: buyer.address }); - - let nestedValue = (await truffleAssert.createTransactionResult(this.contractVoucherKernel, CommitTx.tx)).logs - - let filtered = nestedValue.filter(e => e.event == 'LogVoucherDelivered')[0] - return filtered.returnValues['_tokenIdVoucher'] - } - - async commitToBuy_ETH_TKN_WithPermit(buyer, seller, tokenSupplyId) { - const nonce1 = await this.contractBSNTokenDeposit.nonces(buyer.address); - - const digestDeposit = await getApprovalDigest( - this.contractBSNTokenDeposit, - buyer.address, - this.contractCashier.address, - helpers.buyer_deposit, - nonce1, - this.deadline - ) - - let { v, r, s } = ecsign( - Buffer.from(digestDeposit.slice(2), 'hex'), - Buffer.from(buyer.pk.slice(2), 'hex')); - - - let txOrder = await this.contractCashier.requestVoucher_ETH_TKN_WithPermit( - tokenSupplyId, - seller.address, - helpers.buyer_deposit, - this.deadline, - v, r, s, - { from: buyer.address, value: helpers.product_price.toString() } - ); - - let nestedValue = (await truffleAssert.createTransactionResult(this.contractVoucherKernel, txOrder.tx)).logs - - let filtered = nestedValue.filter(e => e.event == 'LogVoucherDelivered')[0] - return filtered.returnValues['_tokenIdVoucher'] - } - - async commitToBuy_ETH_ETH(buyer, seller, tokenSupplyId) { - const txValue = new BN(helpers.buyer_deposit).add(new BN(helpers.product_price)) - - let CommitTx = await this.contractCashier.requestVoucher_ETH_ETH(tokenSupplyId, seller.address, { from: buyer.address, value: txValue.toString() }); - - let nestedValue = (await truffleAssert.createTransactionResult(this.contractVoucherKernel, CommitTx.tx)).logs - - let filtered = nestedValue.filter(e => e.event == 'LogVoucherDelivered')[0] - return filtered.returnValues['_tokenIdVoucher'] - } - - async commitToBuy_TKN_ETH_WithPermit(buyer, seller, tokenSupplyId) { - const nonce1 = await this.contractBSNTokenPrice.nonces(buyer.address); - - const digestDeposit = await getApprovalDigest( - this.contractBSNTokenPrice, - buyer.address, - this.contractCashier.address, - helpers.product_price, - nonce1, - this.deadline - ) - - let { v, r, s } = ecsign( - Buffer.from(digestDeposit.slice(2), 'hex'), - Buffer.from(buyer.pk.slice(2), 'hex')); - - - let txOrder = await this.contractCashier.requestVoucher_TKN_ETH_WithPermit( - tokenSupplyId, - seller.address, - helpers.product_price, - this.deadline, - v, r, s, - { from: buyer.address, value: helpers.buyer_deposit } - ); - - let nestedValue = (await truffleAssert.createTransactionResult(this.contractVoucherKernel, txOrder.tx)).logs - - let filtered = nestedValue.filter(e => e.event == 'LogVoucherDelivered')[0] - return filtered.returnValues['_tokenIdVoucher'] - } - - async refund(voucherID, buyer) { - await this.contractVoucherKernel.refund(voucherID, { from: buyer }); - } - - async redeem(voucherID, buyer) { - await this.contractVoucherKernel.redeem(voucherID, { from: buyer }); - } - - async complain(voucherID, buyer) { - await this.contractVoucherKernel.complain(voucherID, { from: buyer }); - } - - async cancel(voucherID, seller) { - await this.contractVoucherKernel.cancelOrFault(voucherID, { from: seller }); - } - - async finalize(voucherID, deployer) { - await this.contractVoucherKernel.triggerFinalizeVoucher(voucherID, {from: deployer}) - } - - async withdraw(voucherID, deployer) { - const tx = await this.contractCashier.withdraw(voucherID, {from: deployer}); - console.log('GAS USED: ', tx.receipt.gasUsed); - return tx - } - - async withdrawWhenPaused(voucherID, executor) { - const tx = await this.contractCashier.withdrawWhenPaused(voucherID, {from: executor}); - console.log('GAS USED: ', tx.receipt.gasUsed); - return tx - } - - async pause(deployer) { - await this.contractCashier.pause({from: deployer}) - } - - async safeTransfer721(oldVoucherOwner, newVoucherOwner, voucherID, from) { - const arbitraryBytes = web3.utils.fromAscii('0x0').padEnd(66, '0') - return await this.contractERC1155ERC721 - .methods['safeTransferFrom(address,address,uint256,bytes)'] - (oldVoucherOwner, newVoucherOwner, voucherID, arbitraryBytes, from); - } - - async safeTransfer1155(oldSupplyOwner, newSupplyOwner, supplyID, qty, from) { - const arbitraryBytes = web3.utils.fromAscii('0x0').padEnd(66, '0') - return await this.contractERC1155ERC721 - .methods['safeTransferFrom(address,address,uint256,uint256,bytes)'] - (oldSupplyOwner, newSupplyOwner, supplyID, qty, arbitraryBytes, from); - } - - async safeBatchTransfer1155(oldSupplyOwner, newSupplyOwner, supplyIDs, values, from) { - const arbitraryBytes = web3.utils.fromAscii('0x0').padEnd(66, '0') - return await this.contractERC1155ERC721 - .methods['safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)'] - (oldSupplyOwner, newSupplyOwner, supplyIDs, values, arbitraryBytes, from); - } - - calcTotalAmountToRecipients(event, distributionAmounts, recipient, buyer, seller) { - if (event[recipient] == buyer) { - distributionAmounts.buyerAmount = new BN(distributionAmounts.buyerAmount.toString()).add(new BN(event._payment.toString())) - } else if (event[recipient] == seller) { - distributionAmounts.sellerAmount = new BN(distributionAmounts.sellerAmount.toString()).add(new BN(event._payment.toString())) - } else { - distributionAmounts.escrowAmount = new BN(distributionAmounts.escrowAmount.toString()).add(new BN(event._payment.toString())) + constructor () { + this.createOrder = '' + this.commitToBuy = '' + this.deadline = toWei(1) + } + + setContracts ( + erc1155721, voucherKernel, cashier, bsnTokenPrice, bsnTokenDeposit + ) { + this.contractERC1155ERC721 = erc1155721 + this.contractVoucherKernel = voucherKernel + this.contractCashier = cashier + this.contractBSNTokenPrice = bsnTokenPrice + this.contractBSNTokenDeposit = bsnTokenDeposit + this.contractBSNTokenSAME = bsnTokenPrice + } + + async requestCreateOrder_ETH_ETH ( + seller, from, to, sellerDeposit, qty, returnTx = false + ) { + const txValue = new BN(sellerDeposit).mul(new BN(qty)) + + let txOrder = await this.contractCashier.requestCreateOrder_ETH_ETH( + [ from, + to, + helpers.product_price, + sellerDeposit, + helpers.buyer_deposit, + qty ], + { + from: seller.address, + value: txValue + } + ) + + return returnTx ? + txOrder : + (txOrder.logs[0].args._tokenIdSupply).toString() + } + + async requestCreateOrder_TKN_TKN_Same_WithPermit ( + seller, from, to, sellerDeposit, qty + ) { + const txValue = new BN(sellerDeposit).mul(new BN(qty)) + + const nonce = await this.contractBSNTokenSAME.nonces(seller.address) + + const digest = await getApprovalDigest( + this.contractBSNTokenSAME, + seller.address, + this.contractCashier.address, + txValue, + nonce, + this.deadline + ) + + const { v, r, s } = ecsign( + Buffer.from(digest.slice(2), 'hex'), + Buffer.from(seller.pk.slice(2), 'hex')) + + let txOrder = await this.contractCashier + .requestCreateOrder_TKN_TKN_WithPermit( + this.contractBSNTokenSAME.address, + this.contractBSNTokenSAME.address, + txValue, + this.deadline, + v, r, s, + [ + from, + to, + helpers.product_price, + sellerDeposit, + helpers.buyer_deposit, + qty + ], + { + from: seller.address + } + ) + + return (txOrder.logs[0].args._tokenIdSupply).toString() + } + + async requestCreateOrder_TKN_TKN_WithPermit ( + seller, from, to, sellerDeposit, qty + ) { + const txValue = new BN(sellerDeposit).mul(new BN(qty)) + + const nonce = await this.contractBSNTokenDeposit.nonces(seller.address) + + const digest = await getApprovalDigest( + this.contractBSNTokenDeposit, + seller.address, + this.contractCashier.address, + txValue, + nonce, + this.deadline + ) + + const { v, r, s } = ecsign( + Buffer.from(digest.slice(2), 'hex'), + Buffer.from(seller.pk.slice(2), 'hex')) + + let txOrder = await this.contractCashier + .requestCreateOrder_TKN_TKN_WithPermit( + this.contractBSNTokenPrice.address, + this.contractBSNTokenDeposit.address, + txValue, + this.deadline, + v, r, s, + [ + from, + to, + helpers.product_price, + sellerDeposit, + helpers.buyer_deposit, + qty + ], + { + from: seller.address } + ) + + return (txOrder.logs[0].args._tokenIdSupply).toString() + } + + async requestCreateOrder_ETH_TKN_WithPermit ( + seller, from, to, sellerDeposit, qty, returnTx = false + ) { + const txValue = new BN(sellerDeposit).mul(new BN(qty)) + const nonce = await this.contractBSNTokenDeposit.nonces(seller.address) + + const digest = await getApprovalDigest( + this.contractBSNTokenDeposit, + seller.address, + this.contractCashier.address, + txValue, + nonce, + this.deadline + ) + + const { v, r, s } = ecsign( + Buffer.from(digest.slice(2), 'hex'), + Buffer.from(seller.pk.slice(2), 'hex')) + + let txOrder = await this.contractCashier + .requestCreateOrder_ETH_TKN_WithPermit( + this.contractBSNTokenDeposit.address, + txValue, + this.deadline, + v, r, s, + [ + from, + to, + helpers.product_price, + sellerDeposit, + helpers.buyer_deposit, + qty + ], + { + from: seller.address + } + ) + + return returnTx ? + txOrder : + (txOrder.logs[0].args._tokenIdSupply).toString() + } + + async requestCreateOrder_TKN_ETH ( + seller, from, to, sellerDeposit, qty + ) { + const txValue = new BN(sellerDeposit).mul(new BN(qty)) + + let txOrder = await this.contractCashier.requestCreateOrder_TKN_ETH( + this.contractBSNTokenPrice.address, + [ + from, + to, + helpers.product_price, + sellerDeposit, + helpers.buyer_deposit, + qty + ], + { + from: seller.address, + value: txValue + } + ) + + return (txOrder.logs[0].args._tokenIdSupply).toString() + } + + async commitToBuy_TKN_TKN_WithPermit (buyer, seller, tokenSupplyId) { + const txValue = new BN(helpers.buyer_deposit) + .add(new BN(helpers.product_price)) + const nonce1 = await this.contractBSNTokenDeposit.nonces(buyer.address) + + const digestDeposit = await getApprovalDigest( + this.contractBSNTokenDeposit, + buyer.address, + this.contractCashier.address, + helpers.buyer_deposit, + nonce1, + this.deadline + ) + + let VRS_DEPOSIT = ecsign( + Buffer.from(digestDeposit.slice(2), 'hex'), + Buffer.from(buyer.pk.slice(2), 'hex')) + + let vDeposit = VRS_DEPOSIT.v + let rDeposit = VRS_DEPOSIT.r + let sDeposit = VRS_DEPOSIT.s + + const nonce2 = await this.contractBSNTokenPrice.nonces(buyer.address) + + const digestPrice = await getApprovalDigest( + this.contractBSNTokenPrice, + buyer.address, + this.contractCashier.address, + helpers.product_price, + nonce2, + this.deadline + ) + + let VRS_PRICE = ecsign( + Buffer.from(digestPrice.slice(2), 'hex'), + Buffer.from(buyer.pk.slice(2), 'hex')) + + let vPrice = VRS_PRICE.v + let rPrice = VRS_PRICE.r + let sPrice = VRS_PRICE.s + + let CommitTx = await this.contractCashier + .requestVoucher_TKN_TKN_WithPermit( + tokenSupplyId, + seller.address, + txValue, + this.deadline, + vPrice, rPrice, sPrice, + vDeposit, rDeposit, sDeposit, + { from: buyer.address }) + + let nestedValue = + (await truffleAssert + .createTransactionResult(this.contractVoucherKernel, CommitTx.tx)) + .logs + + let filtered = nestedValue + .filter(e => e.event === 'LogVoucherDelivered')[0] + + return filtered.returnValues['_tokenIdVoucher'] + } + + async commitToBuy_TKN_TKN_Same_WithPermit (buyer, seller, tokenSupplyId) { + const txValue = new BN(helpers.buyer_deposit) + .add(new BN(helpers.product_price)) + const nonce = await this.contractBSNTokenSAME.nonces(buyer.address) + + const digestTxValue = await getApprovalDigest( + this.contractBSNTokenSAME, + buyer.address, + this.contractCashier.address, + txValue, + nonce, + this.deadline + ) + + let VRS_TX_VALUE = ecsign( + Buffer.from(digestTxValue.slice(2), 'hex'), + Buffer.from(buyer.pk.slice(2), 'hex')) + + let v = VRS_TX_VALUE.v + let r = VRS_TX_VALUE.r + let s = VRS_TX_VALUE.s + + let CommitTx = await this.contractCashier + .requestVoucher_TKN_TKN_Same_WithPermit( + tokenSupplyId, + seller.address, + txValue, + this.deadline, + v, r, s, + { from: buyer.address }) + + let nestedValue = + (await truffleAssert + .createTransactionResult(this.contractVoucherKernel, CommitTx.tx)) + .logs + + let filtered = nestedValue + .filter(e => e.event === 'LogVoucherDelivered')[0] + + return filtered.returnValues['_tokenIdVoucher'] + } + + async commitToBuy_ETH_TKN_WithPermit (buyer, seller, tokenSupplyId) { + const nonce1 = await this.contractBSNTokenDeposit.nonces(buyer.address) + + const digestDeposit = await getApprovalDigest( + this.contractBSNTokenDeposit, + buyer.address, + this.contractCashier.address, + helpers.buyer_deposit, + nonce1, + this.deadline + ) + + let { v, r, s } = ecsign( + Buffer.from(digestDeposit.slice(2), 'hex'), + Buffer.from(buyer.pk.slice(2), 'hex')) + + let txOrder = await this.contractCashier + .requestVoucher_ETH_TKN_WithPermit( + tokenSupplyId, + seller.address, + helpers.buyer_deposit, + this.deadline, + v, r, s, + { from: buyer.address, value: helpers.product_price.toString() } + ) + + let nestedValue = + (await truffleAssert + .createTransactionResult(this.contractVoucherKernel, txOrder.tx)) + .logs + + let filtered = nestedValue + .filter(e => e.event === 'LogVoucherDelivered')[0] + + return filtered.returnValues['_tokenIdVoucher'] + } + + async commitToBuy_ETH_ETH (buyer, seller, tokenSupplyId) { + const txValue = new BN(helpers.buyer_deposit) + .add(new BN(helpers.product_price)) + + let CommitTx = await this.contractCashier + .requestVoucher_ETH_ETH( + tokenSupplyId, + seller.address, + { + from: buyer.address, + value: txValue.toString() + }) + + let nestedValue = + (await truffleAssert + .createTransactionResult(this.contractVoucherKernel, CommitTx.tx)) + .logs + + let filtered = nestedValue + .filter(e => e.event === 'LogVoucherDelivered')[0] + + return filtered.returnValues['_tokenIdVoucher'] + } + + async commitToBuy_TKN_ETH_WithPermit (buyer, seller, tokenSupplyId) { + const nonce1 = await this.contractBSNTokenPrice.nonces(buyer.address) + + const digestDeposit = await getApprovalDigest( + this.contractBSNTokenPrice, + buyer.address, + this.contractCashier.address, + helpers.product_price, + nonce1, + this.deadline + ) + + let { v, r, s } = ecsign( + Buffer.from(digestDeposit.slice(2), 'hex'), + Buffer.from(buyer.pk.slice(2), 'hex')) + + let txOrder = await this.contractCashier + .requestVoucher_TKN_ETH_WithPermit( + tokenSupplyId, + seller.address, + helpers.product_price, + this.deadline, + v, r, s, + { from: buyer.address, value: helpers.buyer_deposit } + ) + + let nestedValue = + (await truffleAssert + .createTransactionResult(this.contractVoucherKernel, txOrder.tx)) + .logs + + let filtered = nestedValue + .filter(e => e.event === 'LogVoucherDelivered')[0] + + return filtered.returnValues['_tokenIdVoucher'] + } + + async refund (voucherID, buyer) { + await this.contractVoucherKernel + .refund(voucherID, { from: buyer }) + } + + async redeem (voucherID, buyer) { + await this.contractVoucherKernel + .redeem(voucherID, { from: buyer }) + } + + async complain (voucherID, buyer) { + await this.contractVoucherKernel + .complain(voucherID, { from: buyer }) + } + + async cancel (voucherID, seller) { + await this.contractVoucherKernel + .cancelOrFault(voucherID, { from: seller }) + } + + async finalize (voucherID, deployer) { + await this.contractVoucherKernel + .triggerFinalizeVoucher(voucherID, { from: deployer }) + } + + async withdraw (voucherID, deployer) { + const tx = await this.contractCashier + .withdraw(voucherID, { from: deployer }) + + console.log('GAS USED: ', tx.receipt.gasUsed) + + return tx + } + + async withdrawWhenPaused (voucherID, executor) { + const tx = await this.contractCashier + .withdrawWhenPaused(voucherID, { from: executor }) + + console.log('GAS USED: ', tx.receipt.gasUsed) + + return tx + } + + async pause (deployer) { + await this.contractCashier.pause({ from: deployer }) + } + + async safeTransfer721 ( + oldVoucherOwner, newVoucherOwner, voucherID, from + ) { + const arbitraryBytes = web3.utils.fromAscii('0x0').padEnd(66, '0') + + const methodSignature = 'safeTransferFrom(' + + 'address,' + + 'address,' + + 'uint256,' + + 'bytes)' + const method = this.contractERC1155ERC721.methods[methodSignature] + + return await method( + oldVoucherOwner, + newVoucherOwner, + voucherID, + arbitraryBytes, + from) + } + + async safeTransfer1155 ( + oldSupplyOwner, newSupplyOwner, supplyID, qty, from + ) { + const arbitraryBytes = web3.utils.fromAscii('0x0').padEnd(66, '0') + + const methodSignature = 'safeTransferFrom(' + + 'address,' + + 'address,' + + 'uint256,' + + 'uint256,' + + 'bytes)' + const method = this.contractERC1155ERC721.methods[methodSignature] + + return await method( + oldSupplyOwner, + newSupplyOwner, + supplyID, + qty, + arbitraryBytes, + from) + } + + async safeBatchTransfer1155 ( + oldSupplyOwner, newSupplyOwner, supplyIDs, values, from + ) { + const arbitraryBytes = web3.utils.fromAscii('0x0').padEnd(66, '0') + + const methodSignature = 'safeBatchTransferFrom(' + + 'address,' + + 'address,' + + 'uint256[],' + + 'uint256[],' + + 'bytes)' + const method = this.contractERC1155ERC721.methods[methodSignature] + + return await method( + oldSupplyOwner, + newSupplyOwner, + supplyIDs, + values, + arbitraryBytes, + from) + } + + calcTotalAmountToRecipients ( + event, distributionAmounts, recipient, buyer, seller + ) { + if (event[recipient] === buyer) { + distributionAmounts.buyerAmount = + new BN(distributionAmounts.buyerAmount.toString()) + .add(new BN(event._payment.toString())) + } else if (event[recipient] === seller) { + distributionAmounts.sellerAmount = + new BN(distributionAmounts.sellerAmount.toString()) + .add(new BN(event._payment.toString())) + } else { + distributionAmounts.escrowAmount = + new BN(distributionAmounts.escrowAmount.toString()) + .add(new BN(event._payment.toString())) } + } - async mintTokens(tokenContract, to, value) { - - await this[tokenContract].mint(to, value); - } + async mintTokens (tokenContract, to, value) { + await this[tokenContract].mint(to, value) + } - static async getCurrTimestamp() { - let blockNumber = await web3.eth.getBlockNumber() - let block = await web3.eth.getBlock(blockNumber) + static async getCurrTimestamp () { + let blockNumber = await web3.eth.getBlockNumber() + let block = await web3.eth.getBlock(blockNumber) - return block.timestamp - } + return block.timestamp + } } -module.exports = Utils \ No newline at end of file +module.exports = Utils diff --git a/testHelpers/utilsBuilder.js b/testHelpers/utilsBuilder.js index 58ad2d74..aff462b0 100644 --- a/testHelpers/utilsBuilder.js +++ b/testHelpers/utilsBuilder.js @@ -1,67 +1,81 @@ - // @ts-nocheck const Utils = require('./utils') class UtilsBuilder { - - constructor() { - this.utils = new Utils() - } - - static NEW () { - return new UtilsBuilder() - }; - - ETH_ETH () { - this.utils.createOrder = this.utils.requestCreateOrder_ETH_ETH - this.utils.commitToBuy = this.utils.commitToBuy_ETH_ETH - - return this - } - - ERC20withPermit () { - this.ETH_TKN = this.ETH_TKN_WithPermit - this.TKN_TKN = this.TKN_TKN_WithPermit - this.TKN_ETH = this.TKN_ETH_WithPermit - this.TKN_TKN_SAME = this.TKN_TKN_SameWithPermit - - return this - } - - build(erc1155721, voucherKernel, cashier, bsnTokenPrice, bsnTokenDeposit) { - this.utils.setContracts(erc1155721, voucherKernel, cashier, bsnTokenPrice, bsnTokenDeposit); - return this.utils; - } - - ETH_TKN_WithPermit() { - this.utils.createOrder = this.utils.requestCreateOrder_ETH_TKN_WithPermit - this.utils.commitToBuy = this.utils.commitToBuy_ETH_TKN_WithPermit - - return this - } - - TKN_TKN_WithPermit() { - this.utils.createOrder = this.utils.requestCreateOrder_TKN_TKN_WithPermit - this.utils.commitToBuy = this.utils.commitToBuy_TKN_TKN_WithPermit - - return this - } - - TKN_TKN_SameWithPermit() { - this.utils.createOrder = this.utils.requestCreateOrder_TKN_TKN_Same_WithPermit - this.utils.commitToBuy = this.utils.commitToBuy_TKN_TKN_Same_WithPermit - - return this - } - - TKN_ETH_WithPermit() { - this.utils.createOrder = this.utils.requestCreateOrder_TKN_ETH - this.utils.commitToBuy = this.utils.commitToBuy_TKN_ETH_WithPermit - - return this - } - - + constructor () { + this.utils = new Utils() + } + + static NEW () { + return new UtilsBuilder() + }; + + ETH_ETH () { + this.utils.createOrder = + this.utils.requestCreateOrder_ETH_ETH + this.utils.commitToBuy = + this.utils.commitToBuy_ETH_ETH + + return this + } + + ERC20withPermit () { + this.ETH_TKN = this.ETH_TKN_WithPermit + this.TKN_TKN = this.TKN_TKN_WithPermit + this.TKN_ETH = this.TKN_ETH_WithPermit + this.TKN_TKN_SAME = this.TKN_TKN_SameWithPermit + + return this + } + + build ( + erc1155721, voucherKernel, cashier, bsnTokenPrice, bsnTokenDeposit + ) { + this.utils.setContracts( + erc1155721, + voucherKernel, + cashier, + bsnTokenPrice, + bsnTokenDeposit) + + return this.utils + } + + ETH_TKN_WithPermit () { + this.utils.createOrder = + this.utils.requestCreateOrder_ETH_TKN_WithPermit + this.utils.commitToBuy = + this.utils.commitToBuy_ETH_TKN_WithPermit + + return this + } + + TKN_TKN_WithPermit () { + this.utils.createOrder = + this.utils.requestCreateOrder_TKN_TKN_WithPermit + this.utils.commitToBuy = + this.utils.commitToBuy_TKN_TKN_WithPermit + + return this + } + + TKN_TKN_SameWithPermit () { + this.utils.createOrder = + this.utils.requestCreateOrder_TKN_TKN_Same_WithPermit + this.utils.commitToBuy = + this.utils.commitToBuy_TKN_TKN_Same_WithPermit + + return this + } + + TKN_ETH_WithPermit () { + this.utils.createOrder = + this.utils.requestCreateOrder_TKN_ETH + this.utils.commitToBuy = + this.utils.commitToBuy_TKN_ETH_WithPermit + + return this + } } -module.exports = UtilsBuilder; \ No newline at end of file +module.exports = UtilsBuilder diff --git a/truffle-config.js b/truffle-config.js index ad5693bd..eeae6bfa 100644 --- a/truffle-config.js +++ b/truffle-config.js @@ -47,14 +47,20 @@ module.exports = { // development: { host: '127.0.0.1', // Localhost (default: none) - port: 8545, // Standard Ethereum port (default: none) - network_id: '*' // Any network (default: none) + port: 8545, // Standard Ethereum port (default: none) + network_id: '*' // Any network (default: none) + }, + + test: { + host: process.env.HOST, // Localhost (default: none) + port: process.env.PORT, // Standard Ethereum port (default: none) + network_id: '*' // Any network (default: none) }, coverage: { host: '127.0.0.1', // Localhost (default: none) - port: 8555, // Test Coverage Port - network_id: '*' // Any network (default: none) + port: 8555, // Test Coverage Port + network_id: '*' // Any network (default: none) }, ropsten: {