I am trying to implement ERC2981 for royalties but want to use OpenZepplins Payment Splitter to split the royalty amount to two different addresses with two different amounts. I can't find any examples of both of these combined. I understand how to pass in the values to the constructor for the PaymentSplitter but not sure how to set those values for the royality methods. Here is an example of the code:

  constructor(string memory _name, string memory _symbol, address[] memory _payees, uint256[] memory _shares
    ) ERC721(_name, _symbol) PaymentSplitter(_payees, _shares) payable {

        //Need to figure out how to set _royalities.recipient to _payees and _royalties.salePrice to _shares

        console.log("Testing test deploy", _name, _symbol);
  function _setTokenRoyalty(uint256 tokenId, address recipient, uint256 salePrice) internal {
      //This is so expected 'value' will be at most 10,000 which is 100%
      require(salePrice <= 10000, "ERC2981Royalities: Too high");

      //How can I set the recipient to use the array of _payees and _shares here?
      _royalties[tokenId] = Royalty(recipient, salePrice);

  function royaltyInfo(uint256 tokenId, uint256 salePrice)
    returns (address receiver, uint256 royaltyAmount)
      require(_exists(tokenId), "Nonexistent token");

      if(_royalties[tokenId].recipient != address(0)) {
          return (_royalties[tokenId].recipient, salePrice * _royalties[tokenId].salePrice / 10000);
      Royalty memory royalty = _royalties[tokenId];
      if(royalty.recipient != address(0) && royalty.salePrice != 0) {
          return (royalty.recipient, (salePrice * royalty.salePrice) / 10000);
      return (address(0), 0);
  • Just make the splitter the recipient
    – johnny 5
    Mar 9, 2022 at 19:34
  • Thank you! You are 100% correct, but I had no idea how to implement this or what that meant. I have my answer bellow.
    – Cleoke
    May 3, 2022 at 23:51

2 Answers 2


EIP-2981 accepts just one address as royalty recipient so payment splitting logic should be on that address.



In order to have the main contract receive 100% of the minted NFT funds and split only the royalties I implemented the ERC2981 into my BohoNFT.sol contract. I created a separate contract using the code from PaymentSplitter.sol and passed that in for the royalties.

The PaymentSplitter.sol contract I used was Open Zepplin's contract. https://docs.openzeppelin.com/contracts/2.x/api/payment#PaymentSplitter I deployed it first and passed in the addresses and the percentages I wanted for the royalties into the constructor. One thing to note. The percentage will be based off the royalty amount you have set for the other contract. Since mine was 8% and I wanted 2% to go to the artist and 6% to go to another account, I needed to pass in 25 for the artist and 75 for the other account. (.08 * .25 = .02 which is 2%)

Here is an example of the values I used when deploying: address[] memory payees = ["0x..artistAddress", "0x..otherAddress"] and uint256[] memory shares_ = [25,75]. Once deployed use this contract address for the _receiver.

Then, I passed in address _receiver, uint256 _royalties into the constructor of the BohoNFT.sol contract and inside it called setRoyalties(_receiver, _royalties); The _receiver address I passed in was the deployed contract address of PaymentSplitter.sol (make sure to deploy this first before your other one) and the _royalties were 8% so I passed in 800.

Below are the methods I added to my BohoNFT contract.

/// @notice Allows to set the royalties on the contract
/// @param value Updated royalties (between 0 and 10000)
function setRoyalties(address recipient, uint256 value) public onlyOwner {
    _setRoyalties(recipient, value);

/// @inheritdoc ERC165
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721A, ERC2981Base) returns (bool) {
    return super.supportsInterface(interfaceId);

Side note: Since OpenSea did not recognize ERC2981 royalties at this time, I went into my NFT collection on OpenSea and setup the Creator Royalties to be 8% and set the address to the deployed contract address of the PaymentSplitter.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.