Skip to content

Commit

Permalink
Docs update: Plutus
Browse files Browse the repository at this point in the history
Based on Aiken's Hello WOrld example.

TODO:
I couldn't get the redeem contract to be accepted by the network.
We need to figure out why and update this example.

Replaces the plutus part of #307
  • Loading branch information
rooooooooob committed Jul 25, 2024
1 parent bf34fe4 commit 8e6cfcb
Showing 1 changed file with 139 additions and 0 deletions.
139 changes: 139 additions & 0 deletions docs/docs/modules/builders/plutus_contracts.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
---
sidebar_position: 2
---

# Aiken's Hello World Example

Using Aiken's [hello world](https://aiken-lang.org/example--hello-world/basics) example we can see how to use datums and redeemers with the transaction builder.

To deploy the contract datum we need to create an output to the contract with the datum attached like so:

```rust
let change_addr: Address = todo!("Add your change address here");
let sk1: PrivateKey = todo!("Add your own private key here that controls the input");
let sk2: PrivateKey = todo!("Add your own private key here for the contract's datum");

let mut tx_builder = make_tx_builder();

// input needed to pay for the tx
tx_builder.add_input(SingleInputBuilder::new(
TransactionInput::new(
TransactionHash::from_hex("1665fc34e312445884d752a557e6b3499e1fc10228de77ca712b6bda9078ced7").unwrap(),
0
),
TransactionOutput::new(
addr.clone(),
Value::from(10000000000),
Some(DatumOption::new_hash(contract_datum.hash())),
None
),
).payment_key().unwrap())?;

// contract created from bytes from the Plutus.json generated by Aiken
let contract = PlutusV2Script::from_cbor_bytes(&hex::decode("58f2010000323232323232323222232325333008323232533300b002100114a06644646600200200644a66602200229404c8c94ccc040cdc78010028a511330040040013014002375c60240026eb0c038c03cc03cc03cc03cc03cc03cc03cc03cc020c008c020014dd71801180400399b8f375c6002600e00a91010d48656c6c6f2c20576f726c6421002300d00114984d958c94ccc020cdc3a400000226464a66601a601e0042930b1bae300d00130060041630060033253330073370e900000089919299980618070010a4c2c6eb8c030004c01401058c01400c8c014dd5000918019baa0015734aae7555cf2ab9f5742ae881").unwrap()).unwrap();
let contract_addr = EnterpriseAddress::new(
change_addr.network_id().unwrap(),
StakeCredential::new_script(contract.hash()),
).to_address();

// contract datum
let contract_datum = PlutusData::new_constr_plutus_data(
ConstrPlutusData::new(0, vec![PlutusData::new_bytes(sk2.to_public().hash().to_raw_bytes().to_vec())])
);

// send funds to the contract
tx_builder.add_output(SingleOutputBuilderResult::new(
TransactionOutput::new(contract_addr.clone(), Value::from(5000000000), None, None)
));

let mut signed_tx_builder = tx_builder.build(
ChangeSelectionAlgo::Default,
&addr
)?;

let tx_hash = hash_transaction(&signed_tx_builder.body());
signed_tx_builder.add_vkey(make_vkey_witness(&tx_hash, &sk1));
let tx = signed_tx_builder.build_checked().unwrap();
```

After we've deployed this contract it is time to redeem it.

```rust
// contract / tx_builder / contract_datum are same as above

let redeemer_datum = PlutusData::new_constr_plutus_data(
ConstrPlutusData::new(0, vec![PlutusData::new_bytes("Hello, World!".as_bytes().to_vec())])
);

tx_builder.add_input(SingleInputBuilder::new(
TransactionInput::new(
TransactionHash::from_hex("6079e89a1eeba9ef1d6a334f8edbf6029ff5299315a3fd55fce732da6a72fd9b").unwrap(),
0
),
TransactionOutput::new(
addr.clone(),
Value::from(7500000),
None,
None
),
).plutus_script(
PartialPlutusWitness::new(
PlutusScriptWitness::Script(contract.into()),
redeemer_datum.clone()
),
vec![sk1.to_public().hash(), sk2.to_public().hash()],
contract_datum.clone(),
).unwrap())?;

// In order to run plutus contracts we must supply collateral which will only be spent if the contract does
// not provide enough ADA specified via exunits to execute it.
tx_builder.add_collateral(SingleInputBuilder::new(
TransactionInput::new(
TransactionHash::from_hex("5acebd1bc82df3d6c8f50908c1a182d5fb2ff0525066fa5a3ec44fe8df80f005").unwrap(),
0,
),
TransactionOutput::new(
addr.clone(),
Value::from(5000000),
None,
None,
),
).payment_key().unwrap())?;
let mut redeemer_builder = tx_builder.build_for_evaluation(
ChangeSelectionAlgo::Default,
&addr,
)?;

// We must then send this draft tx for evaluation via ogmios, blockfrost, etc
// in order to figure out how many exunits are necessary to evaluate it
println!("draft tx: {}", hex::encode(redeemer_builder.draft_tx()?.to_cbor_bytes()));

// once we get the exunits required back we can set it and be ready to finalize the signing of the tx
redeemer_builder.set_exunits(
RedeemerWitnessKey::new(RedeemerTag::Spend, 0),
ExUnits::new(5000000, 2000000000),
);
let redeemers = redeemer_builder.build()?;
tx_builder.set_exunits(
RedeemerWitnessKey::new(RedeemerTag::Spend, 0),
ExUnits::new(5000000, 2000000000),
);


let mut signed_tx_builder = tx_builder.build(
ChangeSelectionAlgo::Default,
&addr
)?;
let tx_hash = hash_transaction(&signed_tx_builder.body());
signed_tx_builder
.add_vkey(make_vkey_witness(
&tx_hash,
&sk1,
));
signed_tx_builder
.add_vkey(make_vkey_witness(
&tx_hash,
&sk2,
));
let tx = signed_tx_builder.build_checked().unwrap();
```

0 comments on commit 8e6cfcb

Please sign in to comment.