Payment Splitter - Unable to release funds

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,

  1. Deployed the PaymentSplitter contract with 2 addresses and a 50/50 split.
  2. Deployed the NFT contract
  3. Minted an NFT and kept it on sell on OpenSea
  4. Bought the NFT from a different account
  5. Called withdraw method (from creator address) of the NFT contract to withdraw the amount in the PaymentSplitter contract
  6. 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"
}

:1234: 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);
    }
}

:computer: 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:

Is there anything that I am missing or doing wrong?

Thank you.

Check the balance of your payment splitter, try to add a get balance function or a payment emitter to check if payment splitter balance was updated.
You can checkout this post to know if you setup your payment splitter accurately.

1 Like

In a payment splitter parent contract, there was a require statement
require(payment != 0, "PaymentSplitter: account is not due payment");

Please do not use the contracts from the main branch, only tagged releases.


It seems the PaymentSplitter simply didn't receive any payments. Why did you expect it to have received payment? The sale price would have gone to the seller, and there doesn't seem to be any royalties on the contract.

Because after the sale, I called the withdraw method and while contract deployment, I had provided the address of the PaymentSplitter in this method.

Okay, I will give that a try.