# Vesting Example

# Deploying to the Cardano Testnet

Lecture 3, Part 6

Lecture Video

Install and run a testnet node.

# Generating Wallets

To test out a contract, you'll want a couple wallets to interact with.

Change into the testnet directory under week 3

cd plutus-pioneer-program/code/week03/testnet

Generate a key for "wallet 1"

cardano-cli address key-gen \
  --verification-key-file 01.vkey \
  --signing-key-file 01.skey

Generate a key for "wallet 2"

cardano-cli address key-gen \
  --verification-key-file 02.vkey \
  --signing-key-file 02.skey

From these two commands, four new keys are created:

  • 01.vkey - wallet 1's verification key
  • 01.skey - wallet 1's signing key
  • 02.vkey - wallet 2's verification key
  • 02.skey - wallet 2's signing key

You can view any of these keys

cat 01.vkey

{
  "type": "PaymentVerificationKeyShelley_ed255519",
  "description": "Payment Verification Key",
  "cborHex": "582..."
}

The next commands require the testnet magic number.

View it in the genesis configuration for the started node

cat testnet-shelley-genesis.json | grep Magic
  "networkMagic": 1097911063

Build a testnet address based on wallet 1's verification key

cardano-cli address build \
  --payment-verification-key-file 01.vkey \
  --testnet-magic 1097911063 \
  --out-file 01.addr

And again, but for wallet 2

cardano-cli address build \
  --payment-verification-key-file 02.vkey \
  --testnet-magic 1097911063 \
  --out-file 02.addr

Those two commands generated two new files:

  • 01.addr - wallet 1's address
  • 02.addr - wallet 2's address

You can view them if you like

cat 01.addr
addr_test1vrlnf...

# Funding with Test ADA

You'll need some ADA to play with. On the testnet, this is called tADA. You can request tADA for free using the testnet faucet.

First, copy the address of wallet 1 to your clipboard

Then go to https://testnets.cardano.org/en/testnets/cardano/tools/faucet

Paste in the address into the Address box

Check the I'm not a robot checkbox to complete the CAPTCHA.

Click on Request funds

A new transaction is automatically generated with 1000 tADA to your address as an output.

You can query for all UTxOs containing wallet 1's address

cardano-cli query utxo \
  --address $(cat 01.addr)
  --testnet-magic 1097911063

TxHash  TxIx  Amount
--------------------------------------------------
1e7...     0  1000000000 lovelace + TxOutDatumNone

Since we just created this wallet and used the faucet to receive 1000 tADA, there's a single UTxO that contains that amount.

# Transferring from One Address to Another

The faucet only lets you use it once every 24 hours. To fund wallet 2, we can transfer tADA from wallet 1. This type of transaction requires 3 cardano-cli actions:

  • Build the transaction
  • Sign the transaction
  • Submit the transaction

Week 3's testnet directory contains a shell script to do these three things. So you don't have to type out the whole thing. You will, however, have to modify this file slightly.

Edit send.sh

vim send.sh

On line 5, you need to paste in the TxHash of the UTxO that contains the 1000 tADA. Note that --tx-in takes the TxHash, followed by #, followed by the TxIx.

cardano-cli transaction build \
  --alonzo-era \
  --testnet-magic 1097911063 \
  --change-address $(cat 01.addr) \
  --tx-in dfc1a522cd34fe723a0e89f68ed43a520fd218e20d8e5705b120d2cedc7f45ad#0 \
  --tx-out "$(cat 02.addr) 10000000 lovelace" \
  --out-file tx.body

cardano-cli transaction sign \
  --tx-body-file tx.body \
  --signing-key-file 01.skey \
  --testnet-magic 1097911063 \
  --out-file tx.signed

cardano-cli transaction submit \
  --testnet-magic 1097911063 \
  --tx-file tx.signed

Wait a little bit for the transaction to be processed. On average, it takes about 20 seconds.

Query for relevant UTxOs again

cardano-cli query utxo \
  --address $(cat 01.addr)
  --testnet-magic 1097911063

TxHash  TxIx  Amount
--------------------------------------------------
9e1...     0  989834279 lovelace + TxOutDatumNone

Notice the original 1000 tADA UTxO is gone. It's no longer an Unspent Transaction Output. It has been spent. In its place is a new UTxO with a lower amount as expected. The lower amount is 1000 minus the 10 we sent to wallet 2 minus fees.

Query for wallet 2's UTxOs now

cardano-cli query utxo \
  --address $(cat 02.addr)
  --testnet-magic 1097911063

TxHash  TxIx  Amount
------------------------------------------------
9e1...     0  10000000 lovelace + TxOutDatumNone

Note that it contains 10 tADA as expected.

# Using Plutus in the Cardano CLI

