Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Docs update: Plutus #346

Draft
wants to merge 1 commit into
base: develop
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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();
```
Loading