adeelhasan / licensing-dapp

9 stars 0 forks source link

Introduction

Software License NFTs are relatively straightforward, where token ownership establishes a licensee relationship which can be validated at runtime. This project augments that concept by having the option to specify an expiration date. This is more in line with how software subscription models work. Additionally, licensees can rent out their license, with a pay-as-you-go / streaming option .

A license can be thought of as a product or a product tier. By grouping licenses under a LicensingProject contract, it is simpler to express various tiers of a product, both in terms of pricing as well as supported functionality. For example, there can be a limited free trial, a standard version and its "pro" variant. And these can be on a recurring basis.

Payments can be collected in ether/native currency as well as in tokens.

Usage

If you want to use duration based licenses, the LicenseProject contract will be sufficient. If the ability for licensees to rent out their license will be needed, then the RentableLicenseProject (which descends from LicenseProject) should be used. In either case, the sequence is to create a license and for an end user to purchase it.

function addLicense(string memory name, uint256 maxRenewals, uint256 duration, uint256 price) returns (uint256 licenseId)

the license id returned is then referenced in a call to purchase the license, and at that point an NFT is minted:

function buyLicense(uint256 licenseId, uint256 startTime) 

The validity is checked via the following function:

function checkValidity(uint tokenId) public virtual returns (bool)

The context can guide how often the check should be called. Even if the license is current, the check will return false if called by an address which is neither the owner nor the renter.

Rentals

The RentableLicenseProject contract is elaborated for renting out a license. It can be thought of as a reservation system for the duration of license validity. The end user will buy a lease, based on a listing created by the license / token holder. The listing specifies the rate for a block of time called a RentalTimeUnit.

enum RentalTimeUnit { Seconds, Minutes, Hourly, Daily, Weekly, Monthly, Annual }
function addRentalListing(
    uint256 tokenId,
    RentalTimeUnit timeUnit,
    uint256 timeUnitPrice,
    uint256 minimumUnits,
    uint256 maximumUnits,
    bool allowStreaming
)
    public
    returns (uint256 listingId)     

So eg, you can create a listing which lays out a daily rental rate. You can also pick a minimum or maximum number of rental units that need to be bought to start a lease. So eg, you can have an hourly rate, but restrict the user to at least 1 hour or at most 12 hours. At the same time, the same license can have a monthly rate quoted. At the moment there is no support for arbitrary start and end dates for a lease.

Each license can have a single listing per RentalTimeUnit. Eg, you cannot have two hourly rates quoted for the same license. When a renter buys a listing, a RentalLease is established. There can be multiple leases, eg, if a token is for a year, there can be different leases for two different time periods within that year. Leases cannot overlap, eg. if the 15th of April is rented out from 12 pm to 10 pm, then a month long lease from the 10th of April to the 10th of May won't be given.

function buyLease(
    uint256 tokenId,
    uint256 listingId,
    uint256 startTime,
    uint256 timeUnitsCount,
    bool streamLease
) 
    public
    payable
    returns (uint256 leaseId)

Streaming Rentals

For a RentalListing which has allowStreaming enabled, the RentalLease will have the option to become a stream as well. This means that the billing for the license will be pay-as-you-go based on the price per second as in the RentalListing. The renter can cancel the lease at any point before the lease expiration and get the pro-rated refund. The token holder however cannot cancel the lease, and can withdraw the rent accumulated based on usage. Note that in all other cases, the rent is paid upfront.

Installation

Install Foundry if not already done so.

git clone --recurse-submodules CLONE_URL

If the standard library did not come across, install that

forge install foundry-rs/forge-std --no-commit

then forge build and forge test.