diff --git a/contracts/exchange/Exchange.sol b/contracts/exchange/Exchange.sol index 353f904..82ee07a 100644 --- a/contracts/exchange/Exchange.sol +++ b/contracts/exchange/Exchange.sol @@ -27,9 +27,9 @@ contract Exchange { /* * @dev contract addresses */ - address public XCT_TOKEN_CONTRACT; - address public TOKEN_TRANSFER_PROXY_CONTRACT; - address public NFTOKEN_TRANSFER_PROXY_CONTRACT; + address XCT_TOKEN_CONTRACT; + address TOKEN_TRANSFER_PROXY_CONTRACT; + address NFTOKEN_TRANSFER_PROXY_CONTRACT; /* * @dev Changes to state require at least 5000 gas. @@ -94,21 +94,37 @@ contract Exchange { } /* - * @dev Get addresses to all associated contracts (token, tokenTransferProxy, xcertProxy) . - * @return Array of addresses (token, tokenTransferProxy, nfTokenTransferProxy) + * @dev Get address of token used in exchange. */ - function getAddresses() + function getTokenAddress() external view - returns (address[]) + returns (address) { - address[] memory addresses; - addresses[0] = XCT_TOKEN_CONTRACT; - addresses[1] = TOKEN_TRANSFER_PROXY_CONTRACT; - addresses[2] = NFTOKEN_TRANSFER_PROXY_CONTRACT; - return addresses; + return XCT_TOKEN_CONTRACT; } + /* + * @dev Get address of token transfer proxy used in exchange. + */ + function getTokenTransferProxyAddress() + external + view + returns (address) + { + return TOKEN_TRANSFER_PROXY_CONTRACT; + } + + /* + * @dev Get address of none-fundgible token transfer proxy used in exchange. + */ + function getNFTokenTransferProxyAddress() + external + view + returns (address) + { + return NFTOKEN_TRANSFER_PROXY_CONTRACT; + } /* * @dev Performs the Xcert transfer. diff --git a/contracts/exchange/MintableExchange.sol b/contracts/exchange/MintableExchange.sol index 96b7cd3..fe78ca1 100644 --- a/contracts/exchange/MintableExchange.sol +++ b/contracts/exchange/MintableExchange.sol @@ -24,7 +24,7 @@ contract MintableExchange is Exchange{ /* * @dev contract addresses */ - address public XCERT_MINT_PROXY_CONTRACT; + address XCERT_MINT_PROXY_CONTRACT; /* * @dev Mapping of all canceled mints. @@ -98,17 +98,12 @@ contract MintableExchange is Exchange{ * NFtokenTransferProxy, xcertMintProxy) . * @return Array of addresses (token, tokenTransferProxy, nfTokenTransferProxy, xcertMintProxy) */ - function getAddresses() + function getXcertMintProxyAddress() external view - returns (address[]) + returns (address) { - address[] memory addresses; - addresses[0] = XCT_TOKEN_CONTRACT; - addresses[1] = TOKEN_TRANSFER_PROXY_CONTRACT; - addresses[2] = NFTOKEN_TRANSFER_PROXY_CONTRACT; - addresses[3] = XCERT_MINT_PROXY_CONTRACT; - return addresses; + return XCERT_MINT_PROXY_CONTRACT; } diff --git a/contracts/mocks/ERC721TokenReceiverMock.sol b/contracts/mocks/ERC721TokenReceiverMock.sol new file mode 100644 index 0000000..f90001f --- /dev/null +++ b/contracts/mocks/ERC721TokenReceiverMock.sol @@ -0,0 +1,35 @@ +pragma solidity ^0.4.19; + +import "../tokens/ERC721TokenReceiver.sol"; + +contract ERC721TokenReceiverMock is ERC721TokenReceiver { + + /* + * @dev Magic value of a smart contract that can recieve NFToken. + */ + bytes4 private constant MAGIC_ONERC721RECEIVED = bytes4( + keccak256("onERC721Received(address,uint256,bytes)") + ); + + /* + * @notice Handle the receipt of an NFT + * @dev The ERC721 smart contract calls this function on the recipient + * after a `transfer`. This function MAY throw to revert and reject the + * transfer. This function MUST use 50,000 gas or less. Return of other + * than the magic value MUST result in the transaction being reverted. + * Note: the contract address is always the message sender. + * @param _from The sending address + * @param _tokenId The NFT identifier which is being transfered + * @param data Additional data with no specified format + * @return `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))` + * unless throwing + */ + function onERC721Received(address _from, + uint256 _tokenId, + bytes data) + external + returns(bytes4) + { + return MAGIC_ONERC721RECEIVED; + } +} \ No newline at end of file diff --git a/contracts/tokens/Xcert.sol b/contracts/tokens/Xcert.sol index 9da2847..aae9765 100644 --- a/contracts/tokens/Xcert.sol +++ b/contracts/tokens/Xcert.sol @@ -62,7 +62,7 @@ contract Xcert is Ownable, ERC721, ERC721Metadata, ERC165 { mapping (address => bool) private addressToMintAuthorized; /* - * @dev Check for recieved transfer to a smart contract. + * @dev Magic value of a smart contract that can recieve NFToken. */ bytes4 private constant MAGIC_ONERC721RECEIVED = bytes4( keccak256("onERC721Received(address,uint256,bytes)") diff --git a/test/exchange/Exchange.test.js b/test/exchange/Exchange.test.js index ae1c3db..4c1161d 100644 --- a/test/exchange/Exchange.test.js +++ b/test/exchange/Exchange.test.js @@ -37,6 +37,23 @@ contract('Exchange', (accounts) => { tokenProxy.addAuthorizedAddress(exchange.address); }); + describe('contract addresses', function () { + it('check if token address is correct', async () => { + var address = await exchange.getTokenAddress(); + assert.equal(address, token.address); + }); + + it('check if token transfer proxy address is correct', async () => { + var address = await exchange.getTokenTransferProxyAddress(); + assert.equal(address, tokenProxy.address); + }); + + it('check if none-fundgible token transfer proxy address is correct', async () => { + var address = await exchange.getNFTokenTransferProxyAddress(); + assert.equal(address, nfTokenProxy.address); + }); + }); + describe('hashing', function () { var testArrayAccount = [accounts[3], accounts[5]]; var testArrayAmount = [1, 10]; diff --git a/test/exchange/MintableExchange.test.js b/test/exchange/MintableExchange.test.js index 3047f71..dcd6902 100644 --- a/test/exchange/MintableExchange.test.js +++ b/test/exchange/MintableExchange.test.js @@ -38,6 +38,13 @@ contract('MintableExchange', (accounts) => { mintProxy.addAuthorizedAddress(exchange.address); }); + describe('contract addresses', function () { + it('check if xcert mint proxy address is correct', async () => { + var address = await exchange.getXcertMintProxyAddress(); + assert.equal(address, mintProxy.address); + }); + }); + describe('hashing', function () { var testArrayAccount = [accounts[3], accounts[5]]; var testArrayAmount = [1, 10]; @@ -54,7 +61,6 @@ contract('MintableExchange', (accounts) => { }); }); - describe('mint', function () { describe('valid signature', function () { @@ -148,6 +154,18 @@ contract('MintableExchange', (accounts) => { assert.notEqual(event, undefined); }); + it('throws when fee amount array is no the same length then feeRecipient', async () => { + await token.approve(tokenProxy.address, 20, {from: to}); + await xcert.setMintAuthorizedAddress(mintProxy.address, true, {from: owner}); + await assertRevert(exchange.performMint(to, xcert.address, id1, uri, addressArray, [20,10], timestamp, v, r, s, true, {from: to})); + }); + + it('throws when _from is the owner addresses are the same', async () => { + await token.approve(tokenProxy.address, 20, {from: to}); + await xcert.setMintAuthorizedAddress(mintProxy.address, true, {from: owner}); + await assertRevert(exchange.performMint(owner, xcert.address, id1, uri, addressArray, amountArray, timestamp, v, r, s, true, {from: to})); + }); + it('fails when trying to perform already performed mint', async () => { await token.approve(tokenProxy.address, 20, {from: to}); await xcert.setMintAuthorizedAddress(mintProxy.address, true, {from: owner}); @@ -189,6 +207,7 @@ contract('MintableExchange', (accounts) => { await token.approve(tokenProxy.address, 20, {from: to}); await assertRevert(exchange.performMint(to, xcert.address, id1, uri, addressArray, amountArray, timestamp, v, r, s, false, {from: to})); }); + }); }); diff --git a/test/tokens/Xcert.test.js b/test/tokens/Xcert.test.js index 3d9f5cf..743a3ac 100644 --- a/test/tokens/Xcert.test.js +++ b/test/tokens/Xcert.test.js @@ -1,6 +1,7 @@ const Xcert = artifacts.require('Xcert'); const util = require('ethjs-util'); const assertRevert = require('../helpers/assertRevert'); +const TokenReceiverMock = artifacts.require('ERC721TokenReceiverMock'); contract('Xcert', (accounts) => { let xcert; @@ -223,13 +224,12 @@ contract('Xcert', (accounts) => { await assertRevert(xcert.transferFrom(owner, 0, id3, {from: owner})); }); - // tests skipped because of trufflesuite/truffle#737 - /*it('corectly safe transfers NFToken from owner', async () => { + it('corectly safe transfers NFToken from owner', async () => { var sender = accounts[1]; var recipient = accounts[2]; await xcert.mint(sender, id2, 'url2'); - var { logs } = await xcert.safeTransferFrom(sender, recipient, id2, {from: sender}); + var { logs } = await xcert.safeTransferFrom(sender, recipient, id2, "data", {from: sender}); let transferEvent = logs.find(e => e.event === 'Transfer'); assert.notEqual(transferEvent, undefined); @@ -247,8 +247,27 @@ contract('Xcert', (accounts) => { var recipient = xcert.address; await xcert.mint(sender, id2, 'url2'); - await assertRevert(xcert.safeTransferFrom(sender, recipient, id2, {from: sender})); - });*/ + await assertRevert(xcert.safeTransferFrom(sender, recipient, id2, "data", {from: sender})); + }); + + it('corectly safe transfers NFToken from owner to smart contract that can recieve NFTokens', async () => { + var sender = accounts[1]; + var tokenReceiverMock = await TokenReceiverMock.new(); + var recipient = tokenReceiverMock.address; + + await xcert.mint(sender, id2, 'url2'); + var { logs } = await xcert.safeTransferFrom(sender, recipient, id2, "data", {from: sender}); + let transferEvent = logs.find(e => e.event === 'Transfer'); + assert.notEqual(transferEvent, undefined); + + var senderBalance = await xcert.balanceOf(sender); + var recipientBalance = await xcert.balanceOf(recipient); + var ownerOfId2 = await xcert.ownerOf(id2); + + assert.equal(senderBalance, 0); + assert.equal(recipientBalance, 1); + assert.equal(ownerOfId2, recipient); + }); it('returns the correct issuer name', async () => { const name = await xcert.name();