```\n  function _payment(\n    uint256 collateralId,\n    uint8 position,\n    uint256 paymentAmount,\n    address payer\n  ) internal returns (uint256) {\n    if (paymentAmount == uint256(0)) {\n      return uint256(0);\n    }\n\n\n    uint256 lienId = liens[collateralId][position];\n    Lien storage lien = lienData[lienId];\n    uint256 end = (lien.start + lien.duration);\n    require(\n      block.timestamp < end || address(msg.sender) == address(AUCTION_HOUSE),\n      "cannot pay off an expired lien"\n    );\n\n\n    address lienOwner = ownerOf(lienId);\n    bool isPublicVault = IPublicVault(lienOwner).supportsInterface(\n      type(IPublicVault).interfaceId\n    );\n\n\n    lien.amount = _getOwed(lien);\n\n\n    address payee = getPayee(lienId);\n    if (isPublicVault) {\n      IPublicVault(lienOwner).beforePayment(lienId, paymentAmount);\n    }\n    if (lien.amount > paymentAmount) {\n      lien.amount -= paymentAmount;\n      lien.last = block.timestamp.safeCastTo32();\n      // slope does not need to be updated if paying off the rest, since we neutralize slope in beforePayment()\n      if (isPublicVault) {\n        IPublicVault(lienOwner).afterPayment(lienId);\n      }\n    } else {\n      if (isPublicVault && !AUCTION_HOUSE.auctionExists(collateralId)) {\n        // since the openLiens count is only positive when there are liens that haven't been paid off\n        // that should be liquidated, this lien should not be counted anymore\n        IPublicVault(lienOwner).decreaseEpochLienCount(\n          IPublicVault(lienOwner).getLienEpoch(end)\n        );\n      }\n      //delete liens\n      _deleteLienPosition(collateralId, position);\n      delete lienData[lienId]; //full delete\n\n\n      _burn(lienId);\n    }\n\n\n    TRANSFER_PROXY.tokenTransferFrom(WETH, payer, payee, paymentAmount);\n\n\n    emit Payment(lienId, paymentAmount);\n    return paymentAmount;\n  }\n```\n