Skip to content

ligolang/permit-cameligo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

28 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

permit-cameligo

This example contract implements an FA2 multi-asset contract with a TZIP-17 extension.

In this implementation, permits can be submitted and consumed in separate-steps.

Why permits?

Permits have 2 main use cases:

  • making gasless transaction
  • avoiding manipulating operators (FA2) or allowances (FA1.2) when a transaction must be done by a third party

Requirements

The contract is written in cameligo flavour of LigoLANG, to be able to compile the contract, you need either a ligo binary, or docker.

For deploy scripts, you also need to have nodejs installed, up to version 14 and docker if you wish to deploy on a sandbox.

Usage

  1. Run make install to install dependencies
  2. Run make compile to compile the contracts
  3. Run make deploy to deploy the contracts. You need to rename deploy/.env.dist to deploy/.env and fill the required variables.

You can also override make parameters by running :

make compile ligo_compiler=<LIGO_EXECUTABLE> PROTOCOL_OPT="--protocol <PROTOCOL>"

Use case: taco shop loyalty program

A potential use case is the digitalization of the good old loyalty card.

Loyalty Token creation

Expanding on the taco shop tutorial, let's say Pedro creates a new token to reward his customers.

sequenceDiagram
  actor Pedro
  participant FA2
  Note left of Pedro: Pedro create a token
  Pedro->>FA2: Create_token
Loading

Token distribution

Pedro rewards his customers with one token for each taco bought.

sequenceDiagram
  actor Pedro
  participant FA2
  Note left of Pedro: Pedro mint one token to<br> reward tacos buyers
  Pedro->>FA2: Mint_token
Loading

Permit creation

Alicia is a regular client of the taco shop. She already accumulated 10 tokens, which can be exchanged for a free taco. One day, she happens to be out of tez, so she decides to use her tokens to pay.

So, she asks Pedro to create a permit. The permitted action will be the transfer of 10 tokens from Alicia to Pedro. Once Pedro has verified the permit parameters given by Alicia, he calls the smart contract with them, registering the permit.

sequenceDiagram
  actor Alicia
  actor Pedro
  participant FA2
  Note left of Alicia: Alicia signs the transfer parameters
  Alicia->>Pedro: send public key, signature, hash
  Note left of Pedro: Pedro registers Alicia request by creating a permit<br> with her public key, signature and hash.
  Pedro->>FA2: Permit(key, (signature, bytes))
Loading

Permit consumption

The last step consists in Alicia asking Pedro to consume the permit, by revealing him the parameters she used for the permit creation, allowing Pedro to call the transfer entrypoint with these parameters, actually consuming the permit.

sequenceDiagram
  actor Alicia
  actor Pedro
  participant FA2
  Note left of Alicia: Alicia reveals the parameters<br> used for the previously created permit.
  Alicia->>Pedro: reveal params
  Note left of Pedro: Pedro calls the transfer entry point for Alicia
  Pedro->>FA2: Transfer
Loading

Entrypoints

On top of FA2 standard, the following entrypoints are implemented:

  • permit: allows any sender to register a permit.
  • setExpiry: allows any sender to change its expiry configuration for its own permits. (intended camel case to comply with tzip-17)
  • transfer: overrides FA2 transfer to add the handling of permitted parameters.

Additionally, for the use case presentation, 3 entrypoints have been added:

  • create_token: creates a token.
  • mint_token: mint a token.
  • burn_token: burn a token.
  • set_admin: to set the authorized account for the 3 above entry points.

Smart Contract Data Types

classDiagram
    Permit <|-- Storage
    UserExpiry <|-- Storage
    PermitExpiry <|-- Storage

    class Storage {
        defaultExpiry: nat
        counter: nat
    }

    class Permit{
        type t
    }

    class UserExpiry {
        type t
        get(address)
        set(address, nat)
    }

    class PermitExpiry {
        type t
        get(address, bytes)
        set(address, bytes, nat)
    }
Loading

Resources