diff --git a/packages/marketplace/contracts/ExchangeCore.sol b/packages/marketplace/contracts/ExchangeCore.sol index fafd68d697..84e62a4751 100644 --- a/packages/marketplace/contracts/ExchangeCore.sol +++ b/packages/marketplace/contracts/ExchangeCore.sol @@ -170,16 +170,8 @@ abstract contract ExchangeCore is Initializable, ITransferManager { LibOrder.FillResult memory newFill = _parseOrdersSetFillEmitMatch(sender, orderLeft, orderRight); doTransfers( - ITransferManager.DealSide( - LibAsset.Asset(makeMatch, newFill.leftValue), - orderLeft.maker, - orderLeft.makeRecipient - ), - ITransferManager.DealSide( - LibAsset.Asset(takeMatch, newFill.rightValue), - orderRight.maker, - orderRight.makeRecipient - ), + ITransferManager.DealSide(LibAsset.Asset(makeMatch, newFill.leftValue), orderLeft.maker), + ITransferManager.DealSide(LibAsset.Asset(takeMatch, newFill.rightValue), orderRight.maker), LibAsset.getFeeSide(makeMatch.assetClass, takeMatch.assetClass) ); } diff --git a/packages/marketplace/contracts/OrderValidator.sol b/packages/marketplace/contracts/OrderValidator.sol index eb0dbf43e3..3b9431f194 100644 --- a/packages/marketplace/contracts/OrderValidator.sol +++ b/packages/marketplace/contracts/OrderValidator.sol @@ -42,7 +42,6 @@ contract OrderValidator is IOrderValidator, Initializable, EIP712Upgradeable, Wh /// @param sender Address of the order sender. function validate(LibOrder.Order calldata order, bytes memory signature, address sender) external view { require(order.maker != address(0), "no maker"); - require(order.makeRecipient != address(0), "no recipient"); LibOrder.validateOrderTime(order); _verifyWhitelists(order.makeAsset); diff --git a/packages/marketplace/contracts/TransferManager.sol b/packages/marketplace/contracts/TransferManager.sol index 0c272f005d..81bd4d54de 100644 --- a/packages/marketplace/contracts/TransferManager.sol +++ b/packages/marketplace/contracts/TransferManager.sol @@ -98,11 +98,14 @@ abstract contract TransferManager is Initializable, ITransferManager { paymentSide = right; nftSide = left; } + + (address paymentSideRecipient, address nftSideRecipient) = _getRecipients(paymentSide, nftSide); + // Transfer NFT or left side if FeeSide.NONE - _transfer(nftSide.asset, nftSide.account, paymentSide.recipient); + _transfer(nftSide.asset, nftSide.account, paymentSideRecipient); // Transfer ERC20 or right side if FeeSide.NONE if (feeSide == LibAsset.FeeSide.NONE || _mustSkipFees(paymentSide.account)) { - _transfer(paymentSide.asset, paymentSide.account, nftSide.recipient); + _transfer(paymentSide.asset, paymentSide.account, nftSideRecipient); } else { _doTransfersWithFeesAndRoyalties(paymentSide, nftSide); } @@ -138,6 +141,26 @@ abstract contract TransferManager is Initializable, ITransferManager { emit DefaultFeeReceiverSet(newDefaultFeeReceiver); } + function _getRecipients( + DealSide memory paymentSide, + DealSide memory nftSide + ) internal pure returns (address paymentSideRecipient, address nftSideRecipient) { + address decodedPaymentSideRecipient = LibAsset.decodeRecipient(paymentSide.asset.assetType); + address decodedNftSideRecipient = LibAsset.decodeRecipient(nftSide.asset.assetType); + + if (decodedPaymentSideRecipient != address(0)) { + paymentSideRecipient = decodedPaymentSideRecipient; + } else { + paymentSideRecipient = paymentSide.account; + } + + if (decodedNftSideRecipient != address(0)) { + nftSideRecipient = decodedNftSideRecipient; + } else { + nftSideRecipient = nftSide.account; + } + } + /// @notice Transfer protocol fees and royalties. /// @param paymentSide DealSide of the fee-side order /// @param nftSide DealSide of the nft-side order @@ -155,7 +178,8 @@ abstract contract TransferManager is Initializable, ITransferManager { remainder = _transferPercentage(remainder, paymentSide, defaultFeeReceiver, fees, PROTOCOL_FEE_MULTIPLIER); } if (remainder > 0) { - _transfer(LibAsset.Asset(paymentSide.asset.assetType, remainder), paymentSide.account, nftSide.recipient); + (, address nftSideRecipient) = _getRecipients(paymentSide, nftSide); + _transfer(LibAsset.Asset(paymentSide.asset.assetType, remainder), paymentSide.account, nftSideRecipient); } } @@ -178,13 +202,14 @@ abstract contract TransferManager is Initializable, ITransferManager { DealSide memory nftSide ) internal returns (uint256) { (address token, uint256 tokenId) = LibAsset.decodeToken(nftSide.asset.assetType); + (, address nftSideRecipient) = _getRecipients(paymentSide, nftSide); IRoyaltiesProvider.Part[] memory royalties = royaltiesRegistry.getRoyalties(token, tokenId); uint256 totalRoyalties; uint256 len = royalties.length; for (uint256 i; i < len; i++) { IRoyaltiesProvider.Part memory r = royalties[i]; totalRoyalties = totalRoyalties + r.basisPoints; - if (r.account == nftSide.recipient) { + if (r.account == nftSideRecipient) { // We just skip the transfer because the nftSide will get the full payment anyway. continue; } diff --git a/packages/marketplace/contracts/interfaces/ITransferManager.sol b/packages/marketplace/contracts/interfaces/ITransferManager.sol index 267ded02ae..19105065ef 100644 --- a/packages/marketplace/contracts/interfaces/ITransferManager.sol +++ b/packages/marketplace/contracts/interfaces/ITransferManager.sol @@ -13,7 +13,6 @@ abstract contract ITransferManager { struct DealSide { LibAsset.Asset asset; // The asset associated with this side of the deal. address account; // The account address associated with this side of the deal. - address recipient; // The account address receiving the tokens } /// @notice Executes the asset transfers associated with two matched orders. diff --git a/packages/marketplace/contracts/libraries/LibAsset.sol b/packages/marketplace/contracts/libraries/LibAsset.sol index 547ab5c5d7..2662d6d923 100644 --- a/packages/marketplace/contracts/libraries/LibAsset.sol +++ b/packages/marketplace/contracts/libraries/LibAsset.sol @@ -104,4 +104,18 @@ library LibAsset { function decodeAddress(AssetType memory assetType) internal pure returns (address) { return abi.decode(assetType.data, (address)); } + + /// @notice Decode the recipient address from an AssetType. + /// @param assetType The asset type to decode. + /// @return The address of the recipient, or zero address if not present. + function decodeRecipient(AssetType memory assetType) internal pure returns (address) { + bytes memory data = assetType.data; + if (data.length == 96) { + // 3 * 32 bytes (address, uint256, address) + (, , address recipient) = abi.decode(data, (address, uint256, address)); + return recipient; + } else { + return address(0); + } + } } diff --git a/packages/marketplace/contracts/libraries/LibOrder.sol b/packages/marketplace/contracts/libraries/LibOrder.sol index aa32014268..17c33a0290 100644 --- a/packages/marketplace/contracts/libraries/LibOrder.sol +++ b/packages/marketplace/contracts/libraries/LibOrder.sol @@ -11,7 +11,7 @@ import {LibMath} from "./LibMath.sol"; library LibOrder { bytes32 internal constant ORDER_TYPEHASH = keccak256( - "Order(address maker,Asset makeAsset,address taker,Asset takeAsset,address makeRecipient,uint256 salt,uint256 start,uint256 end)Asset(AssetType assetType,uint256 value)AssetType(uint256 assetClass,bytes data)" + "Order(address maker,Asset makeAsset,address taker,Asset takeAsset,uint256 salt,uint256 start,uint256 end)Asset(AssetType assetType,uint256 value)AssetType(uint256 assetClass,bytes data)" ); /// @dev Represents the structure of an order. @@ -20,7 +20,6 @@ library LibOrder { LibAsset.Asset makeAsset; // Asset the maker is providing. address taker; // Address of the taker. LibAsset.Asset takeAsset; // Asset the taker is providing. - address makeRecipient; // recipient address for maker. uint256 salt; // Random number to ensure unique order hash. uint256 start; // Timestamp when the order becomes valid. uint256 end; // Timestamp when the order expires. @@ -40,7 +39,6 @@ library LibOrder { keccak256( abi.encode( order.maker, - order.makeRecipient, LibAsset.hash(order.makeAsset.assetType), LibAsset.hash(order.takeAsset.assetType), order.salt @@ -61,7 +59,6 @@ library LibOrder { LibAsset.hash(order.makeAsset), order.taker, LibAsset.hash(order.takeAsset), - order.makeRecipient, order.salt, order.start, order.end diff --git a/packages/marketplace/docs/Exchange.md b/packages/marketplace/docs/Exchange.md index ef945093ab..5190ef26d1 100644 --- a/packages/marketplace/docs/Exchange.md +++ b/packages/marketplace/docs/Exchange.md @@ -181,6 +181,22 @@ In the extreme cases: gets the benefit because she sells at 2000 MATIC each ASSET. Alice gets more MATIC than expected. +### Custom recipients + +The protocol allows both buyer and seller to set custom recipients for the +exchange. + +Inside the `LibAsset` library, the `Asset` struct contains a `data` field which +is a `bytes` type. We encode the recipient address into that field. + +Look up `decodeRecipient` function in `LibAsset` to see how to decode the +recipient address. Assets like ERC20 only have the token address in the data so +we need to add a uint256 and a recipient address to make it 96 bytes. + +When transfers are happening, the recipient is decoded from the `Asset` struct, +and if it's not the zero address, then the transfer will be done to the decoded +recipient address otherwise it will be sent to the original deal side address. + ### Order salt Orders contain a salt value that ensure each order is unique, even for the same diff --git a/packages/marketplace/test/OrderValidator.test.ts b/packages/marketplace/test/OrderValidator.test.ts index 48dfd34d78..adc08ac0ef 100644 --- a/packages/marketplace/test/OrderValidator.test.ts +++ b/packages/marketplace/test/OrderValidator.test.ts @@ -325,58 +325,6 @@ describe('OrderValidator.sol', function () { ).to.not.be.reverted; }); - it('should not validate if recipient is zero', async function () { - const makerAsset = await AssetERC721(ERC721Contract, 100); - const takerAsset = await AssetERC20(ERC20Contract, 100); - const order = await OrderDefault( - user1, - makerAsset, - ZeroAddress, - takerAsset, - 1, - 0, - 0, - ZeroAddress - ); - - const signature = await signOrder(order, user1, OrderValidatorAsUser); - - await expect( - OrderValidatorAsUser.validate(order, signature, user2.getAddress()) - ).to.be.revertedWith('no recipient'); - }); - - it('should not validate if recipient is changed after signature', async function () { - const makerAsset = await AssetERC721(ERC721Contract, 100); - const takerAsset = await AssetERC20(ERC20Contract, 100); - const order = await OrderDefault( - user1, - makerAsset, - ZeroAddress, - takerAsset, - 1, - 0, - 0 - ); - - const signature = await signOrder(order, user1, OrderValidatorAsUser); - - const newOrder = await OrderDefault( - user1, - makerAsset, - ZeroAddress, - takerAsset, - 1, - 0, - 0, - await user2.getAddress() - ); - - await expect( - OrderValidatorAsUser.validate(newOrder, signature, user2.getAddress()) - ).to.be.revertedWith('signature verification error'); - }); - it('should not set permission for token if caller is not owner', async function () { await expect(OrderValidatorAsUser.enableRole(TSBRole)).to.revertedWith( `AccessControl: account ${( diff --git a/packages/marketplace/test/exchange/MatchOrders.behavior.ts b/packages/marketplace/test/exchange/MatchOrders.behavior.ts index 8af023a857..66cde8e0e2 100644 --- a/packages/marketplace/test/exchange/MatchOrders.behavior.ts +++ b/packages/marketplace/test/exchange/MatchOrders.behavior.ts @@ -1,16 +1,16 @@ +import {loadFixture} from '@nomicfoundation/hardhat-network-helpers'; import {expect} from 'chai'; import {deployFixtures} from '../fixtures/index.ts'; -import {loadFixture} from '@nomicfoundation/hardhat-network-helpers'; -import {AssetERC20, AssetERC721, AssetERC1155, Asset} from '../utils/assets.ts'; +import {Asset, AssetERC1155, AssetERC20, AssetERC721} from '../utils/assets.ts'; +import {AbiCoder, Contract, Signer, ZeroAddress} from 'ethers'; import { hashKey, + isOrderEqual, + Order, OrderDefault, signOrder, - Order, - isOrderEqual, } from '../utils/order.ts'; -import {ZeroAddress, AbiCoder, Contract, Signer} from 'ethers'; // eslint-disable-next-line mocha/no-exports export function shouldMatchOrders() { @@ -26,7 +26,6 @@ export function shouldMatchOrders() { defaultFeeReceiver: Signer, maker: Signer, taker: Signer, - makeRecipient: Signer, user: Signer, makerAsset: Asset, takerAsset: Asset, @@ -53,7 +52,6 @@ export function shouldMatchOrders() { defaultFeeReceiver, user1: maker, user2: taker, - user3: makeRecipient, user, PAUSER_ROLE, ERC1776_OPERATOR_ROLE, @@ -99,6 +97,222 @@ export function shouldMatchOrders() { takerSig = await signOrder(orderRight, taker, OrderValidatorAsAdmin); }); + describe('Custom recipient', function () { + it('allows seller to set custom recipient for sale proceeds', async function () { + await ERC721Contract.mint(maker.getAddress(), 1); + await ERC721Contract.connect(maker).approve( + await ExchangeContractAsUser.getAddress(), + 1 + ); + + await ERC20Contract.mint(taker.getAddress(), 1); + await ERC20Contract.connect(taker).approve( + await ExchangeContractAsUser.getAddress(), + 1 + ); + + makerAsset = await AssetERC721( + ERC721Contract, + 1, + await user.getAddress() + ); + + takerAsset = await AssetERC20(ERC20Contract, 1); + + orderLeft = await OrderDefault( + maker, + makerAsset, + ZeroAddress, + takerAsset, + 1, + 0, + 0 + ); + + orderRight = await OrderDefault( + taker, + takerAsset, + ZeroAddress, + makerAsset, + 1, + 0, + 0 + ); + + makerSig = await signOrder(orderLeft, maker, OrderValidatorAsAdmin); + takerSig = await signOrder(orderRight, taker, OrderValidatorAsAdmin); + + const initialMakerBalance = await ERC20Contract.balanceOf( + await maker.getAddress() + ); + const initialUserBalance = await ERC20Contract.balanceOf( + await user.getAddress() + ); + + await ExchangeContractAsUser.matchOrders([ + { + orderLeft, + signatureLeft: makerSig, + orderRight, + signatureRight: takerSig, + }, + ]); + + // The payment for the ERC721 token is sent to the custom recipient + // The owner of the ERC721 token is updated to the taker + // The protocol fee is transferred to the default fee receiver + + expect(await ERC721Contract.ownerOf(1)).to.be.equal( + await taker.getAddress() + ); + + expect( + await ERC20Contract.balanceOf(await maker.getAddress()) + ).to.be.equal(initialMakerBalance); + + // User should receive 1 token from the taker + expect( + await ERC20Contract.balanceOf(await user.getAddress()) + ).to.be.equal(initialUserBalance + 1n); + }); + + it('allows buyer to set custom recipient for purchase', async function () { + await ERC721Contract.mint(maker.getAddress(), 1); + await ERC721Contract.connect(maker).approve( + await ExchangeContractAsUser.getAddress(), + 1 + ); + + await ERC20Contract.mint(taker.getAddress(), 1); + await ERC20Contract.connect(taker).approve( + await ExchangeContractAsUser.getAddress(), + 1 + ); + + makerAsset = await AssetERC721(ERC721Contract, 1); + // Taker specified a custom recipient for the ERC721 token + takerAsset = await AssetERC20( + ERC20Contract, + 1, + await user.getAddress() + ); + + orderLeft = await OrderDefault( + maker, + makerAsset, + ZeroAddress, + takerAsset, + 1, + 0, + 0 + ); + + orderRight = await OrderDefault( + taker, + takerAsset, + ZeroAddress, + makerAsset, + 1, + 0, + 0 + ); + + makerSig = await signOrder(orderLeft, maker, OrderValidatorAsAdmin); + takerSig = await signOrder(orderRight, taker, OrderValidatorAsAdmin); + + const initialTakerBalance = await ERC20Contract.balanceOf( + await taker.getAddress() + ); + + await ExchangeContractAsUser.matchOrders([ + { + orderLeft, + signatureLeft: makerSig, + orderRight, + signatureRight: takerSig, + }, + ]); + + expect( + await ERC20Contract.balanceOf(await taker.getAddress()) + ).to.be.equal(initialTakerBalance - 1n); + + // user should own the ERC721 token + expect(await ERC721Contract.ownerOf(1)).to.be.equal( + await user.getAddress() + ); + }); + + it('allows both buyer and seller to set custom recipients for the exchange', async function () { + await ERC1155Contract.mint(maker.getAddress(), 1, 1); + await ERC1155Contract.connect(maker).setApprovalForAll( + await ExchangeContractAsUser.getAddress(), + true + ); + await ERC20Contract.mint(taker.getAddress(), 1); + await ERC20Contract.connect(taker).approve( + await ExchangeContractAsUser.getAddress(), + 1 + ); + + makerAsset = await AssetERC1155( + ERC1155Contract, + 1, + 1, + await user.getAddress() + ); + takerAsset = await AssetERC20( + ERC20Contract, + 1, + await user.getAddress() + ); + + orderLeft = await OrderDefault( + maker, + makerAsset, + ZeroAddress, + takerAsset, + 1, + 0, + 0 + ); + orderRight = await OrderDefault( + taker, + takerAsset, + ZeroAddress, + makerAsset, + 1, + 0, + 0 + ); + + makerSig = await signOrder(orderLeft, maker, OrderValidatorAsAdmin); + takerSig = await signOrder(orderRight, taker, OrderValidatorAsAdmin); + + const initialUserBalance = await ERC20Contract.balanceOf( + await user.getAddress() + ); + + await ExchangeContractAsUser.matchOrders([ + { + orderLeft, + signatureLeft: makerSig, + orderRight, + signatureRight: takerSig, + }, + ]); + + // user should own the ERC1155 token + expect( + await ERC1155Contract.balanceOf(await user.getAddress(), 1) + ).to.be.equal(1); + // user should receive 1 token from the taker + expect( + await ERC20Contract.balanceOf(await user.getAddress()) + ).to.be.equal(initialUserBalance + 1n); + }); + }); + describe('ERC20 x ERC20 token', function () { it('should execute a complete match order between ERC20 tokens', async function () { expect(await ERC20Contract.balanceOf(maker)).to.be.equal(10000000000); @@ -963,88 +1177,6 @@ export function shouldMatchOrders() { }); }); - it('different recipients test', async function () { - const recipientAddress = await makeRecipient.getAddress(); - const makerAssetForLeftOrder = await AssetERC20( - ERC20Contract, - 10000000000 - ); - const takerAssetForLeftOrder = await AssetERC20( - ERC20Contract2, - 20000000000 - ); - - const takerAssetForRightOrder = await AssetERC20( - ERC20Contract2, - 10000000000 - ); - - const makerAssetForRightOrder = await AssetERC20( - ERC20Contract, - 5000000000 - ); - - orderLeft = await OrderDefault( - maker, - makerAssetForLeftOrder, - ZeroAddress, - takerAssetForLeftOrder, - 1, - 0, - 0, - recipientAddress - ); - - orderRight = await OrderDefault( - taker, - takerAssetForRightOrder, - ZeroAddress, - makerAssetForRightOrder, - 1, - 0, - 0, - recipientAddress - ); - - makerSig = await signOrder(orderLeft, maker, OrderValidatorAsAdmin); - takerSig = await signOrder(orderRight, taker, OrderValidatorAsAdmin); - - expect( - await ExchangeContractAsUser.fills(hashKey(orderLeft)) - ).to.be.equal(0); - expect( - await ExchangeContractAsUser.fills(hashKey(orderRight)) - ).to.be.equal(0); - expect(await ERC20Contract.balanceOf(maker)).to.be.equal(10000000000); - expect(await ERC20Contract.balanceOf(taker)).to.be.equal(0); - expect(await ERC20Contract2.balanceOf(maker)).to.be.equal(0); - expect(await ERC20Contract2.balanceOf(taker)).to.be.equal(20000000000); - - await ExchangeContractAsUser.matchOrders([ - { - orderLeft, - signatureLeft: makerSig, - orderRight, - signatureRight: takerSig, - }, - ]); - - expect( - await ExchangeContractAsUser.fills(hashKey(orderLeft)) - ).to.be.equal(10000000000); - expect( - await ExchangeContractAsUser.fills(hashKey(orderRight)) - ).to.be.equal(5000000000); - expect(await ERC20Contract.balanceOf(maker)).to.be.equal(5000000000); - expect(await ERC20Contract.balanceOf(recipientAddress)).to.be.equal( - 5000000000 - ); - expect(await ERC20Contract2.balanceOf(recipientAddress)).to.be.equal( - 10000000000 - ); - expect(await ERC20Contract2.balanceOf(taker)).to.be.equal(10000000000); - }); - it('should emit a Match event', async function () { expect(await ERC20Contract.balanceOf(maker)).to.be.equal(10000000000); expect(await ERC20Contract.balanceOf(taker)).to.be.equal(0); diff --git a/packages/marketplace/test/exchange/MatchOrdersWithRoyalties.behavior.ts b/packages/marketplace/test/exchange/MatchOrdersWithRoyalties.behavior.ts index 0e875cce3c..4f62b672ae 100644 --- a/packages/marketplace/test/exchange/MatchOrdersWithRoyalties.behavior.ts +++ b/packages/marketplace/test/exchange/MatchOrdersWithRoyalties.behavior.ts @@ -30,7 +30,6 @@ export function shouldMatchOrdersWithRoyalty() { admin: Signer, maker: Signer, taker: Signer, - makeRecipient: Signer, receiver1: Signer, receiver2: Signer, royaltyReceiver: Signer, @@ -59,7 +58,6 @@ export function shouldMatchOrdersWithRoyalty() { admin, user1: maker, user2: taker, - user3: makeRecipient, admin: receiver1, user: receiver2, deployer: royaltyReceiver, @@ -661,92 +659,6 @@ export function shouldMatchOrdersWithRoyalty() { ); }); - it('should execute a complete match order taking in account a different recipient', async function () { - await ERC721Contract.mint(maker.getAddress(), 1); - await ERC721Contract.connect(maker).approve( - await ExchangeContractAsUser.getAddress(), - 1 - ); - - // set up royalties by token - await RoyaltiesRegistryAsDeployer.setRoyaltiesByToken( - await ERC721Contract.getAddress(), - [await LibPartData(royaltyReceiver, 2000)] - ); - - ERC721Asset = await AssetERC721(ERC721Contract, 1); - orderLeft = await OrderDefault( - maker, - ERC721Asset, - ZeroAddress, - ERC20Asset, - 1, - 0, - 0, - await makeRecipient.getAddress() - ); - orderRight = await OrderDefault( - taker, - ERC20Asset, - ZeroAddress, - ERC721Asset, - 1, - 0, - 0 - ); - makerSig = await signOrder(orderLeft, maker, OrderValidatorAsAdmin); - takerSig = await signOrder(orderRight, taker, OrderValidatorAsAdmin); - - expect( - await ExchangeContractAsUser.fills(hashKey(orderLeft)) - ).to.be.equal(0); - expect( - await ExchangeContractAsUser.fills(hashKey(orderRight)) - ).to.be.equal(0); - expect(await ERC721Contract.ownerOf(1)).to.be.equal( - await maker.getAddress() - ); - expect(await ERC20Contract.balanceOf(taker.getAddress())).to.be.equal( - 10000000000 - ); - - await ExchangeContractAsUser.matchOrders([ - { - orderLeft, - signatureLeft: makerSig, - orderRight, - signatureRight: takerSig, - }, - ]); - - expect( - await ExchangeContractAsUser.fills(hashKey(orderLeft)) - ).to.be.equal(10000000000); - expect( - await ExchangeContractAsUser.fills(hashKey(orderRight)) - ).to.be.equal(1); - expect(await ERC721Contract.ownerOf(1)).to.be.equal( - await taker.getAddress() - ); - - // check protocol fee - expect( - await ERC20Contract.balanceOf(defaultFeeReceiver.getAddress()) - ).to.be.equal(250000000); // 250 * 10000000000 / 10000 = 250000000 - - // check paid royalty - expect( - await ERC20Contract.balanceOf(royaltyReceiver.getAddress()) - ).to.be.equal(2000000000); // 20% of the amount - - //recipient should receive the payment in tokens - expect( - await ERC20Contract.balanceOf(makeRecipient.getAddress()) - ).to.be.equal( - 7750000000 // 10000000000 - royalty - protocolFee - ); - }); - describe('token without IROYALTYUGC support', function () { beforeEach(async function () { await ERC721WithRoyaltyWithoutIROYALTYUGC.mint(maker.getAddress(), 1, [ diff --git a/packages/marketplace/test/fixtures/index.ts b/packages/marketplace/test/fixtures/index.ts index e1bd32f2b3..4499f6263e 100644 --- a/packages/marketplace/test/fixtures/index.ts +++ b/packages/marketplace/test/fixtures/index.ts @@ -5,7 +5,7 @@ import {exchangeSetup} from './exchange'; import {mockAssetsSetup} from './assets'; export async function deployFixturesWithoutWhitelist() { - const [deployer, admin, user, defaultFeeReceiver, user1, user2, user3] = + const [deployer, admin, user, defaultFeeReceiver, user1, user2] = await ethers.getSigners(); const exchange = await exchangeSetup(); @@ -33,7 +33,6 @@ export async function deployFixturesWithoutWhitelist() { user, user1, user2, - user3, defaultFeeReceiver, ZERO_ADDRESS: ZeroAddress, }; diff --git a/packages/marketplace/test/utils/assets.ts b/packages/marketplace/test/utils/assets.ts index 0b04a60b9b..e022577de9 100644 --- a/packages/marketplace/test/utils/assets.ts +++ b/packages/marketplace/test/utils/assets.ts @@ -65,46 +65,75 @@ export const LibPartData = async ( export const AssetERC20 = async ( tokenContract: Contract, - value: Numeric -): Promise => ({ - assetType: { - assetClass: AssetClassType.ERC20_ASSET_CLASS, - data: AbiCoder.defaultAbiCoder().encode( - ['address'], - [await tokenContract.getAddress()] - ), - }, - value, -}); + value: Numeric, + recipient?: string +): Promise => { + const baseParams: string[] = ['address']; + const baseValues: (string | number)[] = [await tokenContract.getAddress()]; + + if (recipient) { + baseParams.push('uint256'); + baseValues.push(0); + baseParams.push('address'); + baseValues.push(recipient); + } + + console.log(baseParams); + console.log(baseValues); + + return { + assetType: { + assetClass: AssetClassType.ERC20_ASSET_CLASS, + data: AbiCoder.defaultAbiCoder().encode(baseParams, baseValues), + }, + value, + }; +}; export const AssetERC721 = async ( tokenContract: Contract, - tokenId: Numeric -): Promise => ({ - assetType: { - assetClass: AssetClassType.ERC721_ASSET_CLASS, - data: AbiCoder.defaultAbiCoder().encode( - ['address', 'uint256'], - [await tokenContract.getAddress(), tokenId] - ), - }, - value: 1, -}); + tokenId: Numeric, + recipient?: string +): Promise => { + const baseParams = ['address', 'uint256']; + const baseValues = [await tokenContract.getAddress(), tokenId]; + + if (recipient) { + baseParams.push('address'); + baseValues.push(recipient); + } + + return { + assetType: { + assetClass: AssetClassType.ERC721_ASSET_CLASS, + data: AbiCoder.defaultAbiCoder().encode(baseParams, baseValues), + }, + value: 1, + }; +}; export const AssetERC1155 = async ( tokenContract: Contract, tokenId: Numeric, - value: Numeric -): Promise => ({ - assetType: { - assetClass: AssetClassType.ERC1155_ASSET_CLASS, - data: AbiCoder.defaultAbiCoder().encode( - ['address', 'uint256'], - [await tokenContract.getAddress(), tokenId] - ), - }, - value, -}); + value: Numeric, + recipient?: string +): Promise => { + const baseParams = ['address', 'uint256']; + const baseValues = [await tokenContract.getAddress(), tokenId]; + + if (recipient) { + baseParams.push('address'); + baseValues.push(recipient); + } + + return { + assetType: { + assetClass: AssetClassType.ERC1155_ASSET_CLASS, + data: AbiCoder.defaultAbiCoder().encode(baseParams, baseValues), + }, + value, + }; +}; export function hashAssetType(a: AssetType) { if (a.assetClass === AssetClassType.INVALID_ASSET_CLASS) { diff --git a/packages/marketplace/test/utils/fill.ts b/packages/marketplace/test/utils/fill.ts index 705fe23913..a84bb0b026 100644 --- a/packages/marketplace/test/utils/fill.ts +++ b/packages/marketplace/test/utils/fill.ts @@ -20,7 +20,6 @@ export type FillData = { export const fillOrder = (makeValue: Numeric, takeValue: Numeric): Order => ({ maker: ZeroAddress, taker: ZeroAddress, - makeRecipient: ZeroAddress, end: 0, start: 0, salt: 0, diff --git a/packages/marketplace/test/utils/order.ts b/packages/marketplace/test/utils/order.ts index a20f9b9574..c17d53d40b 100644 --- a/packages/marketplace/test/utils/order.ts +++ b/packages/marketplace/test/utils/order.ts @@ -12,7 +12,7 @@ import { export const ORDER_TYPEHASH = keccak256( Buffer.from( - 'Order(address maker,Asset makeAsset,address taker,Asset takeAsset,address makeRecipient,uint256 salt,uint256 start,uint256 end)Asset(AssetType assetType,uint256 value)AssetType(uint256 assetClass,bytes data)' + 'Order(address maker,Asset makeAsset,address taker,Asset takeAsset,uint256 salt,uint256 start,uint256 end)Asset(AssetType assetType,uint256 value)AssetType(uint256 assetClass,bytes data)' ) ); @@ -24,7 +24,6 @@ export type Order = { makeAsset: Asset; taker: string; takeAsset: Asset; - makeRecipient: string; salt: Numeric; start: Numeric; end: Numeric; @@ -37,15 +36,13 @@ export const OrderDefault = async ( takeAsset: Asset, salt: Numeric, start: Numeric, - end: Numeric, - makeRecipient?: Address + end: Numeric ): Promise => ({ maker: await maker.getAddress(), makeAsset, taker: taker === ZeroAddress ? ZeroAddress : await (taker as Signer).getAddress(), takeAsset, - makeRecipient: makeRecipient || (await maker.getAddress()), // Use makerAddress if makeRecipient is not provided salt, start, end, @@ -53,10 +50,9 @@ export const OrderDefault = async ( export function hashKey(order: Order): string { const encoded = AbiCoder.defaultAbiCoder().encode( - ['address', 'address', 'bytes32', 'bytes32', 'uint256'], + ['address', 'bytes32', 'bytes32', 'uint256'], [ order.maker, - order.makeRecipient, hashAssetType(order.makeAsset.assetType), hashAssetType(order.takeAsset.assetType), order.salt, @@ -76,11 +72,7 @@ export const getSymmetricOrder = async ( takeAsset: o.makeAsset, }; if (taker) { - return { - ...ret, - maker: await taker.getAddress(), - makeRecipient: await taker.getAddress(), - }; + return {...ret, maker: await taker.getAddress()}; } if (o.taker === ZeroAddress) { throw new Error( @@ -98,7 +90,6 @@ export function hashOrder(order: Order): string { 'bytes32', 'address', 'bytes32', - 'address', 'uint256', 'uint256', 'uint256', @@ -109,7 +100,6 @@ export function hashOrder(order: Order): string { hashAsset(order.makeAsset), order.taker, hashAsset(order.takeAsset), - order.makeRecipient, order.salt, order.start, order.end, @@ -145,7 +135,6 @@ export async function signOrder( {name: 'makeAsset', type: 'Asset'}, {name: 'taker', type: 'address'}, {name: 'takeAsset', type: 'Asset'}, - {name: 'makeRecipient', type: 'address'}, {name: 'salt', type: 'uint256'}, {name: 'start', type: 'uint256'}, {name: 'end', type: 'uint256'},