Skip to content

Latest commit

 

History

History

M12-non-fungible-tokens

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
title author
M12 - (Non/)Fungible Tokens
Walker Leite

Introduction

Getting Started

In this module we'll learn about Fungible and Non Fungible Tokens and we'll build a minting solution

To run this presentation type (you will need nix):

../../slide README.md

Community Support

Module Video

What you should know

Parameterized contracts (Plutus and CTL)

The problem

We already know Datums and Redeemers:

  • Datums are data attached to the transaction that are public in the blockchain (can be inspected) they are normally used to represent "contract state";
  • Redeemers are data sent to the validator to decide upon its spending according to the "contract state";
validator :: MyDatum -> MyRedeemer -> ScriptContext -> Bool

But what if you want to inject information in the contract that should not be public in the blockchain?

Solution

validator :: ContractParams -> MyDatum -> MyRedeemer -> ScriptContext -> Bool

validator is a function, you can just add as many arguments you need, if the validator has more than 3 arguments we say it's a parameterized contract.

What happens behind the scene is that the contract hash will be computed as soon as we apply all missing parameters.

Solution - Plutus

-- ...
data CorrectAnswer = CorrectAnswer Integer
unstableMakeIsData ''CorrectAnswer

data Password = Password Integer

{-# INLINEABLE validator #-}
validator :: CorrectAnswer -> BuiltinData -> Password -> BuiltinData -> ()
validator answer _ (Password n) _ | n == answer = ()
validator _ _ _ = _shouldFail

validator' :: Validator
validator' = Validator $ fromCompiledCode $$(compile [|| wrap ||])
  where
    wrap = validator . unsafeFromBuiltinData

Solution - CTL

-- ... on CTL
import Contract.Scripts (PlutusScript, ApplyArgsError, Validator, applyArgs)
-- ...
data CorrectAnswer = CorrectAnswer BigInt

instance ToData CorrectAnswer where
  toData (CorrectAnswer answer) = Constr zero
    [ toData answer
    ]

-- ..

applyError :: ApplyArgsError -> Error
applyError err = error $ "Failed to apply arguments to the script: " <> show err

-- ..

applyScript :: CorrectAnswer -> PlutusScript -> Either Error PlutusScript
applyScript answer ps = applyError `lmap` (applyArgs ps [toData answer])

validator :: CorrectAnswer -> Either Error Validator
validator answer =  wrap <$> (parseScript >>= applyScript answer)

Values

The problem

Up so far we've used only Ada (lovelace) token. What if we need to use our own custom native token?

Solution

newtype Value = Value { getValue :: Map.Map CurrencySymbol (Map.Map TokenName Integer) }

newtype CurrencySymbol = CurrencySymbol { unCurrencySymbol :: BuiltinByteString }

newtype TokenName = TokenName { unTokenName :: BuiltinByteString }

newtype AssetClass = AssetClass { unAssetClass :: (CurrencySymbol, TokenName) }

The convention is to use the script hash hex that have minted the token as CurrencySymbol. TokenName is free to be used in any way (normally we use it as the token symbol (eg: Ada) or a name + unique id. In the case of Ada, its CurrencySymbol is an empty string, given Ada is the only asset that have been minted in the genesis block (there is no minting script for Ada).

Value is also a monoid, you can append together many different Values to produce different combinations.

Minting Policy

Explanation

A minting policy is just a script that validates the mint transaction. The validator knows if it's a mint transaction through ScriptContext.

data ScriptContext = ScriptContext { scriptContextTxInfo :: TxInfo
                                   , scriptContextPurpose :: ScriptPurpose
                                   }
data ScriptPurpose = Minting CurrencySymbol
                   | Spending TxOutRef
                   | Rewarding StakingCredential
                   | Certifying DCert

NFT's

Explanation

So far we've seen fungible native tokens (eg: Ada). We also can have non-fungible native tokens (or unique tokens of a max quantity of 1). It works in the same way as in Values, but the quantity is always 1.

More on Native Tokens & NFT's

Breakthrough: Building a NFT Minting website