1247 lines
51 KiB
JavaScript
1247 lines
51 KiB
JavaScript
const Birdcontract = artifacts.require("CryptoBirdies");
|
|
const Marketcontract = artifacts.require("MarketPlace");
|
|
const TestBirdies = artifacts.require("TestBirdies");
|
|
const TestMarket = artifacts.require("TestMarket");
|
|
const TestErc = artifacts.require("TestErc");
|
|
const assert = require("chai").assert;
|
|
const truffleAssert = require("truffle-assertions");
|
|
const Web3 = require('web3');
|
|
const web3 = new Web3(Web3.givenProvider);
|
|
var testBirdiesInstance;
|
|
var testMarketInstance;
|
|
|
|
contract("CryptoBirdies", (accounts) => {
|
|
|
|
async function createParents() {
|
|
await testBirdiesInstance.testCreateBird(101, accounts[0]);
|
|
await testBirdiesInstance.testCreateBird(202, accounts[0]);
|
|
}
|
|
|
|
it("should deploy correctly", async () => {
|
|
await truffleAssert.passes(Birdcontract.deployed("CryptoBird", "CBX"));
|
|
});
|
|
|
|
beforeEach(async () => {
|
|
testBirdiesInstance = await TestBirdies.new("CryptoBird", "CBX");
|
|
testMarketInstance = await TestMarket.new(testBirdiesInstance.address);
|
|
});
|
|
|
|
describe("constructor()", () =>{
|
|
it("should create and emit a correct birth event for bird0", async () => {
|
|
const zeroAddress = '0x0000000000000000000000000000000000000000';
|
|
|
|
var birdZero = await truffleAssert.createTransactionResult(
|
|
testBirdiesInstance, testBirdiesInstance.transactionHash);
|
|
|
|
truffleAssert.eventEmitted(birdZero, 'Birth', (ev) => {
|
|
return ev.owner == zeroAddress && ev.birdId == 0 && ev.mumId == 0 && ev.dadId == 0 &&
|
|
ev.genes == 115792089237316195423570985008687907853269984665640564039457584007913129639935;
|
|
}, "Event was NOT emitted with correct parameters");
|
|
});
|
|
});
|
|
|
|
describe("getContractOwner()", () =>{
|
|
it("should get the owner of the smart contract", async () => {
|
|
var owner = await testBirdiesInstance.getContractOwner();
|
|
|
|
assert.strictEqual(owner, accounts[0], "The owner was not returned correctly");
|
|
});
|
|
});
|
|
|
|
describe("breed()", () =>{
|
|
|
|
it("should pass, if both parents are owned by msg.sender", async () => {
|
|
await createParents();
|
|
|
|
await truffleAssert.passes(testBirdiesInstance.breed(1, 2));
|
|
});
|
|
|
|
it("should revert, if only the dad is owned by msg.sender", async () => {
|
|
await testBirdiesInstance.testCreateBird(101, accounts[0]);
|
|
await testBirdiesInstance.testCreateBird(202, accounts[1]);
|
|
|
|
await truffleAssert.reverts(testBirdiesInstance.breed(1, 2));
|
|
});
|
|
|
|
it("should revert, if only the mum is owned by msg.sender", async () => {
|
|
await testBirdiesInstance.testCreateBird(101, accounts[0]);
|
|
await testBirdiesInstance.testCreateBird(202, accounts[1]);
|
|
|
|
await truffleAssert.reverts(testBirdiesInstance.breed(2, 1));
|
|
});
|
|
|
|
it("should set the mum and dad IDs for the new bird correctly", async () => {
|
|
await createParents();
|
|
|
|
await testBirdiesInstance.breed(1, 2); // Bird3 = Baby
|
|
var baby = await testBirdiesInstance.getBird(3);
|
|
|
|
assert.equal(baby.dadId, 1, "IDs were not set correctly");
|
|
assert.equal(baby.mumId, 2, "IDs were not set correctly");
|
|
});
|
|
|
|
it("should return the child's generation correctly, if the dad's generation is less than mum's"
|
|
, async () => {
|
|
|
|
//the testfunction enables to use deterministic generations
|
|
//checking the baby for generation makes little sense
|
|
await testBirdiesInstance.testCreateGenXBird(5, 101, accounts[0]);//Bird1
|
|
await testBirdiesInstance.testCreateGenXBird(7, 202, accounts[0]);//Bird2
|
|
|
|
await testBirdiesInstance.breed(1, 2); //Bird3 - Bird1=dad, Bird2=mum
|
|
|
|
var baby = await testBirdiesInstance.getBird(3);
|
|
|
|
assert.equal(baby.generation, 6, "The generation was not set correctly")
|
|
});
|
|
|
|
it("should return the child's generation correctly, if the mum's generation is less than dad's"
|
|
, async () => {
|
|
await testBirdiesInstance.testCreateGenXBird(5, 101, accounts[0]);//Bird1
|
|
await testBirdiesInstance.testCreateGenXBird(7, 202, accounts[0]);//Bird2
|
|
|
|
await testBirdiesInstance.breed(2, 1); //Bird3 - Bird1=mum, Bird2=dad
|
|
var baby = await testBirdiesInstance.getBird(3);
|
|
|
|
assert.equal(baby.generation, 6, "The generation was not set correctly")
|
|
});
|
|
|
|
it("should return the child's generation correctly, if the parents have the same generation"
|
|
, async () => {
|
|
await testBirdiesInstance.testCreateGenXBird(4, 101, accounts[0]);//Bird1
|
|
await testBirdiesInstance.testCreateGenXBird(4, 202, accounts[0]);//Bird2
|
|
|
|
await testBirdiesInstance.breed(1, 2); //Bird3 - Bird1=dad, Bird2=mum
|
|
var baby = await testBirdiesInstance.getBird(3);
|
|
|
|
assert.equal(baby.generation, 5, "The generation was not set correctly")
|
|
});
|
|
|
|
it("should emit a birth event with correct parameters", async () => {
|
|
await createParents();
|
|
|
|
var birdy = await testBirdiesInstance.breed(1, 2);
|
|
|
|
truffleAssert.eventEmitted(birdy, 'Birth', (ev) => {
|
|
return ev.owner == accounts[0] && ev.birdId == 3 && ev.mumId == 2 && ev.dadId == 1;
|
|
}, "Event was NOT emitted with correct parameters");
|
|
});
|
|
});
|
|
|
|
describe("supportsInterface()", () =>{
|
|
it("should check, if the contract supports IERC721", async () => {
|
|
var testIERC721 = await testBirdiesInstance.supportsInterface("0x80ac58cd");
|
|
|
|
assert.strictEqual(testIERC721, true, "The contract does not support IERC721");
|
|
});
|
|
|
|
it("should check, if the contract supports IERC165", async () => {
|
|
var testIERC165 = await testBirdiesInstance.supportsInterface("0x01ffc9a7");
|
|
|
|
assert.strictEqual(testIERC165, true, "The contract does not support IERC721");
|
|
});
|
|
});
|
|
|
|
describe("createBirdGen0()", () =>{
|
|
it("should allow only the owner of the contract to create a bird", async () => {
|
|
await truffleAssert.reverts(testBirdiesInstance.createBirdGen0(101, { from: accounts[1] }));
|
|
});
|
|
|
|
it("should set the contract owner as owner of the new bird", async () => {
|
|
await testBirdiesInstance.createBirdGen0(101);
|
|
var owner = await testBirdiesInstance.ownerOf(1);
|
|
var contractOwner = await testBirdiesInstance.getContractOwner();
|
|
|
|
assert.strictEqual(owner, contractOwner, "The contract owner is not owner of this Gen0 bird");
|
|
});
|
|
|
|
it("should have generation 0", async () => {
|
|
await testBirdiesInstance.createBirdGen0(101);
|
|
var result = await testBirdiesInstance.getBird(1);
|
|
|
|
assert.equal(result.generation, 0, "The generation is incorrect");
|
|
});
|
|
|
|
it("should have the same DNA that is used when the function is called", async () => {
|
|
await testBirdiesInstance.createBirdGen0(101);
|
|
var result = await testBirdiesInstance.getBird(1);
|
|
|
|
assert.equal(result.genes, 101, "The genes are incorrect");
|
|
});
|
|
|
|
it("should add one to the Gen0 counter", async () => {
|
|
await testBirdiesInstance.createBirdGen0(101);
|
|
var result = await testBirdiesInstance.gen0Counter();
|
|
|
|
assert.equal(result, 1, "The counter is incorrect");
|
|
});
|
|
|
|
it("should only allow a maximum of 10 Gen0 birds to be created", async () => {
|
|
await testBirdiesInstance.testSetGenCounter(10);
|
|
|
|
//this should not work for an eleventh Gen0 bird.
|
|
await truffleAssert.reverts(testBirdiesInstance.createBirdGen0(111));
|
|
});
|
|
|
|
it("should call _createBird() and _transfer() and emit a birth event with correct parameters", async () => {
|
|
var birdy = await testBirdiesInstance.createBirdGen0(101);
|
|
|
|
truffleAssert.eventEmitted(birdy, 'Birth', (ev) => {
|
|
return ev.owner == accounts[0] && ev.birdId == 1 && ev.mumId == 0 && ev.dadId == 0 && ev.genes == 101;
|
|
}, "Event was NOT emitted with correct parameters");
|
|
});
|
|
});
|
|
|
|
describe("getBird()", () =>{
|
|
it("should return the correct genes of a bird", async () => {
|
|
await testBirdiesInstance.testCreateBird(101, accounts[0]);
|
|
|
|
var result = await testBirdiesInstance.getBird(1);
|
|
|
|
assert.equal(result.genes, 101, "The genes are incorrect");
|
|
});
|
|
|
|
it("should return the correct birthTime of a bird", async () => {
|
|
var startTime = Date.now();
|
|
await testBirdiesInstance.testCreateBird(101, accounts[0]);
|
|
var endTime = Date.now();
|
|
var result = await testBirdiesInstance.getBird(1);
|
|
|
|
//it is not possible to test the exact birthtime, but this test
|
|
//makes sure the birthTime is within a narrow time window
|
|
assert(startTime/1000 <= result.birthTime <= endTime/1000, "The birthTime is incorrect");
|
|
});
|
|
|
|
it("should return the correct mumId of a bird", async () => {
|
|
await testBirdiesInstance.testCreateBird(101, accounts[0]);
|
|
|
|
var result = await testBirdiesInstance.getBird(1);
|
|
|
|
assert.equal(result.mumId, 0, "The id for the mum is incorrect");
|
|
});
|
|
|
|
it("should return the correct dadId of a bird", async () => {
|
|
await testBirdiesInstance.testCreateBird(101, accounts[0]);
|
|
|
|
var result = await testBirdiesInstance.getBird(1);
|
|
|
|
assert.equal(result.dadId, 0, "The id for the dad is incorrect");
|
|
});
|
|
|
|
it("should return the correct generation of a bird", async () => {
|
|
await testBirdiesInstance.testCreateBird(101, accounts[0]);
|
|
|
|
var result = await testBirdiesInstance.getBird(1);
|
|
|
|
assert.equal(result.generation, 0, "The generation is not zero");
|
|
});
|
|
|
|
it("should revert, if the bird does not exist", async () => {
|
|
await truffleAssert.reverts(testBirdiesInstance.getBird(5));
|
|
});
|
|
});
|
|
|
|
describe("getAllBirdsOfOwner()", () =>{
|
|
it("should return all birds owned by an address", async () => {
|
|
await testBirdiesInstance.testCreateBird(101, accounts[0]);
|
|
await testBirdiesInstance.testCreateBird(202, accounts[1]);
|
|
|
|
var testAllBirdsOfOwner = await testBirdiesInstance.getAllBirdsOfOwner(accounts[1]);
|
|
|
|
assert.equal(testAllBirdsOfOwner.length, 1, "The number of birds was not returned correctly");
|
|
});
|
|
});
|
|
|
|
describe("balanceOf()", () =>{
|
|
it("should return the correct balance of tokens owned by an address", async () => {
|
|
var numberTokens = await testBirdiesInstance.balanceOf(accounts[0]);
|
|
|
|
//initally the balance should be 0
|
|
assert.equal(numberTokens, 0, "The record of tokens is flawed and can't be trusted");
|
|
|
|
await testBirdiesInstance.testCreateBird(101, accounts[0]);
|
|
|
|
//after the creation of the test bird, the balance should be 1
|
|
numberTokens = await testBirdiesInstance.balanceOf(accounts[0]);
|
|
|
|
assert.equal(numberTokens, 1, "The record of tokens is flawed and can't be trusted");
|
|
});
|
|
});
|
|
|
|
describe("totalSupply()", () =>{
|
|
it("should record the total supply of tokens", async () => {
|
|
await testBirdiesInstance.testCreateBird(101, accounts[0]);
|
|
|
|
//the total supply should be Bird0 and the test bird created here.
|
|
var supply = await testBirdiesInstance.totalSupply();
|
|
|
|
assert.equal(supply, 2, "The record of total supply is flawed and can't be trusted");
|
|
});
|
|
});
|
|
|
|
describe("name()", () =>{
|
|
it("should return the name of the native token 'CryptoBird'", async () => {
|
|
var testName = await testBirdiesInstance.name();
|
|
|
|
assert.equal(testName, "CryptoBird", "Token wasn't constructed correctly");
|
|
});
|
|
});
|
|
|
|
describe("symbol()", () =>{
|
|
it("should return the ticker symbol 'CBX'", async () => {
|
|
var testSymbol = await testBirdiesInstance.symbol();
|
|
|
|
assert.equal(testSymbol, "CBX", "Symbol wasn't constructed correctly");
|
|
});
|
|
});
|
|
|
|
describe("ownerOf()", () =>{
|
|
it("should return the correct owner of the token", async () => {
|
|
await testBirdiesInstance.testCreateBird(101, accounts[0]);
|
|
|
|
var testOwner = await testBirdiesInstance.ownerOf(1);
|
|
|
|
assert.strictEqual(testOwner, accounts[0], "The owner of the token is incorrect");
|
|
});
|
|
|
|
it("should revert, if the ID does not exist", async () => {
|
|
await truffleAssert.reverts(testBirdiesInstance.ownerOf(5));
|
|
});
|
|
});
|
|
|
|
describe("transfer()", () =>{
|
|
it("should not allow transfer to the burn address", async () => {
|
|
const zeroAddress = '0x0000000000000000000000000000000000000000';
|
|
await testBirdiesInstance.testCreateBird(101, accounts[0]);
|
|
|
|
await truffleAssert.reverts(testBirdiesInstance.transfer(zeroAddress, 0));
|
|
});
|
|
|
|
it("should not allow transfer to the contract address", async () => {
|
|
const contractAddress = await testBirdiesInstance.address;
|
|
await testBirdiesInstance.testCreateBird(101, accounts[0]);
|
|
|
|
await truffleAssert.reverts(testBirdiesInstance.transfer(contractAddress, 0));
|
|
});
|
|
|
|
it("should emit a transfer event when a transfer was successful", async () => {
|
|
await testBirdiesInstance.testCreateBird(101, accounts[0]);
|
|
|
|
var testTransfer = await testBirdiesInstance.transfer(accounts[1], 1);
|
|
|
|
truffleAssert.eventEmitted(testTransfer, 'Transfer', (ev) => {
|
|
return ev.from == accounts[0] && ev.to == accounts[1] && ev.tokenId == 1;
|
|
}, "Transfer event should have been emitted with correct parameters");
|
|
});
|
|
|
|
it("should revert if msg.sender does not own the bird", async () => {
|
|
await testBirdiesInstance.testCreateBird(101, accounts[0]);
|
|
|
|
await truffleAssert.reverts(testBirdiesInstance.transfer(accounts[1], 1, { from: accounts[2] }));
|
|
});
|
|
|
|
it("should check balances and transfer a token from one account to another", async () => {
|
|
await testBirdiesInstance.testCreateBird(101, accounts[0]);
|
|
|
|
//sender initially has one bird
|
|
var numberTokensSender = await testBirdiesInstance.balanceOf(accounts[0]);
|
|
assert.equal(numberTokensSender, 1, "Token balance is incorrect");
|
|
|
|
//recipient initially has no bird
|
|
var numberTokensRecipient = await testBirdiesInstance.balanceOf(accounts[1]);
|
|
assert.equal(numberTokensRecipient, 0, "Token balance is incorrect");
|
|
|
|
await testBirdiesInstance.transfer(accounts[1], 1);
|
|
|
|
//sender has no more birds
|
|
numberTokensSender = await testBirdiesInstance.balanceOf(accounts[0]);
|
|
assert.equal(numberTokensSender, 0, "Token balance is incorrect");
|
|
|
|
//recipient now has one bird
|
|
numberTokensRecipient = await testBirdiesInstance.balanceOf(accounts[1]);
|
|
assert.equal(numberTokensRecipient, 1, "Token balance is incorrect");
|
|
});
|
|
});
|
|
|
|
describe("approve()", () =>{
|
|
it("should set operator approval for one bird and emit the correct event", async () => {
|
|
await testBirdiesInstance.testCreateBird(101, accounts[0]);
|
|
var marketAddress = await testMarketInstance.address;
|
|
|
|
var approval = await testBirdiesInstance.approve(marketAddress, 1);
|
|
|
|
truffleAssert.eventEmitted(approval, 'Approval', (ev) => {
|
|
return ev.owner == accounts[0] && ev.approved == marketAddress && ev.tokenId == 1;
|
|
}, "Event was NOT emitted with correct parameters");
|
|
});
|
|
|
|
it("should revert, if msg.sender is not the owner", async () => {
|
|
await testBirdiesInstance.testCreateBird(101, accounts[0]);
|
|
var marketAddress = await testMarketInstance.address;
|
|
|
|
await truffleAssert.reverts(testBirdiesInstance.approve(marketAddress, 1, { from: accounts[2] }));
|
|
});
|
|
});
|
|
|
|
describe("setApprovalForAll()", () =>{
|
|
it("should set operator approval for all birds of an owner and emit the correct event", async () => {
|
|
|
|
//create two birds
|
|
await testBirdiesInstance.testCreateBird(101, accounts[0]);
|
|
await testBirdiesInstance.testCreateBird(202, accounts[0]);
|
|
var marketAddress = await testMarketInstance.address;
|
|
|
|
//give market contract operator approval for both of them
|
|
var approvalForAll = await testBirdiesInstance.setApprovalForAll(marketAddress, true);
|
|
|
|
//ensure correct event is emitted
|
|
truffleAssert.eventEmitted(approvalForAll, 'ApprovalForAll', (ev) => {
|
|
return ev.owner == accounts[0] && ev.operator == marketAddress && ev.approved == true;
|
|
}, "Event was NOT emitted with correct parameters");
|
|
});
|
|
|
|
it("should remove operator approval for all birds of an owner and emit the correct event", async () => {
|
|
|
|
//create two birds
|
|
await testBirdiesInstance.testCreateBird(101, accounts[0]);
|
|
await testBirdiesInstance.testCreateBird(202, accounts[0]);
|
|
var marketAddress = await testMarketInstance.address;
|
|
|
|
//give market contract operator approval for both of them
|
|
var approvalForAll = await testBirdiesInstance.setApprovalForAll(marketAddress, true);
|
|
|
|
//remove market contract operator approval for both of them
|
|
var approvalForAll = await testBirdiesInstance.setApprovalForAll(marketAddress, false);
|
|
|
|
//check for the correct event
|
|
truffleAssert.eventEmitted(approvalForAll, 'ApprovalForAll', (ev) => {
|
|
return ev.owner == accounts[0] && ev.operator == marketAddress && ev.approved == false;
|
|
}, "Event was NOT emitted with correct parameters");
|
|
});
|
|
|
|
it("should allow more than one operator approval for all birds of an owner and emit the correct events",
|
|
async () => {
|
|
|
|
//create two test birds
|
|
await testBirdiesInstance.testCreateBird(101, accounts[0]);
|
|
await testBirdiesInstance.testCreateBird(202, accounts[0]);
|
|
var marketAddress = await testMarketInstance.address;
|
|
|
|
//give market contract operator approval
|
|
var approvalForMarketContract = await testBirdiesInstance.setApprovalForAll(marketAddress, true);
|
|
|
|
//check for correct event
|
|
truffleAssert.eventEmitted(approvalForMarketContract, 'ApprovalForAll', (ev) => {
|
|
return ev.owner == accounts[0] && ev.operator == marketAddress && ev.approved == true;
|
|
}, "Event was NOT emitted with correct parameters");
|
|
|
|
//additionally give accounts[1] the same approval
|
|
var approvalForAddress = await testBirdiesInstance.setApprovalForAll(accounts[1], true);
|
|
|
|
//this should work and emit the correct event
|
|
truffleAssert.eventEmitted(approvalForAddress, 'ApprovalForAll', (ev) => {
|
|
return ev.owner == accounts[0] && ev.operator == accounts[1] && ev.approved == true;
|
|
}, "Event was NOT emitted with correct parameters");
|
|
});
|
|
});
|
|
|
|
describe("getApproved()", () =>{
|
|
it("should return the approved operator for a bird", async () => {
|
|
|
|
//create test bird
|
|
await testBirdiesInstance.testCreateBird(101, accounts[0]);
|
|
var marketAddress = await testMarketInstance.address;
|
|
|
|
//give market contract operator approval for this one bird
|
|
await testBirdiesInstance.approve(marketAddress, 1);
|
|
|
|
//return address of operator for bird 1
|
|
var approvedOperator = await testBirdiesInstance.getApproved(1);
|
|
|
|
//the approved operator should be the market contract
|
|
assert.strictEqual(approvedOperator, marketAddress, "The operator was NOT returned correctly");
|
|
});
|
|
});
|
|
|
|
describe("isApprovedForAll()", () =>{
|
|
it("should return approved status for an operator", async () => {
|
|
|
|
//create two test birds
|
|
await testBirdiesInstance.testCreateBird(101, accounts[0]);
|
|
await testBirdiesInstance.testCreateBird(202, accounts[0]);
|
|
var marketAddress = await testMarketInstance.address;
|
|
|
|
//set operator approval for the market contract for all birds
|
|
await testBirdiesInstance.setApprovalForAll(marketAddress, true);
|
|
|
|
//query for who has operator approval for all of accounts[0]'s birds
|
|
var hasApprovalForAll = await testBirdiesInstance.isApprovedForAll(accounts[0], marketAddress);
|
|
assert.strictEqual(hasApprovalForAll, true, "The status was NOT returned correctly");
|
|
});
|
|
});
|
|
|
|
describe("safeTransferFrom()", () =>{
|
|
it("should pass, if msg.sender is owner", async () => {
|
|
|
|
//create one test bird
|
|
await testBirdiesInstance.testCreateBird(101, accounts[0]);
|
|
|
|
//the owner of the bird intiates the safe transfer successfully
|
|
await truffleAssert.passes(testBirdiesInstance.safeTransferFrom(
|
|
accounts[0], accounts[1], 1, { from: accounts[0]}));
|
|
});
|
|
|
|
it("should pass, if msg.sender has approval for this token", async () => {
|
|
|
|
//create test bird
|
|
await testBirdiesInstance.testCreateBird(101, accounts[0]);
|
|
|
|
//set individual operator approval for this one bird for accounts[2]
|
|
await testBirdiesInstance.approve(accounts[2], 1);
|
|
|
|
//the operator should now be able to execute the safe transfer
|
|
await truffleAssert.passes(testBirdiesInstance.safeTransferFrom(
|
|
accounts[0], accounts[1], 1, {from: accounts[2]}));
|
|
});
|
|
|
|
it("should pass, if msg.sender has operator approval for this owner", async () => {
|
|
|
|
//create two test birds
|
|
await testBirdiesInstance.testCreateBird(101, accounts[0]);
|
|
await testBirdiesInstance.testCreateBird(202, accounts[0]);
|
|
|
|
//give accounts[2] general operator approval for all birds
|
|
await testBirdiesInstance.setApprovalForAll(accounts[2], true);
|
|
|
|
//the operator should be able to transfer that bird
|
|
await truffleAssert.passes(testBirdiesInstance.safeTransferFrom(
|
|
accounts[0], accounts[1], 1, {from: accounts[2]}));
|
|
});
|
|
|
|
it("should revert, if msg.sender is not owner or operator for a token", async () => {
|
|
|
|
//create one test bird
|
|
await testBirdiesInstance.testCreateBird(101, accounts[0]);
|
|
|
|
//let an address call the safe transfer function that is not owner, nor operator
|
|
//this operations must fail
|
|
await truffleAssert.reverts(testBirdiesInstance.safeTransferFrom(
|
|
accounts[0], accounts[1], 1, { from: accounts[2]}));
|
|
});
|
|
|
|
it("should revert, if msg.sender is has no approval for this token", async () => {
|
|
|
|
//create one test bird
|
|
await testBirdiesInstance.testCreateBird(101, accounts[0]);
|
|
|
|
//make accounts[1] operator for this bird
|
|
await testBirdiesInstance.approve(accounts[1], 1);
|
|
|
|
//the transfer is expected to fail initiated by someone else
|
|
await truffleAssert.reverts(testBirdiesInstance.safeTransferFrom(
|
|
accounts[0], accounts[1], 1, { from: accounts[2]}));
|
|
});
|
|
|
|
it("should revert, if msg.sender has no operator rights for this owner", async () => {
|
|
|
|
//create one test bird
|
|
await testBirdiesInstance.testCreateBird(101, accounts[0]);
|
|
|
|
//make accounts[2] general operator accounts[0]
|
|
await testBirdiesInstance.setApprovalForAll(accounts[2], true);
|
|
|
|
//the transfer is expected to fail initiated by someone else
|
|
await truffleAssert.reverts(testBirdiesInstance.safeTransferFrom(
|
|
accounts[0], accounts[1], 1, { from: accounts[1]}));
|
|
});
|
|
|
|
it("should revert, if from address is not the owner of the bird", async () => {
|
|
await testBirdiesInstance.testCreateBird(101, accounts[0]);
|
|
|
|
await truffleAssert.reverts(testBirdiesInstance.safeTransferFrom(
|
|
accounts[2], accounts[1], 1, {from: accounts[0]}));
|
|
});
|
|
|
|
it("should not allow a transfer to the zero address", async () => {
|
|
const zeroAddress = '0x0000000000000000000000000000000000000000';
|
|
await testBirdiesInstance.testCreateBird(101, accounts[0]);
|
|
|
|
await truffleAssert.reverts(testBirdiesInstance.safeTransferFrom(
|
|
accounts[0], zeroAddress, 1));
|
|
});
|
|
|
|
it("should not allow a transfer of a token that doesn't exist", async () => {
|
|
await truffleAssert.reverts(testBirdiesInstance.safeTransferFrom(
|
|
accounts[0], accounts[1], 1));
|
|
});
|
|
|
|
it("should revert, if the receiving contract does not support ERC721", async () => {
|
|
|
|
//this test contract does not support the ERC721 standard
|
|
testMarketInstance = await TestMarket.new(testBirdiesInstance.address);
|
|
|
|
//create one test bird
|
|
await testBirdiesInstance.testCreateBird(101, accounts[0]);
|
|
|
|
//trying to safe transfer that bird to a contract without ERC721 support must fail
|
|
await truffleAssert.reverts(testBirdiesInstance.safeTransferFrom(
|
|
accounts[0], testMarketInstance.address, 1));
|
|
});
|
|
|
|
it("should execute, if the receiving contract supports ERC721", async () => {
|
|
|
|
//create instance of ERC721 compliant test contract
|
|
testErcInstance = await TestErc.new();
|
|
|
|
//create test bird
|
|
await testBirdiesInstance.testCreateBird(101, accounts[0]);
|
|
|
|
//safe transfer to the ERC721 test contract should work
|
|
await truffleAssert.passes(testBirdiesInstance.safeTransferFrom(
|
|
accounts[0], testErcInstance.address, 1));
|
|
});
|
|
});
|
|
|
|
describe("_mixDna()", () =>{
|
|
it("should create a deterministic DNA string", async () => {
|
|
|
|
//the function should create a DNA string that is exactly defined by
|
|
//four random parameters.
|
|
var newDna = await testBirdiesInstance.testMixDna(
|
|
"11223344556677889", "98877665544332211", "100", "0", "0", "63");
|
|
|
|
//using the four parameters the new DNA can be predicted as 63223365546632211
|
|
assert.equal(newDna, "63223365546632211", "DNA string was created incorrectly");
|
|
});
|
|
});
|
|
})
|
|
|
|
contract("MarketPlace", (accounts) => {
|
|
|
|
async function createBirdAndSetApproval(){
|
|
await testBirdiesInstance.testCreateBird(101, accounts[0]);
|
|
var marketAddress = await testMarketInstance.address;
|
|
await testBirdiesInstance.setApprovalForAll(marketAddress, true, { from: accounts[0] });
|
|
}
|
|
|
|
it("should deploy correctly", async () => {
|
|
testBirdiesInstance = await TestBirdies.new("CryptoBird", "CBX");
|
|
|
|
await truffleAssert.passes(Marketcontract.deployed(testBirdiesInstance.address));
|
|
});
|
|
|
|
beforeEach(async () => {
|
|
testBirdiesInstance = await TestBirdies.new("CryptoBird", "CBX");
|
|
testMarketInstance = await TestMarket.new(testBirdiesInstance.address);
|
|
});
|
|
|
|
describe("setContract()", () =>{
|
|
it("should set the Birdcontract by address", async () => {
|
|
await truffleAssert.passes(testMarketInstance.setContract(testBirdiesInstance.address));
|
|
});
|
|
|
|
it("should revert, if not called by owner", async () => {
|
|
await truffleAssert.reverts(testMarketInstance.setContract(
|
|
testBirdiesInstance.address, { from: accounts[1] }));
|
|
});
|
|
});
|
|
|
|
describe("pause()", () =>{
|
|
it("should execute for the contract owner", async () => {
|
|
await truffleAssert.passes(testMarketInstance.pause( { from: accounts[0] }));
|
|
});
|
|
|
|
it("should not execute for other users", async () => {
|
|
await truffleAssert.reverts(testMarketInstance.pause( { from: accounts[1] }));
|
|
});
|
|
|
|
it("should prevent the execution of buyBird()", async () => {
|
|
await createBirdAndSetApproval();
|
|
await testMarketInstance.setOffer(1, 1, { from: accounts[0] });
|
|
|
|
await testMarketInstance.pause( { from: accounts[0] });
|
|
|
|
//it should not be possible to buy this bird after pause() is called
|
|
await truffleAssert.reverts(testMarketInstance.buyBird(1, { from: accounts[1], value: 1 }));
|
|
});
|
|
|
|
it("should prevent the execution of withdrawFunds()", async () => {
|
|
await createBirdAndSetApproval();
|
|
await testMarketInstance.setOffer(1, 1, { from: accounts[0] });
|
|
await testMarketInstance.buyBird(1, { from: accounts[1], value: 1 });
|
|
|
|
await testMarketInstance.pause( { from: accounts[0] });
|
|
|
|
//it should not be possible to withdraw that 1 ETH after pause() is called
|
|
await truffleAssert.reverts(testMarketInstance.withdrawFunds({ from: accounts[0] }));
|
|
});
|
|
|
|
it("should still allow the execution of getAllTokensOnSale()", async () => {
|
|
await createBirdAndSetApproval();
|
|
await testMarketInstance.setOffer(1, 1, { from: accounts[0] });
|
|
await testMarketInstance.pause( { from: accounts[0] });
|
|
await truffleAssert.passes(testMarketInstance.getAllTokensOnSale());
|
|
});
|
|
|
|
it("should still allow the execution of getBalance()", async () => {
|
|
await testMarketInstance.testSetBalance(5);
|
|
await testMarketInstance.pause( { from: accounts[0] });
|
|
await truffleAssert.passes(testMarketInstance.getBalance());
|
|
});
|
|
});
|
|
|
|
describe("resume()", () =>{
|
|
it("should execute for the contract owner", async () => {
|
|
|
|
//first pause the contract through test function
|
|
await testMarketInstance.testSetPause( { from: accounts[0] });
|
|
|
|
//owner should be able to resume
|
|
await truffleAssert.passes(testMarketInstance.resume( { from: accounts[0] }));
|
|
});
|
|
|
|
it("should not execute for other users", async () => {
|
|
|
|
//first pause the contract through test function
|
|
await testMarketInstance.testSetPause( { from: accounts[0] });
|
|
|
|
//another user shouldn't be able to resume contract execution
|
|
await truffleAssert.reverts(testMarketInstance.resume( { from: accounts[1] }));
|
|
});
|
|
|
|
it("should resume the execution of buyBird()", async () => {
|
|
await createBirdAndSetApproval();
|
|
await testMarketInstance.setOffer(1, 1, { from: accounts[0] });
|
|
|
|
// pause the contract through test function
|
|
await testMarketInstance.testSetPause( { from: accounts[0] });
|
|
|
|
//resume execution
|
|
await testMarketInstance.resume( { from: accounts[0] });
|
|
|
|
//buying the bird should work fine and emit the correct event
|
|
var purchase = await testMarketInstance.buyBird(1, { from: accounts[1], value: 1 });
|
|
truffleAssert.eventEmitted(purchase, 'MarketTransaction', (ev) => {
|
|
return ev.TxType == "Bird successfully purchased" && ev.owner == accounts[1] && ev.tokenId == 1;
|
|
}, "Event was NOT emitted with correct parameters");
|
|
|
|
});
|
|
|
|
it("should resume the execution of withdrawFunds()", async () => {
|
|
await createBirdAndSetApproval();
|
|
await testMarketInstance.setOffer(1, 1, { from: accounts[0] });
|
|
|
|
//first pause the contract through test function
|
|
await testMarketInstance.testSetPause( { from: accounts[0] });
|
|
|
|
//it should not be possible to buy the bird at this point
|
|
await truffleAssert.reverts(testMarketInstance.buyBird(1, { from: accounts[1], value: 1 }));
|
|
|
|
//resume execution
|
|
await testMarketInstance.resume( { from: accounts[0] });
|
|
|
|
//purchase of the bird should now execute
|
|
await testMarketInstance.buyBird(1, { from: accounts[1], value: 1 });
|
|
|
|
//seller should be able to withdraw funds
|
|
var fundsReceived = await testMarketInstance.withdrawFunds({ from: accounts[0] });
|
|
truffleAssert.eventEmitted(fundsReceived, 'MonetaryTransaction', (ev) => {
|
|
return ev.message == "Funds successfully received" && ev.recipient == accounts[0] && ev.amount == 1;
|
|
}, "Event was NOT emitted with correct parameters");
|
|
});
|
|
});
|
|
|
|
describe("getOffer()", () =>{
|
|
it("should revert, if there is no active offer", async () => {
|
|
await testBirdiesInstance.testCreateBird(101, accounts[1]);
|
|
|
|
//give market contract operator approval for all birds of accounts[1]
|
|
var marketAddress = await testMarketInstance.address;
|
|
await testBirdiesInstance.setApprovalForAll(marketAddress, true, { from: accounts[1] });
|
|
|
|
//as no offer was set, this assert statement is expected to revert
|
|
await truffleAssert.reverts(testMarketInstance.getOffer(1));
|
|
});
|
|
|
|
it("should return seller, price, index, tokenId, and status of an offer correctly",
|
|
async () => {
|
|
await createBirdAndSetApproval();
|
|
|
|
//set offer of 1 ETH for bird 1
|
|
await testMarketInstance.setOffer(1, 1, { from: accounts[0] });
|
|
var offer = await testMarketInstance.getOffer(1);
|
|
|
|
//check offer parameters
|
|
assert.strictEqual(offer.seller, accounts[0], "Seller is wrong");
|
|
assert.equal(offer.price, 1, "Price is wrong");
|
|
assert.equal(offer.index, 0, "Index is wrong");
|
|
assert.equal(offer.tokenId, 1, "TokenId is wrong");
|
|
assert.strictEqual(offer.active, true, "Offer status is wrong");
|
|
});
|
|
});
|
|
|
|
describe("getAllTokensOnSale()", () =>{
|
|
it("should return an array with the correct length and ids of offers",
|
|
async () => {
|
|
|
|
//create 4 test birds for 3 different owners
|
|
await testBirdiesInstance.testCreateBird(706, accounts[0]); //Bird 1
|
|
await testBirdiesInstance.testCreateBird(707, accounts[0]); //Bird 2
|
|
await testBirdiesInstance.testCreateBird(101, accounts[1]); //Bird 3
|
|
await testBirdiesInstance.testCreateBird(202, accounts[2]); //Bird 4
|
|
var marketAddress = await testMarketInstance.address;
|
|
|
|
//all 3 owners give the market contract operator rights
|
|
await testBirdiesInstance.setApprovalForAll(marketAddress, true, { from: accounts[0] });
|
|
await testBirdiesInstance.setApprovalForAll(marketAddress, true, { from: accounts[1] });
|
|
await testBirdiesInstance.setApprovalForAll(marketAddress, true, { from: accounts[2] });
|
|
|
|
//create an offer for each of the 4 birds
|
|
await testMarketInstance.setOffer(10, 1);//10 ETH for Bird 1
|
|
await testMarketInstance.setOffer(100, 2);//100 ETH for Bird 1
|
|
await testMarketInstance.setOffer(1, 3, { from: accounts[1] });//1 ETH for Bird3
|
|
await testMarketInstance.setOffer(2, 4, { from: accounts[2] });//2 ETH for Bird4
|
|
|
|
//remove offer for Bird 1
|
|
await testMarketInstance.removeOffer(1);
|
|
|
|
//call for the array with the offers
|
|
var arrayOffers = await testMarketInstance.getAllTokensOnSale();
|
|
|
|
//make sure the array contains 3 offers
|
|
assert.equal(arrayOffers.length, 3, "The offer array does NOT have the correct length");
|
|
|
|
//make sure each of the 3 offers is assigned to the correct bird
|
|
//[0] is Bird2; [1] is Bird 3; [2] is Bird4
|
|
assert.equal(arrayOffers[0], 2, "Bird2 offer status is wrong");
|
|
assert.equal(arrayOffers[1], 3, "Bird3 offer status is wrong");
|
|
assert.equal(arrayOffers[2], 4, "Bird4 offer status is wrong");
|
|
});
|
|
});
|
|
|
|
describe("setOffer()", () =>{
|
|
it("should set an offer with a price and tokenId correctly and emit the correct event",
|
|
async () => {
|
|
await createBirdAndSetApproval();
|
|
|
|
//set offer for 1ETH for Bird1
|
|
var offer = await testMarketInstance.setOffer(1, 1, { from: accounts[0] });
|
|
|
|
//check for correct event parameters
|
|
await truffleAssert.eventEmitted(offer, 'MarketTransaction', (ev) => {
|
|
return ev.TxType == "Offer created" && ev.owner == accounts[0] && ev.tokenId == 1;
|
|
}, "Event was NOT emitted with correct parameters");
|
|
|
|
//return offer
|
|
var offer = await testMarketInstance.getOffer(1);
|
|
|
|
//make sure all details of the offer are correct
|
|
assert.strictEqual(offer.seller, accounts[0], "Seller is wrong");
|
|
assert.equal(offer.price, 1, "Price is wrong");
|
|
assert.equal(offer.index, 0, "Index is wrong");
|
|
assert.equal(offer.tokenId, 1, "TokenId is wrong");
|
|
assert.strictEqual(offer.active, true, "Offer status is wrong");
|
|
});
|
|
|
|
it("should only allow the owner to set an offer", async () => {
|
|
await testBirdiesInstance.testCreateBird(101, accounts[0]);
|
|
var marketAddress = await testMarketInstance.address;
|
|
|
|
//give market contract operator approval
|
|
await testBirdiesInstance.setApprovalForAll(marketAddress, true);
|
|
|
|
//accounts[1] should not be able to set an offer
|
|
await truffleAssert.reverts(testMarketInstance.setOffer(1, 1, { from: accounts[1] }));
|
|
});
|
|
|
|
it("should not allow to set a new offer when another already exists", async () => {
|
|
await createBirdAndSetApproval();
|
|
await testMarketInstance.setOffer(1, 1, { from: accounts[0] });
|
|
|
|
//the second attempt to set an offer for Bird 1 should fail
|
|
await truffleAssert.reverts(testMarketInstance.setOffer(5, 1));//5 ETH for Bird1
|
|
});
|
|
|
|
it("should not allow to set an offer, if the Marketcontract is not an approved operator",
|
|
async () => {
|
|
await testBirdiesInstance.testCreateBird(101, accounts[0]);
|
|
var marketAddress = await testMarketInstance.address;
|
|
|
|
//make sure the market contract is NOT an approved operator
|
|
await testBirdiesInstance.setApprovalForAll(marketAddress, false);
|
|
|
|
//setting the offer should now fail
|
|
await truffleAssert.reverts(testMarketInstance.setOffer(5, 1));//5 ETH for Bird1
|
|
});
|
|
|
|
it("should emit a transaction event with correct parameters", async () => {
|
|
await createBirdAndSetApproval();
|
|
|
|
//set offer for 1ETH for Bird1
|
|
var offer = await testMarketInstance.setOffer(1, 1, { from: accounts[0] });
|
|
|
|
//a correctly created event should be emitted
|
|
truffleAssert.eventEmitted(offer, 'MarketTransaction', (ev) => {
|
|
return ev.TxType == "Offer created" && ev.owner == accounts[0] && ev.tokenId == 1;
|
|
}, "Event was NOT emitted with correct parameters");
|
|
});
|
|
});
|
|
|
|
describe("removeOffer()", () =>{
|
|
it("should only allow the owner to remove an offer", async () => {
|
|
await createBirdAndSetApproval();
|
|
|
|
//owner sets offer
|
|
await testMarketInstance.setOffer(1, 1, { from: accounts[0] });
|
|
|
|
//someone else trying to remove the offer should fail
|
|
await truffleAssert.reverts(testMarketInstance.removeOffer(1, { from: accounts[1] }));
|
|
});
|
|
|
|
it("should set status in the offers array to false", async () => {
|
|
await createBirdAndSetApproval();
|
|
|
|
//create an offer of 1ETH for Bird1
|
|
await testMarketInstance.setOffer(1, 1, { from: accounts[0] });
|
|
|
|
//this should set the status within the offers array to false
|
|
await testMarketInstance.removeOffer(1, { from: accounts[0] });
|
|
|
|
//get all 5 parameters from the offers array
|
|
var offer = await testMarketInstance.getOfferFromArray(0);
|
|
|
|
//owner, price, index, and tokenID are still in the array, but status must be false
|
|
assert.strictEqual(offer.seller, accounts[0], "The offer was not removed correctly");
|
|
assert.equal(offer.price, 1, "The offer was not removed correctly");
|
|
assert.equal(offer.index, 0, "The offer was not removed correctly");
|
|
assert.equal(offer.tokenId, 1, "The offer was not removed correctly");
|
|
assert.strictEqual(offer.active, false, "The offer was not removed correctly");
|
|
});
|
|
|
|
it("should delete the entry in the offer mapping", async () => {
|
|
await createBirdAndSetApproval();
|
|
|
|
//create an offer of 1ETH for Bird1
|
|
await testMarketInstance.setOffer(1, 1, { from: accounts[0] });
|
|
|
|
//delete the entry in the mapping
|
|
await testMarketInstance.removeOffer(1, { from: accounts[0] });
|
|
|
|
//trying to get the offer from the mapping
|
|
var offer = await testMarketInstance.getOfferFromMapping(1);
|
|
|
|
//none of the 5 parameters should reflect the original offer
|
|
assert.notStrictEqual(offer.seller, accounts[0], "The offer was not removed correctly");
|
|
assert.notEqual(offer.price, 1, "The offer was not removed correctly");
|
|
assert.equal(offer.index, 0, "The offer was not removed correctly");
|
|
assert.notEqual(offer.tokenId, 1, "The offer was not removed correctly");
|
|
assert.notStrictEqual(offer.active, true, "The offer was not removed correctly");
|
|
});
|
|
|
|
it("should emit a MarketTransaction with correct parameters", async () => {
|
|
await createBirdAndSetApproval();
|
|
|
|
//create an offer of 1ETH for Bird1
|
|
await testMarketInstance.setOffer(1, 1, { from: accounts[0] });
|
|
|
|
//offer removed
|
|
var removal = await testMarketInstance.removeOffer(1, { from: accounts[0] });
|
|
|
|
//check for removal event
|
|
truffleAssert.eventEmitted(removal, 'MarketTransaction', (ev) => {
|
|
return ev.TxType == "Offer removed" && ev.owner == accounts[0] && ev.tokenId == 1;
|
|
}, "Event was NOT emitted with correct parameters");
|
|
});
|
|
});
|
|
|
|
describe("buyBird()", () =>{
|
|
it("should only work, if there is an active offer", async () => {
|
|
await testBirdiesInstance.testCreateBird(101, accounts[1]);
|
|
var marketAddress = await testMarketInstance.address;
|
|
|
|
//after the Bird1 is created, the market contract receives operator rights
|
|
await testBirdiesInstance.setApprovalForAll(marketAddress, true, { from: accounts[1] });
|
|
|
|
//since no offer was created, the purchase of the bird must fail
|
|
await truffleAssert.reverts(testMarketInstance.buyBird(1, { from: accounts[2], value: 1 }));
|
|
});
|
|
|
|
it("should only work, if the value offered is equal to the asking price", async () => {
|
|
await createBirdAndSetApproval();
|
|
|
|
//set offer for 1ETH for Bird1
|
|
await testMarketInstance.setOffer(1, 1, { from: accounts[0] });
|
|
|
|
//Trying to buy the bird for 2ETH must fail
|
|
await truffleAssert.reverts(testMarketInstance.buyBird(1, { from: accounts[1], value: 2 }));
|
|
});
|
|
|
|
it("should transfer ownership correctly", async () => {
|
|
await createBirdAndSetApproval();
|
|
|
|
//set offer for 1ETH for Bird1
|
|
await testMarketInstance.setOffer(1, 1, { from: accounts[0] });
|
|
|
|
//accounts[1] buys Bird1 from accounts[0]
|
|
await testMarketInstance.buyBird(1, { from: accounts[1], value: 1 });
|
|
|
|
//get owner
|
|
var owner = await testBirdiesInstance.ownerOf(1);
|
|
|
|
//make sure the new owner is accounts[1]
|
|
assert.strictEqual(owner, accounts[1], "Ownership was not updated correctly");
|
|
});
|
|
|
|
it("should set the status in the offers array to false", async () => {
|
|
await createBirdAndSetApproval();
|
|
|
|
//set offer for 1ETH for Bird1
|
|
await testMarketInstance.setOffer(1, 1, { from: accounts[0] });
|
|
|
|
//accounts[1] buys Bird1 for 1ETH from accounts[0]
|
|
await testMarketInstance.buyBird(1, { from: accounts[1], value: 1 });
|
|
|
|
//check array for offer parameters
|
|
var offer = await testMarketInstance.getOfferFromArray(0);
|
|
|
|
//make sure seller, price, index, and tokenId are still correct
|
|
//while offer status must now be false
|
|
assert.strictEqual(offer.seller, accounts[0], "The offer was not removed correctly");
|
|
assert.equal(offer.price, 1, "The offer was not removed correctly");
|
|
assert.equal(offer.index, 0, "The offer was not removed correctly");
|
|
assert.equal(offer.tokenId, 1, "The offer was not removed correctly");
|
|
assert.strictEqual(offer.active, false, "The offer was not removed correctly");
|
|
});
|
|
|
|
it("should delete the entry in the offer mapping", async () => {
|
|
await createBirdAndSetApproval();
|
|
|
|
//set offer for 1ETH for Bird1
|
|
await testMarketInstance.setOffer(1, 1, { from: accounts[0] });
|
|
|
|
//accounts[1] buys Bird1 for 1ETH from accounts[0]
|
|
await testMarketInstance.buyBird(1, { from: accounts[1], value: 1 });
|
|
|
|
//return parameters from mapping
|
|
var offer = await testMarketInstance.getOfferFromMapping(1);
|
|
|
|
//all 5 parameters of the mapping are deleted and should not reflect the original offer
|
|
assert.notStrictEqual(offer.seller, accounts[0], "The offer was not removed correctly");
|
|
assert.notStrictEqual(offer.price, 1, "The offer was not removed correctly");
|
|
assert.notStrictEqual(offer.index, 0, "The offer was not removed correctly");
|
|
assert.notStrictEqual(offer.tokenId, 1, "The offer was not removed correctly");
|
|
assert.notStrictEqual(offer.active, true, "The offer was not removed correctly");
|
|
});
|
|
|
|
it("should transfer funds to the _fundsToBeCollected mapping", async () => {
|
|
var buyer = accounts[1];
|
|
await createBirdAndSetApproval();
|
|
|
|
//convert offer of 1ETH to BN
|
|
var price = web3.utils.toBN(1);
|
|
|
|
//convert offer to Wei
|
|
var inWei = web3.utils.toWei(price, "ether");
|
|
|
|
//set offer for 1ETH for Bird1
|
|
await testMarketInstance.setOffer(inWei, 1);
|
|
|
|
//check buyer's ETH balance before the purchase
|
|
var buyerStart = parseInt(await web3.eth.getBalance(buyer));
|
|
|
|
//purchase Bird1 for 1ETH
|
|
await testMarketInstance.buyBird(1, { from: buyer, value: inWei });
|
|
|
|
//check buyer's ETH balance after the purchase
|
|
var buyerEnd = parseInt(await web3.eth.getBalance(buyer));
|
|
|
|
//check the balance in the funds mapping
|
|
var fundsInMapping = parseInt(await testMarketInstance.getBalanceOfMapping(accounts[0]));
|
|
|
|
//convert the purchase price back into integer for comparison reasons
|
|
weiInt = parseInt(inWei);
|
|
|
|
//check that the same amount was added to the funds mapping that the buyer sent
|
|
assert.strictEqual(fundsInMapping, weiInt,
|
|
"Funds were not correctly added to the mapping");
|
|
|
|
//check that the buyer's balance is at most
|
|
//what he had before less the purchase price.
|
|
//it should be a little less, because of gas fees.
|
|
assert.isAtMost(buyerEnd, buyerStart - weiInt,
|
|
"Funds were not correctly subtracted from the buyer account");
|
|
|
|
//check that the buyer's balance is at least
|
|
//what he had before less twice the purchase price.
|
|
//this ensures that buyer wasn't double charged
|
|
assert.isAtLeast(buyerEnd, buyerStart - 2 * weiInt,
|
|
"Funds were not correctly subtracted from the buyer account");
|
|
});
|
|
|
|
it("should emit a MarketTransaction event with correct parameters", async () => {
|
|
await createBirdAndSetApproval();
|
|
|
|
//set offer of 1ETH for Bird1
|
|
await testMarketInstance.setOffer(1, 1, { from: accounts[0] });
|
|
|
|
//purchase Bird1
|
|
var purchase = await testMarketInstance.buyBird(1, { from: accounts[1], value: 1 });
|
|
|
|
//check for all event parameters to be emitted correctly
|
|
truffleAssert.eventEmitted(purchase, 'MarketTransaction', (ev) => {
|
|
return ev.TxType == "Bird successfully purchased" && ev.owner == accounts[1] && ev.tokenId == 1;
|
|
}, "Event was NOT emitted with correct parameters");
|
|
});
|
|
});
|
|
|
|
describe("getBalance()", () =>{
|
|
it("should return the balance of msg.sender", async () => {
|
|
var amountToSet = 5;
|
|
|
|
//a test function was created to set test balances in the funds mapping
|
|
//create a balance of 5ETH for msg.sender
|
|
await testMarketInstance.testSetBalance(amountToSet);
|
|
|
|
//check mapping for balance
|
|
var amountToGet = await testMarketInstance.getBalance();
|
|
|
|
//ensure the mapping contains the same value as was set in the test
|
|
assert.equal(amountToSet, amountToGet,
|
|
"Balance was not returned correctly");
|
|
});
|
|
});
|
|
|
|
describe("withdrawFunds()", () =>{
|
|
it("should revert, if no funds are available to withdraw", async () => {
|
|
await truffleAssert.reverts(testMarketInstance.withdrawFunds({ from: accounts[0] }));
|
|
});
|
|
|
|
it("should revert, if the contract owner tries to withdraw user funds", async () => {
|
|
await testMarketInstance.testSetBalance(5, { from: accounts[2] });
|
|
await truffleAssert.reverts(testMarketInstance.withdrawFunds({ from: accounts[0] }));
|
|
});
|
|
|
|
it("should withdraw funds correctly", async () => {
|
|
var seller = accounts[1];
|
|
var buyer = accounts[2];
|
|
|
|
//create test bird for seller
|
|
await testBirdiesInstance.testCreateBird(101, seller);
|
|
var marketAddress = await testMarketInstance.address;
|
|
await testBirdiesInstance.setApprovalForAll(marketAddress, true, { from: seller });
|
|
|
|
//conversions of offer of 1ETH
|
|
var price = web3.utils.toBN(1);
|
|
var inWei = web3.utils.toWei(price, "ether");
|
|
|
|
//set offer for 1ETH for Bird1
|
|
await testMarketInstance.setOffer(inWei, 1, { from: seller });
|
|
|
|
//check buyer's ETH balance before purchase
|
|
var buyerStart = parseInt(await web3.eth.getBalance(buyer));
|
|
|
|
//correct purchase of Bird1
|
|
await testMarketInstance.buyBird(1, { from: buyer, value: inWei });
|
|
|
|
//check buyer's ETH balance after purchase
|
|
var buyerEnd = parseInt(await web3.eth.getBalance(buyer));
|
|
|
|
//check seller's ETH balance before withdrawal
|
|
var sellerStart = parseInt(await web3.eth.getBalance(seller));
|
|
|
|
//check funds in mapping
|
|
var fundsInMapping = await testMarketInstance.getBalanceOfMapping(seller);
|
|
assert.equal(fundsInMapping, parseInt(inWei),
|
|
"Funds were not correctly added to the mapping");
|
|
|
|
//seller should be able to withdraw 1ETH
|
|
await testMarketInstance.withdrawFunds({ from: seller });
|
|
|
|
//check seller's ETH balance after withdrawal
|
|
var sellerEnd = parseInt(await web3.eth.getBalance(seller));
|
|
|
|
//check mapping again
|
|
fundsInMapping = await testMarketInstance.getBalanceOfMapping(seller);
|
|
|
|
//convert back to integer
|
|
var weiInt = parseInt(inWei);
|
|
|
|
//make sure funds were removed from mapping
|
|
assert.equal(fundsInMapping, 0,
|
|
"Funds were not correctly removed from the mapping");
|
|
|
|
//make sure seller didn't receive any more funds than the proceedings from the purchase
|
|
assert.isAtMost(sellerEnd - sellerStart, weiInt,
|
|
"Funds were not correctly added to the seller account");
|
|
|
|
//check that the amount was correctly subtracted from buyer
|
|
//considering gas, at least purchase price and gas should have been removed
|
|
assert.isAtLeast(buyerStart - buyerEnd, weiInt,
|
|
"Funds were not correctly subtracted from the buyer account");
|
|
|
|
//check that the amount was correctly subtracted from buyer
|
|
//considering gas, at most double the purchase price should have been removed
|
|
//this ensures that there is no double spending
|
|
assert.isAtMost(buyerStart - buyerEnd, 2 * weiInt,
|
|
"Funds were not correctly subtracted from the buyer account");
|
|
});
|
|
|
|
it("should emit a MonetaryTransaction event with correct parameters", async () => {
|
|
await createBirdAndSetApproval();
|
|
|
|
//set offer for 1ETH for Bird1
|
|
await testMarketInstance.setOffer(1, 1, { from: accounts[0] });
|
|
|
|
//purchase of Bird1
|
|
await testMarketInstance.buyBird(1, { from: accounts[1], value: 1 });
|
|
|
|
//seller withdraws funds
|
|
var fundsReceived = await testMarketInstance.withdrawFunds({ from: accounts[0] });
|
|
|
|
//ensure correct event for withdrawal is emitted
|
|
truffleAssert.eventEmitted(fundsReceived, 'MonetaryTransaction', (ev) => {
|
|
return ev.message == "Funds successfully received" && ev.recipient == accounts[0] && ev.amount == 1;
|
|
}, "Event was NOT emitted with correct parameters");
|
|
});
|
|
|
|
it("should allow seller to access correct funds, if birds were sold to different buyers",
|
|
async () => {
|
|
var seller = accounts[1];
|
|
var buyer1 = accounts[2];
|
|
var buyer2 = accounts[3];
|
|
|
|
//create 2 test birds and give market contract approval as operator
|
|
await testBirdiesInstance.testCreateBird(101, seller);
|
|
await testBirdiesInstance.testCreateBird(202, seller);
|
|
var marketAddress = await testMarketInstance.address;
|
|
await testBirdiesInstance.setApprovalForAll(marketAddress, true, { from: seller });
|
|
|
|
//conversions
|
|
var price1 = web3.utils.toBN(5);
|
|
var inWei1 = web3.utils.toWei(price1, "ether");
|
|
var price2 = web3.utils.toBN(3);
|
|
var inWei2 = web3.utils.toWei(price2, "ether");
|
|
|
|
//create 2 offers
|
|
await testMarketInstance.setOffer(inWei1, 1, { from: seller }); //5 ETH for Bird1
|
|
await testMarketInstance.setOffer(inWei2, 2, { from: seller }); //3 ETH for Bird2
|
|
|
|
//purchase of the birds by two different buyers
|
|
await testMarketInstance.buyBird(1, { from: buyer1, value: inWei1 });
|
|
await testMarketInstance.buyBird(2, { from: buyer2, value: inWei2 });
|
|
|
|
//check seller's ETH balance before withdrawal
|
|
var sellerStart = parseInt(await web3.eth.getBalance(seller));
|
|
|
|
await testMarketInstance.withdrawFunds({ from: seller });
|
|
|
|
//check seller's ETH balance after withdrawal
|
|
var sellerEnd = parseInt(await web3.eth.getBalance(seller));
|
|
var weiInt = parseInt(inWei1 + inWei2);
|
|
|
|
//make sure seller didn't receive any more funds than the proceedings from the purchase
|
|
assert.isAtMost(sellerEnd - sellerStart, weiInt,
|
|
"Funds were not correctly added to the seller account");
|
|
});
|
|
});
|
|
}) |