Hello,
I am trying to integrate PaymentSplitter with my NFT contract.
To do this, I imported the contract from GitHub (main branch - v4.4.1) and added the constructor with the required parameters.
After that, I added one more parameter in my NFT contract's constructor that will accept the address of the deployed PaymentSplitter contract and I set this variable in the withdraw method of my NFT contract.
To test,
- Deployed the PaymentSplitter contract with 2 addresses and a 50/50 split.
- Deployed the NFT contract
- Minted an NFT and kept it on sell on OpenSea
- Bought the NFT from a different account
- Called withdraw method (from creator address) of the NFT contract to withdraw the amount in the PaymentSplitter contract
- Called release method (from receiver's address). However, this failed with the error:
{
"code": 3,
"message": "execution reverted: PaymentSplitter: account is not due payment",
"data": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002b5061796d656e7453706c69747465723a206163636f756e74206973206e6f7420647565207061796d656e74000000000000000000000000000000000000000000"
}
Code to reproduce
Payment.sol
pragma solidity ^0.8.7;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/finance/PaymentSplitter.sol";
contract Payments is PaymentSplitter {
constructor(address[] memory _payees, uint256[] memory _shares) PaymentSplitter(_payees, _shares) payable {
}
}
MyNFT.sol
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "contracts/access/Ownable.sol";
contract MyNFT is ERC721Enumerable, Ownable {
using Strings for uint256;
string public baseURI;
string public baseExtension = ".json";
uint256 public cost = 0.05 ether;
uint256 public presaleCost = 0.03 ether;
uint256 public maxSupply = 4;
uint256 public maxMintAmount = 1;
bool public paused = false;
mapping(address => bool) public whitelisted;
mapping(address => bool) public presaleWallets;
address payable public paymentAddress; //For PaymentSplitter address
constructor(
string memory _name,
string memory _symbol,
string memory _initBaseURI,
address _paymentAddress
) ERC721(_name, _symbol) {
setBaseURI(_initBaseURI);
paymentAddress = payable(_paymentAddress);
mint(msg.sender, 1);
}
// internal
function _baseURI() internal view virtual override returns (string memory) {
return baseURI;
}
// public
function mint(address _to, uint256 _mintAmount) public payable {
uint256 supply = totalSupply();
require(!paused);
require(_mintAmount > 0);
require(_mintAmount <= maxMintAmount);
require(supply + _mintAmount <= maxSupply);
if (msg.sender != owner()) {
if (whitelisted[msg.sender] != true) {
if (presaleWallets[msg.sender] != true) {
//general public
require(msg.value >= cost * _mintAmount);
} else {
//presale
require(msg.value >= presaleCost * _mintAmount);
}
}
}
for (uint256 i = 1; i <= _mintAmount; i++) {
_safeMint(_to, supply + i);
}
}
function walletOfOwner(address _owner)
public
view
returns (uint256[] memory)
{
uint256 ownerTokenCount = balanceOf(_owner);
uint256[] memory tokenIds = new uint256[](ownerTokenCount);
for (uint256 i; i < ownerTokenCount; i++) {
tokenIds[i] = tokenOfOwnerByIndex(_owner, i);
}
return tokenIds;
}
function tokenURI(uint256 tokenId)
public
view
virtual
override
returns (string memory)
{
require(
_exists(tokenId),
"ERC721Metadata: URI query for nonexistent token"
);
string memory currentBaseURI = _baseURI();
return
bytes(currentBaseURI).length > 0
? string(
abi.encodePacked(
currentBaseURI,
tokenId.toString(),
baseExtension
)
)
: "";
}
//only owner
function setCost(uint256 _newCost) public onlyOwner {
cost = _newCost;
}
function setPresaleCost(uint256 _newCost) public onlyOwner {
presaleCost = _newCost;
}
function setmaxMintAmount(uint256 _newmaxMintAmount) public onlyOwner {
maxMintAmount = _newmaxMintAmount;
}
function setBaseURI(string memory _newBaseURI) public onlyOwner {
baseURI = _newBaseURI;
}
function setBaseExtension(string memory _newBaseExtension)
public
onlyOwner
{
baseExtension = _newBaseExtension;
}
function pause(bool _state) public onlyOwner {
paused = _state;
}
function whitelistUser(address _user) public onlyOwner {
whitelisted[_user] = true;
}
function removeWhitelistUser(address _user) public onlyOwner {
whitelisted[_user] = false;
}
function addPresaleUser(address _user) public onlyOwner {
presaleWallets[_user] = true;
}
function add100PresaleUsers(address[100] memory _users) public onlyOwner {
for (uint256 i = 0; i < 2; i++) {
presaleWallets[_users[i]] = true;
}
}
function removePresaleUser(address _user) public onlyOwner {
presaleWallets[_user] = false;
}
function withdraw() public payable onlyOwner {
(bool success, ) = payable(paymentAddress).call{value: address(this).balance}("");
require(success);
}
}
Environment
All the transactions were done on Remix in Injected Web3 environment using Metamask (Polygon Mainnet).
I tested it on Ploygon's testnet (Mumbai) as well as on the mainnet. The result was same on both of them.
In case, you want to see the transactions:
- PaymentSplitter Contract: 0x3172F382b37d696a89Ae535750FA4620071F5dEb
- MyNFT Contract: 0xEAb42174088d9d8D623aFc512ee8264D0889DbCA
- Creator: 0x93a6415f3D9E9275ddc3732A3f88D863917710e1
- One of the receiver: 0xe940AB0CEF2f9698b1188517Ce599C8c5Cb456AA
Is there anything that I am missing or doing wrong?
Thank you.