Smart Contracts

Want to get started with smart contracts? Here are some contracts for the most common use-cases.

Cardano introduced smart contract support in 2021, which allowed the creation of a number of decentralised applications.

To initiate a transaction, we import the Transaction class from the @meshsdk/core package and assign the wallet to the initiator property. We build the transaction with .build() constructs the transaction and returns a transaction CBOR. Behind the scenes, it selects all of the necessary inputs belonging to the wallet, calculates the fee for this transaction and returns the remaining assets to the change address. Use wallet.signTx() to sign transaction CBOR.

The verbose is optional and set to false by default, setting it to true will enable verbose logging for the txBodyJson prior going into build.

In this page, we will demonstrate various ways to interact with smart contracts.

Lock assets in Smart Contract

Assets may be reserved in a smart contract by "locking" them at the script's address. The assets can only be subsequently unlocked when certain conditions are met, for example, in the case of making a purchase in a marketplace contract.

In this demo, we will lock selected assets from your wallet in analways succeed smart contract. Even though it is called "always succeed" because there is no actual "validating" logic, unlocking the assets still requires the correct datum to be supplied. Also note that in practice, multiple assets (both native assets and lovelace) can be sent to the contract in a single transaction.

First, we need to create a script and resolve the script address. Luckily Mesh has a handy function to "resolve" (work out) the script address using: serializePlutusScript from the script's CBOR. Here's how it's done:

Next, we need to define the assets we want to lock in the smart contract.

Finally, we can build the transaction and submit it to the blockchain. You realize here we provided the datum value in the transaction. Since this is an always succeed script, any datum value will work, for this example, we used it to allow us to seach for this transaction later.

If the transaction is successful, you would usually want to keep a record of the asset's unit and the datum used in the transaction, as this information is useful to unlock the assets.

Lock assets in Smart Contract

In this demo, we will lock an asset from your wallet in an 'always succeed' smart contract.

Connect wallet to run this demo

No wallets installed

Unlock assets in Smart Contract

In this section, we will demonstrate how to unlock assets in a smart contract.

First, we need to define the smart contract script and resolve the script address.

Next, let's create a function to fetch the correct input UTxO from the script address. This input UTxO is needed for the transaction builder. Notee that in this demo, we are using KoiosProvider, but any of the providers which are implemented by Mesh can be used (see Providers).

For this demo, we search for the UTxO by using the datum that we have set in the previous step. In fact, depends on the redeemer logic of the script, only a transaction with the corrent datum supplied is able to unlock the assets. We query the script address for the UTxO that contains the correct data hash:

Then, we create the transaction to unlock the asset. We use the redeemValue method. The method takes the asset UTxO, the script, and the datum as parameters. We also use the sendValue method to send the asset to the recipient address. The setRequiredSigners method is used to set the required signers for the transaction.

Lastly, we build and sign the transaction. Note that here we need to set the 'partial sign' parameter to true.

Unlock assets in Smart Contract

In this demo, we will unlock the asset that we have locked in the previous demo.

Connect wallet to run this demo

No wallets installed

Minting Assets with Plutus Script

In this section, we will see how to mint native assets with a PlutusScript.

The PlutusScript object is used to define the Plutus script that will be used to mint the asset. The redeemer object is used to provide the data that the validator script will use to validate the transaction. For this example, the validator script is expecting a redeemer with a data field of "mesh".

Similar to previous examples, we define the asset metadata and mint object. The asset metadata is a JSON object that contains the metadata for the asset. The mint object contains the asset name, quantity, metadata, label, and recipient address.

Finally, we create a transaction and mint the asset with the mintAsset method. We set the required signers to include the address that is minting the asset.

Mint Assets with Plutus Script

Mint native assets with Plutus Script. For this example, the Plutus script expects a data field of 'mesh'.

Connect wallet to run this demo

No wallets installed

Apply Parameters to Script

Apply parameters to a script allows you to create a custom CIP-57 compliant script based on some inputs. For example, for the Marketplace contract, we define the owner of the marketplace and the fee percentage that the owner will receive. The script will be created based on these parameters which will return a unique script CBOR and script address.

Note, currently only core-csl supports applying parameters to a script. As such, you must install the package to use this feature.

applyParamsToScript has the following signature:

The parameters allowed for a script depends on how the script is written. For example the Marketplace script:

Thus, in order to apply parameters to this script, we resolve the pubkey address and the fee percentage basis point:

With Mesh, there are 3 PlutusData types of parameters that can be applied to a script. For more details about the 3 types, please refer to the documentation on PlutusData

  • Mesh (default)
  • JSON
  • CBOR
Apply Parameters to Script - Mesh type

Apply parameters to a script to create a custom script.

Apply Parameters to Script - JSON type

Apply parameters to a script to create a custom script.

Apply Parameters to Script - CBOR type

Apply parameters to a script to create a custom script.

Inline Datum

It is possible to attach a "datum" (piece of data) inline to a UTxO outputs, which allows us to use the UTxO to hold information which we can then use without having to spend it (as with normal UTxOs). You can learn more from CIP-32.

Here's an example of creating a UTxO with inline datum:

As you can see, you simply have to define the datum field in the Recipient input parameter, including a (value) and setting inline to true. This works for every transaction endpoints (e.g. sendLovelace(), sendAssets(), sendValue()).

Reference Script

Validation requires access to any scripts that are involved, but adding entire scripts to transactions increases the transaction size and can lead to bloating of the blockchain. A useful solution is to instead store script references in a UTxO, which allows us to later use that UTxO to build future transactions without having to include the entire script. Thus we can reduce the size of the transaction, which may allow us to send (for example) multiple scripts within one transaction without exceeding the maximum transaction size.

Simply define the script as the Recipient input parameter. This works for every transaction endpoints (e.g.. sendLovelace(), sendAssets(), sendValue()).

Designing Datum

Mesh allows you to freely design the datum structure to suit the plutus smart contract requirements. You can import the Data type to help you design the datum.

A string

A datum as simple as just a string, preferably a hex string.

A number

It can also be a number.

An array

Or an array, where each item can be either a string, number, a list, or a map.

A Map

It can also be a map, where both the keys and its values can be a string, number, a list, or a map.

With constructor

Or a datum with a constructor, where alternative is a number, and fields is an array.

Using Redeemer

For redeemers in Mesh, you use the type Action and you only supply the Data part to construct it.

Designing Redeemer

Similarly to the datum, there is freedom in design to suit any smart contract, but the redeemer needs to be supplied a little differently.

In this example, we represent a redeemer which matches the StartRedeemeras defined above with the first Used Address as input:

Supplying the SecondRedeemer as defined above:

Supplying the EndRedeemer as defined above:

Transaction construction

Within the transaction, we can include the redeemer within redeemValue: