5
5
import tempfile
6
6
import time
7
7
8
+ import cbor2
8
9
from retry import retry
9
10
10
11
from pycardano import *
11
12
12
13
13
- class TestMintNFT :
14
+ @retry (tries = 10 , delay = 6 )
15
+ def check_chain_context (chain_context ):
16
+ print (f"Current chain tip: { chain_context .last_block_slot } " )
17
+
18
+
19
+ class TestAll :
14
20
# Define chain context
15
21
NETWORK = Network .TESTNET
16
22
17
23
OGMIOS_WS = "ws://localhost:1337"
18
24
19
25
chain_context = OgmiosChainContext (OGMIOS_WS , Network .TESTNET )
20
26
21
- @retry (tries = 10 , delay = 6 )
22
- def check_ogmios (self ):
23
- print (f"Current chain tip: { self .chain_context .last_block_slot } " )
27
+ check_chain_context (chain_context )
24
28
25
- def test_mint (self ):
26
- self .check_ogmios ()
27
- chain_context = OgmiosChainContext (self .OGMIOS_WS , Network .TESTNET )
28
-
29
- payment_key_path = os .environ .get ("PAYMENT_KEY" )
30
- extended_key_path = os .environ .get ("EXTENDED_PAYMENT_KEY" )
31
- if not payment_key_path or not extended_key_path :
32
- raise Exception (
33
- "Cannot find payment key. Please specify environment variable PAYMENT_KEY and extended_key_path"
34
- )
35
- payment_skey = PaymentSigningKey .load (payment_key_path )
36
- payment_vkey = PaymentVerificationKey .from_signing_key (payment_skey )
37
- extended_payment_skey = PaymentExtendedSigningKey .load (extended_key_path )
38
- extended_payment_vkey = PaymentExtendedVerificationKey .from_signing_key (
39
- extended_payment_skey
29
+ payment_key_path = os .environ .get ("PAYMENT_KEY" )
30
+ extended_key_path = os .environ .get ("EXTENDED_PAYMENT_KEY" )
31
+ if not payment_key_path or not extended_key_path :
32
+ raise Exception (
33
+ "Cannot find payment key. Please specify environment variable PAYMENT_KEY and extended_key_path"
40
34
)
41
- address = Address (payment_vkey .hash (), network = self .NETWORK )
35
+ payment_skey = PaymentSigningKey .load (payment_key_path )
36
+ payment_vkey = PaymentVerificationKey .from_signing_key (payment_skey )
37
+ extended_payment_skey = PaymentExtendedSigningKey .load (extended_key_path )
38
+ extended_payment_vkey = PaymentExtendedVerificationKey .from_signing_key (
39
+ extended_payment_skey
40
+ )
41
+
42
+ @retry (tries = 2 , delay = 6 )
43
+ def test_mint (self ):
44
+ address = Address (self .payment_vkey .hash (), network = self .NETWORK )
42
45
43
46
# Load payment keys or create them if they don't exist
44
47
def load_or_create_key_pair (base_dir , base_name ):
@@ -74,10 +77,10 @@ def load_or_create_key_pair(base_dir, base_name):
74
77
pub_key_policy_1 = ScriptPubkey (policy_vkey .hash ())
75
78
76
79
# A policy that requires a signature from the extended payment key
77
- pub_key_policy_2 = ScriptPubkey (extended_payment_vkey .hash ())
80
+ pub_key_policy_2 = ScriptPubkey (self . extended_payment_vkey .hash ())
78
81
79
82
# A time policy that disallows token minting after 10000 seconds from last block
80
- must_before_slot = InvalidHereAfter (chain_context .last_block_slot + 10000 )
83
+ must_before_slot = InvalidHereAfter (self . chain_context .last_block_slot + 10000 )
81
84
82
85
# Combine two policies using ScriptAll policy
83
86
policy = ScriptAll ([pub_key_policy_1 , pub_key_policy_2 , must_before_slot ])
@@ -125,7 +128,7 @@ def load_or_create_key_pair(base_dir, base_name):
125
128
"""Build transaction"""
126
129
127
130
# Create a transaction builder
128
- builder = TransactionBuilder (chain_context )
131
+ builder = TransactionBuilder (self . chain_context )
129
132
130
133
# Add our own address as the input address
131
134
builder .add_input_address (address )
@@ -143,7 +146,7 @@ def load_or_create_key_pair(base_dir, base_name):
143
146
builder .auxiliary_data = auxiliary_data
144
147
145
148
# Calculate the minimum amount of lovelace that need to hold the NFT we are going to mint
146
- min_val = min_lovelace (Value (0 , my_nft ), chain_context )
149
+ min_val = min_lovelace (Value (0 , my_nft ), self . chain_context )
147
150
148
151
# Send the NFT to our own address
149
152
nft_output = TransactionOutput (address , Value (min_val , my_nft ))
@@ -154,19 +157,21 @@ def load_or_create_key_pair(base_dir, base_name):
154
157
155
158
"""Sign transaction and add witnesses"""
156
159
# Sign the transaction body hash using the payment signing key
157
- payment_signature = payment_skey .sign (tx_body .hash ())
160
+ payment_signature = self . payment_skey .sign (tx_body .hash ())
158
161
159
162
# Sign the transaction body hash using the extended payment signing key
160
- extended_payment_signature = extended_payment_skey .sign (tx_body .hash ())
163
+ extended_payment_signature = self . extended_payment_skey .sign (tx_body .hash ())
161
164
162
165
# Sign the transaction body hash using the policy signing key because we are minting new tokens
163
166
policy_signature = policy_skey .sign (tx_body .hash ())
164
167
165
168
# Add verification keys and their signatures to the witness set
166
169
vk_witnesses = [
167
- VerificationKeyWitness (payment_vkey , payment_signature ),
170
+ VerificationKeyWitness (self . payment_vkey , payment_signature ),
168
171
VerificationKeyWitness (policy_vkey , policy_signature ),
169
- VerificationKeyWitness (extended_payment_vkey , extended_payment_signature ),
172
+ VerificationKeyWitness (
173
+ self .extended_payment_vkey , extended_payment_signature
174
+ ),
170
175
]
171
176
172
177
# Create final signed transaction
@@ -185,11 +190,11 @@ def load_or_create_key_pair(base_dir, base_name):
185
190
186
191
# Submit signed transaction to the network
187
192
print ("############### Submitting transaction ###############" )
188
- chain_context .submit_tx (signed_tx .to_cbor ())
193
+ self . chain_context .submit_tx (signed_tx .to_cbor ())
189
194
190
195
time .sleep (3 )
191
196
192
- utxos = chain_context .utxos (str (address ))
197
+ utxos = self . chain_context .utxos (str (address ))
193
198
found_nft = False
194
199
195
200
for utxo in utxos :
@@ -207,7 +212,7 @@ def load_or_create_key_pair(base_dir, base_name):
207
212
),
208
213
)
209
214
210
- builder = TransactionBuilder (chain_context )
215
+ builder = TransactionBuilder (self . chain_context )
211
216
builder .add_input_address (address )
212
217
213
218
builder .add_output (nft_to_send )
@@ -216,11 +221,11 @@ def load_or_create_key_pair(base_dir, base_name):
216
221
217
222
"""Sign transaction and add witnesses"""
218
223
# Sign the transaction body hash using the payment signing key
219
- payment_signature = payment_skey .sign (tx_body .hash ())
224
+ payment_signature = self . payment_skey .sign (tx_body .hash ())
220
225
221
226
# Add verification keys and their signatures to the witness set
222
227
vk_witnesses = [
223
- VerificationKeyWitness (payment_vkey , payment_signature ),
228
+ VerificationKeyWitness (self . payment_vkey , payment_signature ),
224
229
]
225
230
226
231
# Create final signed transaction
@@ -236,11 +241,11 @@ def load_or_create_key_pair(base_dir, base_name):
236
241
237
242
# Submit signed transaction to the network
238
243
print ("############### Submitting transaction ###############" )
239
- chain_context .submit_tx (signed_tx .to_cbor ())
244
+ self . chain_context .submit_tx (signed_tx .to_cbor ())
240
245
241
246
time .sleep (3 )
242
247
243
- utxos = chain_context .utxos (str (address ))
248
+ utxos = self . chain_context .utxos (str (address ))
244
249
found_nft = False
245
250
246
251
for utxo in utxos :
@@ -249,3 +254,132 @@ def load_or_create_key_pair(base_dir, base_name):
249
254
found_nft = True
250
255
251
256
assert found_nft , f"Cannot find target NFT in address: { address } "
257
+
258
+ @retry (tries = 2 , delay = 6 )
259
+ def test_plutus (self ):
260
+
261
+ # ----------- Giver give ---------------
262
+
263
+ with open ("plutus_scripts/fortytwo.plutus" , "r" ) as f :
264
+ script_hex = f .read ()
265
+ forty_two_script = cbor2 .loads (bytes .fromhex (script_hex ))
266
+
267
+ script_hash = plutus_script_hash (forty_two_script )
268
+
269
+ script_address = Address (script_hash , network = self .NETWORK )
270
+
271
+ giver_address = Address (self .payment_vkey .hash (), network = self .NETWORK )
272
+
273
+ builder = TransactionBuilder (self .chain_context )
274
+ builder .add_input_address (giver_address )
275
+ datum = PlutusData () # A Unit type "()" in Haskell
276
+ builder .add_output (
277
+ TransactionOutput (script_address , 50000000 , datum_hash = datum_hash (datum ))
278
+ )
279
+
280
+ tx_body = builder .build (change_address = giver_address )
281
+ witness_set = builder .build_witness_set ()
282
+
283
+ payment_signature = self .payment_skey .sign (tx_body .hash ())
284
+
285
+ witness_set .vkey_witnesses = [
286
+ VerificationKeyWitness (self .payment_vkey , payment_signature ),
287
+ ]
288
+
289
+ signed_tx = Transaction (
290
+ tx_body ,
291
+ witness_set ,
292
+ )
293
+
294
+ print ("############### Transaction created ###############" )
295
+ print (signed_tx )
296
+ print (signed_tx .to_cbor ())
297
+ print ("############### Submitting transaction ###############" )
298
+ self .chain_context .submit_tx (signed_tx .to_cbor ())
299
+ time .sleep (3 )
300
+
301
+ # ----------- Fund taker a collateral UTxO ---------------
302
+
303
+ taker_address = Address (self .extended_payment_vkey .hash (), network = self .NETWORK )
304
+
305
+ builder = TransactionBuilder (self .chain_context )
306
+
307
+ builder .add_input_address (giver_address )
308
+ builder .add_output (TransactionOutput (taker_address , 5000000 ))
309
+
310
+ tx_body = builder .build (change_address = giver_address )
311
+ witness_set = builder .build_witness_set ()
312
+
313
+ payment_signature = self .payment_skey .sign (tx_body .hash ())
314
+
315
+ witness_set .vkey_witnesses = [
316
+ VerificationKeyWitness (self .payment_vkey , payment_signature ),
317
+ ]
318
+
319
+ signed_tx = Transaction (
320
+ tx_body ,
321
+ witness_set ,
322
+ )
323
+
324
+ print ("############### Transaction created ###############" )
325
+ print (signed_tx )
326
+ print (signed_tx .to_cbor ())
327
+ print ("############### Submitting transaction ###############" )
328
+ self .chain_context .submit_tx (signed_tx .to_cbor ())
329
+ time .sleep (3 )
330
+
331
+ # ----------- Taker take ---------------
332
+
333
+ redeemer = Redeemer (
334
+ RedeemerTag .SPEND , 42 , ExecutionUnits (mem = 10000000 , steps = 10000000000 )
335
+ )
336
+
337
+ utxo_to_spend = self .chain_context .utxos (str (script_address ))[0 ]
338
+
339
+ taker_address = Address (self .extended_payment_vkey .hash (), network = self .NETWORK )
340
+
341
+ builder = TransactionBuilder (self .chain_context )
342
+
343
+ builder .add_script_input (utxo_to_spend , forty_two_script , datum , redeemer )
344
+ take_output = TransactionOutput (taker_address , 25123456 )
345
+ builder .add_output (take_output )
346
+
347
+ non_nft_utxo = None
348
+ for utxo in self .chain_context .utxos (str (taker_address )):
349
+ if isinstance (utxo .output .amount , int ):
350
+ non_nft_utxo = utxo
351
+ break
352
+
353
+ builder .collaterals .append (non_nft_utxo )
354
+
355
+ tx_body = builder .build (change_address = taker_address )
356
+ witness_set = builder .build_witness_set ()
357
+
358
+ collateral_signature = self .extended_payment_skey .sign (tx_body .hash ())
359
+
360
+ witness_set .vkey_witnesses = [
361
+ VerificationKeyWitness (self .extended_payment_vkey , collateral_signature ),
362
+ ]
363
+
364
+ signed_tx = Transaction (
365
+ tx_body ,
366
+ witness_set ,
367
+ )
368
+
369
+ print ("############### Transaction created ###############" )
370
+ print (signed_tx )
371
+ print (signed_tx .to_cbor ())
372
+ print ("############### Submitting transaction ###############" )
373
+ self .chain_context .submit_tx (signed_tx .to_cbor ())
374
+
375
+ time .sleep (3 )
376
+
377
+ utxos = self .chain_context .utxos (str (taker_address ))
378
+ found = False
379
+
380
+ for utxo in utxos :
381
+ output = utxo .output
382
+ if output == take_output :
383
+ found = True
384
+
385
+ assert found , f"Cannot find target UTxO in address: { taker_address } "
0 commit comments