Before using Plutus with the CLI, we have to write various serialized Plutus types to disk. Deploy.hs (in week 3's code directory) does this.

Source code

My commented code

The Cardano.API module is what cardano-cli uses under the hood. It contains all the functionality to interact with the network.

When writing a deployment script like this, you may need a wallet's public key hash. You can write hashes to files for each wallet like so:

cardano-cli address key-hash \
  --payment-verification-key-file 01.vkey
  --out-file 01.pkh

cardano-cli address key-hash \
  --payment-verification-key-file 02.vkey
  --out-file 02.pkh

The *.pkh files each contain a hash

cat 02.pkh
d4f...

You may also need a time in POSIX. You can use an online converter like EpochConverter. Enter a human-readable date and convert it to a timestamp in milliseconds.

In the case of week 3's Deploy.hs, make sure to scroll to the bottom and...

  • set the beneficiary to wallet 2's public key hash
  • set the deadline to a POSIX time in the future. Maybe 30-60 minutes out if you want to be able to test a grab failing before the deadline and then succeeding after

# Build the Script

First, you need write the script file to disk.

Make sure you're in a plutus-apps Nix shell, then start the REPL in week 3's code directory.

cd plutus-apps
nix-shell
cd ~/plutus-pioneer-program/code/week03
cabal repl

Week03.Deploy might already be loaded. If not, load it

:l src/week03/Deploy.hs

Write the validator to disk

writeVestingValidator

That function writes a file called vesting.plutus

Use that file to build the script

cardano-cli address build-script \
  --script-file vesting.plutus \
  --testnet-magic 1097911063 \
  --out-file vesting.addr

You can view the script's address

cat vesting.addr
addr_test1wq6...

# Use the give endpoint

To use any script endpoint, you'll need to again build, sign, and submit a transaction.

cardano-cli transaction build \
  --alonzo-era \
  --testnet-magic 1097911063 \
  --change-address $(cat 01.addr) \
  --tx-in abae0d0e19f75938537dc5e33252567ae3b1df1f35aafedd1402b6b9ccb7685a#0 \
  --tx-out "$(cat vesting.addr) 200000000 lovelace" \
  --tx-out-datum-hash-file unit.json \
  --out-file tx.body

cardano-cli transaction sign \
  --tx-body-file tx.body \
  --signing-key-file 01.skey \
  --testnet-magic 1097911063 \
  --out-file tx.signed

cardano-cli transaction submit \
  --testnet-magic 1097911063 \
  --tx-file tx.signed

These three commands are already written for you in testnet/give.sh. You will need to edit the --tx-in flag in that file. It should be the TxHash and TxIx of the UTxO where wallet 1's tADA is sitting. Again, you can find it with cardano-cli.

cardano-cli query utxo \
  --address $(cat 01.addr)
  --testnet-magic 1097911063

Run the script to build, sign, and submit the transaction

./give.sh

Check the script address to see the transaction

cardano-cli query utxo \
  --address $(cat vesting.addr)
  --testnet-magic 1097911063

TxHash  TxIx  Amount
--------------------------------------------------------------------------------
e10...     0  200000000 lovelace + TxOutDatumHash ScriptDataInAlonzoEra "923..."

The script address does indeed have the 200 ADA we gave from wallet 1

# Use the grab endpoint

Again, you'll need to build, sign, and submit a transaction.

cardano-cli transaction build \
  --alonzo-era \
  --testnet-magic 1097911063 \
  --change-address $(cat 02.addr) \
  --tx-in 18cbe6cadecd3f89b60e08e68e5e6c7d72d730aaa1ad21431590f7e6643438ef#1 \
  --tx-in-script-file vesting.plutus \
  --tx-in-datum-file unit.json \
  --tx-in-redeemer-file unit.json \
  --tx-in-collateral 18e93407ea137b6be63039fd3c564d4c5233e7eb7ce4ee845bc7df12c80e4df7#1 \
  --required-signer-hash c2ff616e11299d9094ce0a7eb5b7284b705147a822f4ffbd471f971a \
  --invalid-before 48866954 \
  --protocol-params-file protocol.json \
  --out-file tx.body

cardano-cli transaction sign \
  --tx-body-file tx.body \
  --signing-key-file 02.skey \
  --testnet-magic 1097911063 \
  --out-file tx.signed

cardano-cli transaction submit \
  --testnet-magic 1097911063 \
  --tx-file tx.signed

testnet/grab.sh has these three commands in it already.

You will need to modify --tx-in to be the TxHash and TxIx of the UTxO with the 200 tADA at the script address. That can be found with the last command you ran.

You will need to modify --tx-in-collateral to be a UTxO you have access to. Since wallet 2 is submitting this transaction, it should be a TxHash and TxIx of a UTxO they have access to. Find one using the CLI again.

cardano-cli query utxo \
  --address $(cat 02.addr)
  --testnet-magic 1097911063

You will need to modify --required-signer-hash to be the public key hash of wallet 2 since they are the beneficiary and the one submitting the grab transaction. This should match the beneficiary listed near the end of Deploy.hs. You can also see it again with the CLI.

cardano-cli address key-hash --payment-verification-key-file 02.vkey

Finally, you will need to modify --invalid-before to be the current slot. You can get the current slot from the CLI

cardano-cli query tip --testnet-magic 1097911063

Look for "slot". Copy and paste the number after the --invalid-before flag.

With all of that done, you can submit the transaction

./grab.sh

If the current time is before the deadline you set in Deploy.hs then you'll see an error

Script debugging logs: deadline not reached

If you try to run it again later, after the deadline as been reached, you'll see a success message

Transaction successfully submitted.

You can now query wallet 2 and see the 200 tADA (minus fees) as one of the matching UTxOs.

cardano-cli query utxo \
  --address $(cat 02.addr)
  --testnet-magic 1097911063

TxHash  TxIx  Amount
------------------------------------------------
578...     0  199634559 lovelace + TxOutDatumNone
9e1...     1  10000000 lovelace + TxOutDatumNone