📘

We are getting better!

We are moving towards more general and flexible contracts to allow you, the developer to create even more custom use-cases to fit your needs. See Step 1: Add a Smart Contract

All existing and integrating customers will continue to be supported.

Whether you're looking to create a custom smart contract from scratch or modify an existing one, using the Paper Compatible Interface is the recommended approach! Paper will be calling the interface functions to ensure your users have a seamless experience. We offer interfaces for both the ERC-721 and ERC-1155 Contracts. The main difference is the tokenID parameter.

🚧

Function names and types must match the interface below!

The function names are case sensitive. Using mismatched types like uint8/uint16 instead of uint256 will result in an error. Make sure function names and types are identical to the interface below!

contract IPaperCompatibleInterface {
    /// @custom:Required  
    ///
    /// @notice Gets any potential reason that the _userWallet is not able to claim _quantity of NFT.
    ///
    /// @dev You do not need to check if the user has enough balance in their wallet
    /// @dev You also do not need to check if there is enough quantity left to be claimed
    ///
    /// @param _userWallet The address of the user's wallet
    /// @param _quantity The number of NFTs to be purchased
    /// @return string containing the reason that they _userWallet cannot claim _quantity of the NFT if any. Empty string if the _userWallet can claim _quantity of the NFT.
    function getClaimIneligibilityReason(address _userWallet, uint256 _quantity) public view returns (string memory);

    /// @custom:Required
    ///
    /// @notice Checks the total amount of NFTs left to be claimed
    ///
    /// @return uint256 The number of NFTs left to be claimed
    function unclaimedSupply() public view returns (uint256);

    /// @custom:Required
    ///
    /// @notice Checks the price of the NFT
    ///
    /// @return uint256 The price of a single NFT in Wei
    function price() public view returns (uint256);

    /// @custom:Required
    /// 
    /// @notice Used by paper to purchase and deliver the NFT to the user.
    ///
    /// @dev This function should emit event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId)
    ///
    /// @param _userWallet The address of the user's wallet
    /// @param _quantity The number of NFTs to be purchased
    function claimTo(address _userWallet, uint256 _quantity) public payable;

    /// @dev should be emitted by the claimTo method
    event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
    
    /// @custom:Optional
    ///
    /// @notice Gets the address of the ERC20 contract that the NFT is priced in.
    ///
    /// @dev You do not need this if you are pricing in the chains native coin. E.g. Eth of Ethereum
    /// @dev You need this if you are pricing in some erc20 token. Some examples:
    /// - WETH on Polygon: 0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619
    /// - USDC on Polygon: 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174
    /// - USDC on Ethereum: 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
    ///
    /// @return string The address of the ERC20 contract that the NFT is priced in.
    function currency() public view returns (address);
}
contract IPaperCompatibleInterface {
    /// @custom:Required  
    ///
    /// @notice Gets any potential reason that the _userWallet is not able to claim _quantity of NFT.
    ///
    /// @dev You do not need to check if the user has enough balance in their wallet
    /// @dev You also do not need to check if there is enough quantity left to be claimed
    ///
    /// @param _userWallet The address of the user's wallet
    /// @param _quantity The number of NFTs to be purchased
    /// @param _tokenId The id of the NFT that the ineligibility reason corrsponds too.
    ///
    /// @return string containing the reason that they _userWallet cannot claim _quantity of the NFT if any. Empty string if the _userWallet can claim _quantity of the NFT.
    function getClaimIneligibilityReason(address _userWallet, uint256 _quantity, uint256 _tokenId) public view returns (string memory);

    /// @custom:Required
    ///
    /// @notice Checks the total amount of NFTs left to be claimed
    ///
    ///
    /// @param _tokenId The id of the NFT that the unclaimed supply corrsponds too.
    ///    
    /// @return uint256 The number of NFTs left to be claimed
    function unclaimedSupply(uint256 _tokenId) public view returns (uint256);
    
    /// @custom:Required
    ///
    /// @notice Checks the price of the NFT
    ///
    /// @param _tokenId The id of the NFT which the pricing corresponds too.
    ///
    /// @return uint256 The price of a single NFT in Wei
    function price(uint256 _tokenId) public view returns (uint256);

    /// @custom:Required
    /// 
    /// @notice Used by paper to purchase and deliver the NFT to the user.
    ///
    /// @dev This function should emit event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId)
    ///
    /// @param _userWallet The address of the user's wallet
    /// @param _quantity The number of NFTs to be purchased
    /// @param _tokenId The id of the NFT to be purchased
    function claimTo(address _userWallet, uint256 _quantity, uint256 _tokenId) public payable;

    /// @custom:Optional
    ///
    /// @notice Gets the address of the ERC20 contract that the NFT is priced in.
    ///
    /// @dev You do not need this if you are pricing in the chains native coin. E.g. Eth of Ethereum
    /// @dev You need this if you are pricing in some erc20 token. Some examples:
    /// - WETH on Polygon: 0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619
    /// - USDC on Polygon: 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174
    /// - USDC on Ethereum: 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
    ///
    /// @param _tokenId The id of the NFT which the erc20 address corresponds too.
    ///
    /// @return string The address of the ERC20 contract that the NFT is priced in.
    function currency(uint256 _tokenId) public view returns (address);
}

❗️

For more advanced builders, you may have a ERC-721 contracts with a tokenID. In this case you will need to use our interface build for ERC-1155 contracts, since that one is compatible with tokenID parameters.

If you're in need for some more inspiration or integration support, here's some sample contracts you can look at:

Now that you have a Paper-compatible smart contract, you're now ready to move on to Step 2: Building a Checkout Flow!