Smart Contracts
Here's a list of open-source smart contracts, complete with documentation, live demos, and end-to-end source code.
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.
In this demo, we will lock an asset from your wallet in an 'always succeed' smart contract.
Connect wallet to run this demo
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
.
In this demo, we will unlock the asset that we have locked in the previous demo.
Connect wallet to run this demo
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 native assets with Plutus Script. For this example, the Plutus script expects a data field of 'mesh'.
Connect wallet to run this demo
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 a script to create a custom script.
Apply parameters to a script to create a custom script.
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 StartRedeemer
as 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
: