Skip to content

Commit 47b2c96

Browse files
committed
Add plutus example
1 parent 2dd347d commit 47b2c96

File tree

4 files changed

+146
-1
lines changed

4 files changed

+146
-1
lines changed

examples/plutus/forty_two/README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# FortyTwo
2+
3+
This example implements the off-chain code of forty-two, a sample program in week2 of Plutus-Pioneer-Program.
4+
The original Plutus script cound be found [here](https://github.com/input-output-hk/plutus-pioneer-program/blob/6be7484d4b8cffaef4faae30588c7fb826bcf5a3/code/week02/src/Week02/Typed.hs).
5+
The compiled Plutus core cbor hex is stored in file [fortytwo.plutus](fortytwo.plutus) in this folder.
6+
7+
FortyTwo is a simple smart contract that could be unlocked only by a redeemer of Integer value 42.
8+
[forty_two.py](forty_two.py) contains the code of two transactions: 1) a giver sending 10 ADA to a script address,
9+
and 2) a taker spend the ADA locked in that script address.
10+
11+
Below is the visualization of the lifecycle of UTxOs involved:
12+
13+
14+
```
15+
16+
Giver Tx Taker Tx
17+
┏-------------------------------------------┓ ┏-------------------------------------------┓
18+
| | | |
19+
Spend Spend with Redeemer (42) |
20+
UTxO (X ADA) ━━━━━━━━┳━━━━━ Script UTxO (10 ADA) ━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━ UTxO (5 ADA) |
21+
| ┃ | | ┃ |
22+
| ┣━━━━━ Change UTxO (X-10 ADA) | | ┣━━━━━━━━━━━━ Change UTxO (~4.7 ADA) |
23+
| ┃ | | ┃ |
24+
| ┗━━━━━ Tx fee (~0.16 ADA) | | ┣━━━━━━━━━━━━ Tx fee (~0.3 ADA) |
25+
┗-------------------------------------------┛ | ┃ |
26+
| ┃ |
27+
| ┃ |
28+
| ┣━━━━━━━━━━━━ Collateral UTxO (5 ADA) |
29+
Taker's Collateral UTxO (5 ADA) ━━━━━━━━━━┛ |
30+
┗-------------------------------------------┛ |
31+
32+
```
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
"""
2+
3+
Off-chain code of taker and giver in fortytwo.
4+
5+
"""
6+
7+
8+
import os
9+
10+
import cbor2
11+
from retry import retry
12+
13+
from pycardano import *
14+
15+
NETWORK = Network.TESTNET
16+
17+
18+
def get_env_val(key):
19+
val = os.environ.get(key)
20+
if not val:
21+
raise Exception(f"Environment variable {key} is not set!")
22+
return val
23+
24+
25+
payment_skey = PaymentSigningKey.load(get_env_val("PAYMENT_KEY_PATH"))
26+
payment_vkey = PaymentVerificationKey.from_signing_key(payment_skey)
27+
28+
chain_context = BlockFrostChainContext(
29+
project_id=get_env_val("BLOCKFROST_ID"), network=NETWORK
30+
)
31+
32+
33+
@retry(delay=20)
34+
def wait_for_tx(tx_id):
35+
chain_context.api.transaction(tx_id)
36+
print(f"Transaction {tx_id} has been successfully included in the blockchain.")
37+
38+
39+
def submit_tx(tx):
40+
print("############### Transaction created ###############")
41+
print(tx)
42+
print(tx.to_cbor())
43+
print("############### Submitting transaction ###############")
44+
chain_context.submit_tx(tx.to_cbor())
45+
wait_for_tx(str(tx.id))
46+
47+
48+
def create_collateral(target_address, skey):
49+
collateral_builder = TransactionBuilder(chain_context)
50+
51+
collateral_builder.add_input_address(target_address)
52+
collateral_builder.add_output(TransactionOutput(target_address, 5000000))
53+
54+
submit_tx(collateral_builder.build_and_sign([skey], target_address))
55+
56+
57+
# ----------- Giver sends 10 ADA to a script address ---------------
58+
with open("fortytwo.plutus", "r") as f:
59+
script_hex = f.read()
60+
forty_two_script = cbor2.loads(bytes.fromhex(script_hex))
61+
62+
script_hash = plutus_script_hash(forty_two_script)
63+
64+
script_address = Address(script_hash, network=NETWORK)
65+
66+
giver_address = Address(payment_vkey.hash(), network=NETWORK)
67+
68+
builder = TransactionBuilder(chain_context)
69+
builder.add_input_address(giver_address)
70+
datum = PlutusData() # A Unit type "()" in Haskell
71+
builder.add_output(
72+
TransactionOutput(script_address, 10000000, datum_hash=datum_hash(datum))
73+
)
74+
75+
signed_tx = builder.build_and_sign([payment_skey], giver_address)
76+
77+
submit_tx(signed_tx)
78+
79+
# ----------- Taker takes 10 ADA from the script address ---------------
80+
81+
# taker_address could be any address. In this example, we will use the same address as giver.
82+
taker_address = giver_address
83+
84+
# Notice that transaction builder will automatically estimate execution units (num steps & memory) for a redeemer if
85+
# no execution units are provided in the constructor of Redeemer.
86+
# Put integer 42 (the secret that unlocks the fund) in the redeemer.
87+
redeemer = Redeemer(RedeemerTag.SPEND, 42)
88+
89+
utxo_to_spend = chain_context.utxos(str(script_address))[0]
90+
91+
builder = TransactionBuilder(chain_context)
92+
93+
builder.add_script_input(utxo_to_spend, forty_two_script, datum, redeemer)
94+
95+
# Send 5 ADA to taker address. The remaining ADA (~4.7) will be sent as change.
96+
take_output = TransactionOutput(taker_address, 5000000)
97+
builder.add_output(take_output)
98+
99+
non_nft_utxo = None
100+
for utxo in chain_context.utxos(str(taker_address)):
101+
if isinstance(utxo.output.amount, int):
102+
non_nft_utxo = utxo
103+
break
104+
105+
if non_nft_utxo is None:
106+
create_collateral(taker_address, payment_skey)
107+
108+
builder.collaterals.append(non_nft_utxo)
109+
110+
signed_tx = builder.build_and_sign([payment_skey], taker_address)
111+
112+
submit_tx(signed_tx)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
59082459082101000033232332233223232333222323332223233333333222222223233322232333322223232332232333222323332223232332233223232333332222233223322332233223322332222223232533530313330063333573466e1cd55ce9baa0054800081248c98d4c120cd5ce0260248238231bad0043333573466e1cd55cea8012400046601264646464646464646464646666ae68cdc39aab9d500a480008cccccccccc05ccd40948c8c8cccd5cd19b8735573aa004900011980e981c1aba15002302a357426ae8940088c98d4c160cd5ce02e02c82b82b09aab9e5001137540026ae854028cd4094098d5d0a804999aa8163ae502b35742a010666aa058eb940acd5d0a80399a8128209aba15006335025335505204a75a6ae854014c8c8c8cccd5cd19b8735573aa0049000119a80f9919191999ab9a3370e6aae7540092000233502733504075a6ae854008c114d5d09aba25002232635305c3357380c00ba0b60b426aae7940044dd50009aba150023232323333573466e1cd55cea80124000466a04a66a080eb4d5d0a80118229aba135744a004464c6a60b866ae7018017416c1684d55cf280089baa001357426ae8940088c98d4c160cd5ce02e02c82b82b09aab9e5001137540026ae854010cd4095d71aba15003335025335505275c40026ae854008c0dcd5d09aba2500223263530543357380b00aa0a60a426ae8940044d5d1280089aba25001135744a00226ae8940044d5d1280089aba25001135744a00226aae7940044dd50009aba150023232323333573466e1d400520062301c3039357426aae79400c8cccd5cd19b875002480108c06cc10cd5d09aab9e500423333573466e1d400d20022301b302e357426aae7940148cccd5cd19b875004480008c078dd71aba135573ca00c464c6a609e66ae7014c14013813413012c1284d55cea80089baa001357426ae8940088c98d4c120cd5ce026024823823082409931a982399ab9c49010350543500048046135573ca00226ea80048848cc00400c0088004888888888848cccccccccc00402c02802402001c01801401000c00880048848cc00400c008800448848cc00400c0084800448848cc00400c0084800448848cc00400c00848004848888c010014848888c00c014848888c008014848888c004014800448c88c008dd6000990009aa81a911999aab9f0012500e233500d30043574200460066ae880080cc8c8c8c8cccd5cd19b8735573aa006900011998039919191999ab9a3370e6aae754009200023300d303135742a00466a02605a6ae84d5d1280111931a981b99ab9c03b038036035135573ca00226ea8004d5d0a801999aa805bae500a35742a00466a01eeb8d5d09aba25002232635303333573806e06806406226ae8940044d55cf280089baa00122212333001004003002200122123300100300220011335500175ceb44488c88c008dd5800990009aa81791191999aab9f0022500923350083355031300635573aa004600a6aae794008c010d5d100181709aba10011122002122122330010040031200112232323333573466e1d400520002350083005357426aae79400c8cccd5cd19b87500248008940208c98d4c0a8cd5ce01701581481401389aab9d500113754002242446004006224400224002464646666ae68cdc39aab9d5002480008cc018c01cd5d0a8011bad357426ae8940088c98d4c090cd5ce01401281181109aab9e50011375400244246600200600440024646666ae68cdc39aab9d5001480008dd71aba135573ca004464c6a604066ae7009008407c0784dd500089119191999ab9a3370ea00290021280391999ab9a3370ea004900111a80518031aba135573ca00846666ae68cdc3a801a40004a014464c6a604666ae7009c09008808408007c4d55cea80089baa00112122230030041122200211222001120012323333573466e1d40052002200623333573466e1d400920002006232635301b33573803e03803403203026aae74dd50008910010910009000919191919191999ab9a3370ea0029006100591999ab9a3370ea0049005100691999ab9a3370ea00690041198059bae35742a00a6eb4d5d09aba2500523333573466e1d4011200623300d375c6ae85401cdd71aba135744a00e46666ae68cdc3a802a400846602460286ae854024dd71aba135744a01246666ae68cdc3a8032400446028602a6ae84d55cf280591999ab9a3370ea00e900011809980b1aba135573ca018464c6a604066ae7009008407c07807407006c0680640604d55cea80209aab9e5003135573ca00426aae7940044dd500090911111118038041109111111198030048041091111111802804091111110020911111100191091111111980100480411091111111980080480410009191919191999ab9a3370ea002900111998041bad35742a0086eb4d5d0a8019bad357426ae89400c8cccd5cd19b875002480008c028c02cd5d09aab9e5006232635301133573802a02402001e01c26aae75400c4d5d1280089aab9e5001137540024244600400644424466600200a0080064002464646666ae68cdc3a800a40044600c6eb8d5d09aab9e500323333573466e1d4009200023008375c6ae84d55cf280211931a980599ab9c00f00c00a009008135573aa00226ea80048488c00800c8488c00400c800444888c8c8cccd5cd19b8735573aa0049000119aa80598031aba150023005357426ae8940088c98d4c020cd5ce00600480380309aab9e5001137540029309000900088910919800801801089000a4903505431001123230010012233003300200200133322222253353004333573466e1c00920540060051006133573892010e77726f6e672072656465656d65720000512200212200120011

pycardano/backend/blockfrost.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ def genesis_param(self) -> GenesisParameters:
7878
@property
7979
def protocol_param(self) -> ProtocolParameters:
8080
if not self._protocol_param or self._check_epoch_and_update():
81-
params = self.api.epoch_latest_parameters(self.epoch)
81+
params = self.api.epoch_latest_parameters()
8282
self._protocol_param = ProtocolParameters(
8383
min_fee_constant=int(params.min_fee_b),
8484
min_fee_coefficient=int(params.min_fee_a),

0 commit comments

Comments
 (0)