Skip to content
This repository has been archived by the owner on Dec 23, 2024. It is now read-only.

[feat] Offers v1.0 #126

Merged
merged 22 commits into from
Feb 9, 2022
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
422 changes: 422 additions & 0 deletions contracts/modules/Offers/V1/OffersV1.sol

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions contracts/test/ZoraModuleManager.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ contract ZoraModuleManagerTest is DSTest {
module = batchModules[0];
}

/// ------------ APPROVE MODULE ------------
/// ------------ APPROVE MODULE ------------ ///

function test_SetApproval() public {
registrar.registerModule(module);
Expand All @@ -62,7 +62,7 @@ contract ZoraModuleManagerTest is DSTest {
bob.setApprovalForModule(module, true);
}

/// ------------ APPROVE MODULE BATCH ------------
/// ------------ APPROVE MODULE BATCH ------------ ///

function test_SetBatchApproval() public {
for (uint256 i = 0; i < 3; i++) {
Expand Down
166 changes: 166 additions & 0 deletions contracts/test/modules/Offers/V1/Offers.integration.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.10;

import {DSTest} from "ds-test/test.sol";

import {OffersV1} from "../../../../modules/Offers/V1/OffersV1.sol";
import {Zorb} from "../../../utils/users/Zorb.sol";
import {ZoraRegistrar} from "../../../utils/users/ZoraRegistrar.sol";
import {ZoraModuleManager} from "../../../../ZoraModuleManager.sol";
import {ZoraProtocolFeeSettings} from "../../../../auxiliary/ZoraProtocolFeeSettings/ZoraProtocolFeeSettings.sol";
import {ERC20TransferHelper} from "../../../../transferHelpers/ERC20TransferHelper.sol";
import {ERC721TransferHelper} from "../../../../transferHelpers/ERC721TransferHelper.sol";
import {RoyaltyEngine} from "../../../utils/modules/RoyaltyEngine.sol";

import {TestERC721} from "../../../utils/tokens/TestERC721.sol";
import {WETH} from "../../../utils/tokens/WETH.sol";
import {VM} from "../../../utils/VM.sol";

/// @title OffersV1IntegrationTest
/// @notice Integration Tests for Offers v1.0
contract OffersV1IntegrationTest is DSTest {
VM internal vm;

ZoraRegistrar internal registrar;
ZoraProtocolFeeSettings internal ZPFS;
ZoraModuleManager internal ZMM;
ERC20TransferHelper internal erc20TransferHelper;
ERC721TransferHelper internal erc721TransferHelper;
RoyaltyEngine internal royaltyEngine;

OffersV1 internal offers;
TestERC721 internal token;
WETH internal weth;

Zorb internal seller;
Zorb internal buyer;
Zorb internal finder;
Zorb internal royaltyRecipient;

function setUp() public {
// Cheatcodes
vm = VM(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);

// Deploy V3
registrar = new ZoraRegistrar();
ZPFS = new ZoraProtocolFeeSettings();
ZMM = new ZoraModuleManager(address(registrar), address(ZPFS));
erc20TransferHelper = new ERC20TransferHelper(address(ZMM));
erc721TransferHelper = new ERC721TransferHelper(address(ZMM));

// Init V3
registrar.init(ZMM);
ZPFS.init(address(ZMM), address(0));

// Create users
seller = new Zorb(address(ZMM));
buyer = new Zorb(address(ZMM));
finder = new Zorb(address(ZMM));
royaltyRecipient = new Zorb(address(ZMM));

// Deploy mocks
royaltyEngine = new RoyaltyEngine(address(royaltyRecipient));
token = new TestERC721();
weth = new WETH();

// Deploy Offers v1.0
offers = new OffersV1(address(erc20TransferHelper), address(erc721TransferHelper), address(royaltyEngine), address(ZPFS), address(weth));
registrar.registerModule(address(offers));

// Set seller balance
vm.deal(address(seller), 100 ether);

// Mint buyer token
token.mint(address(buyer), 0);

// Seller swap 50 ETH <> 50 WETH
vm.prank(address(seller));
weth.deposit{value: 50 ether}();

// Users approve Offers module
seller.setApprovalForModule(address(offers), true);
buyer.setApprovalForModule(address(offers), true);

// Seller approve ERC20TransferHelper
vm.prank(address(seller));
weth.approve(address(erc20TransferHelper), 50 ether);

// Buyer approve ERC721TransferHelper
vm.prank(address(buyer));
token.setApprovalForAll(address(erc721TransferHelper), true);
}

/// ------------ ETH Offer ------------ ///

function runETH() public {
vm.prank(address(seller));
uint256 id = offers.createOffer{value: 1 ether}(address(token), 0, address(0), 1 ether, 1000);

vm.prank(address(buyer));
offers.fillOffer(address(token), 0, id, address(0), 1 ether, address(finder));
}

function test_ETHIntegration() public {
uint256 beforeSellerBalance = address(seller).balance;
uint256 beforeBuyerBalance = address(buyer).balance;
uint256 beforeRoyaltyRecipientBalance = address(royaltyRecipient).balance;
uint256 beforeFinderBalance = address(finder).balance;
address beforeTokenOwner = token.ownerOf(0);

runETH();

uint256 afterSellerBalance = address(seller).balance;
uint256 afterBuyerBalance = address(buyer).balance;
uint256 afterRoyaltyRecipientBalance = address(royaltyRecipient).balance;
uint256 afterFinderBalance = address(finder).balance;
address afterTokenOwner = token.ownerOf(0);

// 1 ETH withdrawn from seller
require((beforeSellerBalance - afterSellerBalance) == 1 ether);
// 0.05 ETH creator royalty
require((afterRoyaltyRecipientBalance - beforeRoyaltyRecipientBalance) == 0.05 ether);
// 1000 bps finders fee (Remaining 0.95 ETH * 10% finders fee = 0.095 ETH)
require((afterFinderBalance - beforeFinderBalance) == 0.095 ether);
// Remaining 0.855 ETH paid to buyer
require((afterBuyerBalance - beforeBuyerBalance) == 0.855 ether);
// NFT transferred to seller
require((beforeTokenOwner == address(buyer)) && afterTokenOwner == address(seller));
}

/// ------------ ERC-20 Offer ------------ ///

function runERC20() public {
vm.prank(address(seller));
uint256 id = offers.createOffer(address(token), 0, address(weth), 1 ether, 1000);

vm.prank(address(buyer));
offers.fillOffer(address(token), 0, id, address(weth), 1 ether, address(finder));
}

function test_ERC20Integration() public {
uint256 beforeSellerBalance = weth.balanceOf(address(seller));
uint256 beforeBuyerBalance = weth.balanceOf(address(buyer));
uint256 beforeRoyaltyRecipientBalance = weth.balanceOf(address(royaltyRecipient));
uint256 beforeFinderBalance = weth.balanceOf(address(finder));
address beforeTokenOwner = token.ownerOf(0);

runERC20();

uint256 afterSellerBalance = weth.balanceOf(address(seller));
uint256 afterBuyerBalance = weth.balanceOf(address(buyer));
uint256 afterRoyaltyRecipientBalance = weth.balanceOf(address(royaltyRecipient));
uint256 afterFinderBalance = weth.balanceOf(address(finder));
address afterTokenOwner = token.ownerOf(0);

// 1 WETH withdrawn from seller
require((beforeSellerBalance - afterSellerBalance) == 1 ether);
// 0.05 WETH creator royalty
require((afterRoyaltyRecipientBalance - beforeRoyaltyRecipientBalance) == 0.05 ether);
// 0.095 WETH finders fee (0.95 WETH * 10% finders fee)
require((afterFinderBalance - beforeFinderBalance) == 0.095 ether);
// Remaining 0.855 WETH paid to buyer
require((afterBuyerBalance - beforeBuyerBalance) == 0.855 ether);
// NFT transferred to seller
require((beforeTokenOwner == address(buyer)) && afterTokenOwner == address(seller));
}
}
Loading