--- a/tests/src/eth/marketplace-v2/Market.sol +++ b/tests/src/eth/marketplace-v2/Market.sol @@ -4,6 +4,7 @@ import "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol"; import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import { UniqueNFT, CrossAddress } from "@unique-nft/solidity-interfaces/contracts/UniqueNFT.sol"; +import { UniqueFungible, CrossAddress as CrossAddressF } from "@unique-nft/solidity-interfaces/contracts/UniqueFungible.sol"; import "@unique-nft/solidity-interfaces/contracts/CollectionHelpers.sol"; import "./royalty/UniqueRoyaltyHelper.sol"; @@ -20,6 +21,7 @@ } uint32 public constant version = 0; + uint32 public constant buildVersion = 1; bytes4 private constant InterfaceId_ERC721 = 0x80ac58cd; bytes4 private constant InterfaceId_ERC165 = 0x5755c3f2; CollectionHelpers private constant collectionHelpers = @@ -251,7 +253,7 @@ IERC721 erc721 = getErc721(collectionId); - if (erc721.getApproved(tokenId) != selfAddress) { + if (erc721.getApproved(tokenId) != selfAddress || erc721.ownerOf(tokenId) != getAddressFromCrossAccount(order.seller)) { uint32 amount = order.amount; order.amount = 0; emit TokenRevoke(version, order, amount); @@ -262,6 +264,27 @@ } } + function getAddressFromCrossAccount(CrossAddress memory account) private pure returns (address) { + if (account.eth != address(0)) { + return account.eth; + } else { + return address(uint160(account.sub >> 96)); + } + } + + function revokeAdmin(uint32 collectionId, uint32 tokenId) public onlyAdmin { + Order memory order = orders[collectionId][tokenId]; + if (order.price == 0) { + revert OrderNotFound(); + } + + uint32 amount = order.amount; + order.amount = 0; + emit TokenRevoke(version, order, amount); + + delete orders[collectionId][tokenId]; + } + // ################################################################ // Buy a token # // ################################################################ @@ -329,13 +352,14 @@ } function sendMoney(CrossAddress memory to, uint256 money) private { - address payable eth; - if (to.eth != address(0)) { - eth = payable(to.eth); - } else { - eth = payable(address(uint160(to.sub >> 96))); - } - eth.transfer(money); + address collectionAddress = collectionHelpers.collectionAddress(0); + + UniqueFungible fungible = UniqueFungible(collectionAddress); + + CrossAddressF memory fromF = CrossAddressF(selfAddress, 0); + CrossAddressF memory toF = CrossAddressF(to.eth, to.sub); + + fungible.transferFromCross(fromF, toF, money); } function sendRoyalties(address collection, uint tokenId, uint sellPrice) private returns (uint256, RoyaltyAmount[] memory) { --- a/tests/src/eth/marketplace-v2/marketplace.test.ts +++ b/tests/src/eth/marketplace-v2/marketplace.test.ts @@ -43,6 +43,10 @@ fsPath: `${dirname}/../api/UniqueNFT.sol`, }, { + solPath: '@unique-nft/solidity-interfaces/contracts/UniqueFungible.sol', + fsPath: `${dirname}/../api/UniqueFungible.sol`, + }, + { solPath: '@openzeppelin/contracts/utils/introspection/IERC165.sol', fsPath: `${dirname}/../../../node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol`, }, @@ -125,7 +129,6 @@ const collection = await helper.ethNativeContract.collection(collectionAddress, 'nft', marketOwner); const [seller] = await helper.arrange.createAccounts([600n], donor); - const sellerMirror = helper.address.substrateToEth(seller.address); const sellerCross = helper.ethCrossAccount.fromKeyringPair(seller); const result = await collection.methods.mintCross(sellerCross, []).send(); const tokenId = result.events.Transfer.returnValues.tokenId; @@ -140,10 +143,9 @@ const buyerMirror = helper.address.substrateToEth(buyer.address); const buyerCross = helper.ethCrossAccount.fromKeyringPair(buyer); await helper.eth.transferBalanceFromSubstrate(donor, buyerMirror, 1n); - //TODO: change balance check to helper.balance.getSubstrate when implementation of sendMoney will be fixed in contract - const sellerBalance = BigInt(await web3.eth.getBalance(sellerMirror)); + const sellerBalance = BigInt(await helper.balance.getSubstrate(seller.address)); await helper.eth.sendEVM(buyer, market.options.address, market.methods.buy(collectionId, tokenId, 1, buyerCross).encodeABI(), PRICE.toString()); - const sellerBalanceAfterBuy = BigInt(await web3.eth.getBalance(sellerMirror)); + const sellerBalanceAfterBuy = BigInt(await helper.balance.getSubstrate(seller.address)); ownerCross = await collection.methods.ownerOfCross(tokenId).call(); expect(ownerCross.eth).to.be.eq(buyerCross.eth); expect(substrateAddressToHex(ownerCross.sub, web3)).to.be.eq(substrateAddressToHex(buyerCross.sub, web3)); --- a/tests/src/eth/tokenProperties.test.ts +++ b/tests/src/eth/tokenProperties.test.ts @@ -561,10 +561,10 @@ itEth.ifWithPallets(`[${testCase.mode}] Can't be multiple set/read for non-existent token`, testCase.requiredPallets, async({helper}) => { const caller = await helper.eth.createAccountWithBalance(donor); - const properties = Array(5).fill(0).map((_, i) => { return {key: `key_${i}`, value: Buffer.from(`value_${i}`)}; }); - const permissions: ITokenPropertyPermission[] = properties.map(p => { return {key: p.key, permission: {tokenOwner: true, + const properties = Array(5).fill(0).map((_, i) => ({key: `key_${i}`, value: Buffer.from(`value_${i}`)})); + const permissions: ITokenPropertyPermission[] = properties.map(p => ({key: p.key, permission: {tokenOwner: true, collectionAdmin: true, - mutable: true}}; }); + mutable: true}})); const collection = await helper[testCase.mode].mintCollection(alice, { tokenPrefix: 'ethp',