-
Notifications
You must be signed in to change notification settings - Fork 721
/
CertifyingAndWithdrawingPlutus.hs
704 lines (567 loc) · 27.6 KB
/
CertifyingAndWithdrawingPlutus.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
{-# LANGUAGE DisambiguateRecordFields #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
module Spec.Plutus.Direct.CertifyingAndWithdrawingPlutus
( hprop_plutus_certifying_withdrawing
) where
import Prelude
import Cardano.Api
import Cardano.Api.Shelley
import Control.Monad (void)
import qualified Data.Aeson as J
import qualified Data.Map.Strict as Map
import Data.Monoid (Last (..))
import Data.Set (Set)
import qualified Data.Set as Set
import qualified Data.Text as T
import GHC.Stack (callStack)
import qualified System.Directory as IO
import System.Environment (getEnvironment)
import System.FilePath ((</>))
import Cardano.CLI.Shelley.Output
import Cardano.CLI.Shelley.Run.Query
import Hedgehog (Property, (/==), (===))
import qualified Hedgehog as H
import qualified Hedgehog.Extras.Stock.IO.Network.Sprocket as IO
import qualified Hedgehog.Extras.Test.Base as H
import qualified Hedgehog.Extras.Test.Concurrent as H
import qualified Hedgehog.Extras.Test.File as H
import qualified Hedgehog.Extras.Test.Process as H
import qualified Test.Base as H
import qualified Test.Process as H
import Testnet.Cardano (TestnetOptions (..), TestnetRuntime (..), defaultTestnetOptions,
testnet)
import qualified Testnet.Cardano as TC
import qualified Testnet.Conf as H
import Testnet.Utils (waitUntilEpoch)
{-
The aim is to test a Plutus certifying and rewarding script. Certifying in the sense of validating a certifiate
e.g in this case a delegating certificate and rewarding in the sense of validating a rewards withdrawal.
In this test, we delegate a Plutus script staking address to our stake pool. We must:
1. Create a stake pool
2. Delegate our Plutus script address to said staking pool
3. Withdraw our rewards from our Plutus script staking address.
-}
hprop_plutus_certifying_withdrawing :: Property
hprop_plutus_certifying_withdrawing = H.integration . H.runFinallies . H.workspace "chairman" $ \tempAbsBasePath' -> do
projectBase <- H.note =<< H.noteIO . IO.canonicalizePath =<< H.getProjectBase
conf@H.Conf { H.tempBaseAbsPath, H.tempAbsPath } <- H.noteShowM $ H.mkConf tempAbsBasePath' Nothing
let fastTestnetOptions = defaultTestnetOptions
{ epochLength = 500
, slotLength = 0.01
, activeSlotsCoeff = 0.1
}
TC.TestnetRuntime { bftSprockets, testnetMagic } <- testnet fastTestnetOptions conf
env <- H.evalIO getEnvironment
execConfig <- H.noteShow H.ExecConfig
{ H.execConfigEnv = Last $ Just $
[ ("CARDANO_NODE_SOCKET_PATH", IO.sprocketArgumentName (head bftSprockets))
]
-- The environment must be passed onto child process on Windows in order to
-- successfully start that process.
<> env
, H.execConfigCwd = Last $ Just tempBaseAbsPath
}
-- First we note all the relevant files
base <- H.note projectBase
work <- H.note tempAbsPath
-- We get our UTxOs from here
utxoVKeyFile <- H.note $ tempAbsPath </> "shelley/utxo-keys/utxo1.vkey"
utxoSKeyFile <- H.note $ tempAbsPath </> "shelley/utxo-keys/utxo1.skey"
utxoVKeyFile2 <- H.note $ tempAbsPath </> "shelley/utxo-keys/utxo2.vkey"
utxoSKeyFile2 <- H.note $ tempAbsPath </> "shelley/utxo-keys/utxo2.skey"
utxoAddr <- H.execCli
[ "address", "build"
, "--testnet-magic", show @Int testnetMagic
, "--payment-verification-key-file", utxoVKeyFile
]
void $ H.execCli' execConfig
[ "query", "utxo"
, "--address", utxoAddr
, "--cardano-mode"
, "--testnet-magic", show @Int testnetMagic
, "--out-file", work </> "utxo-1.json"
]
H.cat $ work </> "utxo-1.json"
utxo1Json <- H.leftFailM . H.readJsonFile $ work </> "utxo-1.json"
UTxO utxo1 <- H.noteShowM $ H.jsonErrorFail $ J.fromJSON @(UTxO AlonzoEra) utxo1Json
txin <- H.noteShow $ head $ Map.keys utxo1
-- Staking keys
utxoStakingVkey2 <- H.note $ tempAbsPath </> "shelley/utxo-keys/utxo2-stake.vkey"
utxoStakingSkey2 <- H.note $ tempAbsPath </> "shelley/utxo-keys/utxo2-stake.skey"
utxoaddrwithstaking <- H.execCli [ "address", "build"
, "--payment-verification-key-file", utxoVKeyFile2
, "--stake-verification-key-file", utxoStakingVkey2
, "--testnet-magic", show @Int testnetMagic
]
utxostakingaddr <- filter (/= '\n')
<$> H.execCli
[ "stake-address", "build"
, "--stake-verification-key-file", utxoStakingVkey2
, "--testnet-magic", show @Int testnetMagic
]
-- Plutus related
plutusStakingScript <- H.note $ base </> "scripts/plutus/scripts/guess-42-stake.plutus"
plutusStakingScriptRedeemer <- H.note $ base </> "scripts/plutus/data/42.redeemer"
scriptPaymentAddressWithStaking <- H.execCli [ "address", "build"
, "--payment-verification-key-file", utxoVKeyFile
, "--stake-script-file", plutusStakingScript
, "--testnet-magic", show @Int testnetMagic
]
plutusStakingAddr <- filter (/= '\n') <$>
H.execCli [ "stake-address", "build"
, "--testnet-magic", show @Int testnetMagic
, "--stake-script-file", plutusStakingScript
]
-- Stake pool related
poolownerstakekey <- H.note $ tempAbsPath </> "addresses/pool-owner1-stake.vkey"
poolownerverkey <- H.note $ tempAbsPath </> "addresses/pool-owner1.vkey"
poolownerstakeaddr <- filter (/= '\n')
<$> H.execCli
[ "stake-address", "build"
, "--stake-verification-key-file", poolownerstakekey
, "--testnet-magic", show @Int testnetMagic
]
poolowneraddresswstakecred <- H.execCli [ "address", "build"
, "--payment-verification-key-file", poolownerverkey
, "--stake-verification-key-file", poolownerstakekey
, "--testnet-magic", show @Int testnetMagic
]
poolcoldVkey <- H.note $ tempAbsPath </> "node-pool1/shelley/operator.vkey"
poolcoldSkey <- H.note $ tempAbsPath </> "node-pool1/shelley/operator.skey"
stakePoolId <- filter ( /= '\n') <$>
H.execCli [ "stake-pool", "id"
, "--cold-verification-key-file", poolcoldVkey
]
-- REGISTER PLEDGER POOL
-- Create pledger registration certificate
void $ H.execCli
[ "stake-address", "registration-certificate"
, "--stake-verification-key-file", poolownerstakekey
, "--out-file", work </> "pledger.regcert"
]
void $ H.execCli' execConfig
[ "transaction", "build"
, "--alonzo-era"
, "--testnet-magic", show @Int testnetMagic
, "--change-address", utxoAddr
, "--tx-in", T.unpack $ renderTxIn txin
, "--tx-out", scriptPaymentAddressWithStaking <> "+" <> show @Int 5000000
, "--tx-out", poolowneraddresswstakecred <> "+" <> show @Int 5000000
, "--tx-out", utxoaddrwithstaking <> "+" <> show @Int 5000000
, "--witness-override", show @Int 3
, "--certificate-file", work </> "pledger.regcert"
, "--out-file", work </> "pledge-registration-cert.txbody"
]
void $ H.execCli
[ "transaction", "sign"
, "--tx-body-file", work </> "pledge-registration-cert.txbody"
, "--testnet-magic", show @Int testnetMagic
, "--signing-key-file", utxoSKeyFile
, "--out-file", work </> "pledge-registration-cert.tx"
]
H.note_ "Submitting pool owner/pledge stake registration cert and funding stake pool owner address..."
void $ H.execCli' execConfig
[ "transaction", "submit"
, "--tx-file", work </> "pledge-registration-cert.tx"
, "--testnet-magic", show @Int testnetMagic
]
-- Wait 5 seconds
H.threadDelay 10000000
-- Check to see if pledge's stake address was registered
void $ H.execCli' execConfig
[ "query", "stake-address-info"
, "--address", poolownerstakeaddr
, "--testnet-magic", show @Int testnetMagic
, "--out-file", work </> "pledgeownerregistration.json"
]
pledgerStakeInfo <- H.leftFailM . H.readJsonFile $ work </> "pledgeownerregistration.json"
delegsAndRewardsMap <- H.noteShowM $ H.jsonErrorFail $ J.fromJSON @DelegationsAndRewards pledgerStakeInfo
let delegsAndRewards = mergeDelegsAndRewards delegsAndRewardsMap
length delegsAndRewards === 1
let (pledgerSAddr, _rewards, _poolId) = head delegsAndRewards
-- Pledger and owner are and can be the same
T.unpack (serialiseAddress pledgerSAddr) === poolownerstakeaddr
H.note_ $ "Register staking key: " <> show utxoStakingVkey2
void $ H.execCli' execConfig
[ "query", "utxo"
, "--address", utxoaddrwithstaking
, "--cardano-mode"
, "--testnet-magic", show @Int testnetMagic
, "--out-file", work </> "utxo-addr-with-staking-1.json"
]
H.cat $ work </> "utxo-addr-with-staking-1.json"
utxoWithStaking1Json <- H.leftFailM . H.readJsonFile $ work </> "utxo-addr-with-staking-1.json"
UTxO utxoWithStaking1 <- H.noteShowM $ H.jsonErrorFail $ J.fromJSON @(UTxO AlonzoEra) utxoWithStaking1Json
txinForStakeReg <- H.noteShow $ head $ Map.keys utxoWithStaking1
void $ H.execCli [ "stake-address", "registration-certificate"
, "--stake-verification-key-file", utxoStakingVkey2
, "--out-file", work </> "stakekey.regcert"
]
void $ H.execCli' execConfig
[ "transaction", "build"
, "--alonzo-era"
, "--testnet-magic", show @Int testnetMagic
, "--change-address", utxoaddrwithstaking
, "--tx-in", T.unpack (renderTxIn txinForStakeReg)
, "--tx-out", utxoaddrwithstaking <> "+" <> show @Int 1000
, "--witness-override", show @Int 3
, "--certificate-file", work </> "stakekey.regcert"
, "--out-file", work </> "key-registration-cert.txbody"
]
void $ H.execCli [ "transaction", "sign"
, "--tx-body-file", work </> "key-registration-cert.txbody"
, "--testnet-magic", show @Int testnetMagic
, "--signing-key-file", utxoStakingSkey2
, "--signing-key-file", utxoSKeyFile2
, "--out-file", work </> "key-registration-cert.tx"
]
void $ H.execCli' execConfig
[ "transaction", "submit"
, "--tx-file", work </> "key-registration-cert.tx"
, "--testnet-magic", show @Int testnetMagic
]
H.note_ $ "Check to see if " <> utxoStakingVkey2 <> " was registered..."
H.threadDelay 10000000
void $ H.execCli' execConfig
[ "query", "stake-address-info"
, "--address", utxostakingaddr
, "--testnet-magic", show @Int testnetMagic
, "--out-file", work </> "stake-address-info-utxo-staking-vkey-2.json"
]
userStakeAddrInfoJSON <- H.leftFailM . H.readJsonFile $ work </> "stake-address-info-utxo-staking-vkey-2.json"
delegsAndRewardsMapUser <- H.noteShowM $ H.jsonErrorFail $ J.fromJSON @DelegationsAndRewards userStakeAddrInfoJSON
let delegsAndRewardsUser = mergeDelegsAndRewards delegsAndRewardsMapUser
userStakeAddrInfo = filter (\(sAddr,_,_) -> utxostakingaddr == T.unpack (serialiseAddress sAddr)) delegsAndRewardsUser
(userSAddr, _rewards, _poolId) = head userStakeAddrInfo
H.note_ $ "Check staking key: " <> show utxoStakingVkey2 <> " was registered"
T.unpack (serialiseAddress userSAddr) === utxostakingaddr
H.note_ "Get updated UTxO"
void $ H.execCli' execConfig
[ "query", "utxo"
, "--address", utxoAddr
, "--cardano-mode"
, "--testnet-magic", show @Int testnetMagic
, "--out-file", work </> "utxo-2.json"
]
H.cat $ work </> "utxo-2.json"
utxo2Json <- H.leftFailM . H.readJsonFile $ work </> "utxo-2.json"
UTxO utxo2 <- H.noteShowM $ H.jsonErrorFail $ J.fromJSON @(UTxO AlonzoEra) utxo2Json
txin2 <- H.noteShow $ head $ Map.keys utxo2
H.note_ "Create delegation certificate of pledger"
void $ H.execCli
[ "stake-address", "delegation-certificate"
, "--stake-verification-key-file", poolownerstakekey
, "--cold-verification-key-file", poolcoldVkey
, "--out-file", work </> "pledger.delegcert"
]
H.note_ "Register stake pool and delegate pledger to stake pool in a single tx"
void $ H.execCli' execConfig
[ "transaction", "build"
, "--alonzo-era"
, "--testnet-magic", show @Int testnetMagic
, "--change-address", utxoAddr
, "--tx-in", T.unpack $ renderTxIn txin2
, "--tx-out", scriptPaymentAddressWithStaking <> "+" <> show @Int 5000000
, "--tx-out", utxoAddr <> "+" <> show @Int 10000000
, "--witness-override", show @Int 3
, "--certificate-file", tempAbsPath </> "node-pool1/registration.cert"
, "--certificate-file", work </> "pledger.delegcert"
, "--out-file", work </> "register-stake-pool.txbody"
]
void $ H.execCli
[ "transaction", "sign"
, "--tx-body-file", work </> "register-stake-pool.txbody"
, "--testnet-magic", show @Int testnetMagic
, "--signing-key-file", utxoSKeyFile
, "--signing-key-file", poolcoldSkey
, "--signing-key-file", tempAbsPath </> "node-pool1/owner.skey"
, "--out-file", work </> "register-stake-pool.tx"
]
void $ H.execCli' execConfig
[ "transaction", "submit"
, "--tx-file", work </> "register-stake-pool.tx"
, "--testnet-magic", show @Int testnetMagic
]
H.threadDelay 10000000
void $ H.execCli' execConfig
[ "query", "stake-pools"
, "--testnet-magic", show @Int testnetMagic
, "--out-file", work </> "current-registered.pools.json"
]
currRegPools <- H.leftFailM . H.readJsonFile $ work </> "current-registered.pools.json"
poolIds <- H.noteShowM $ H.jsonErrorFail $ J.fromJSON @(Set PoolId) currRegPools
poolId <- H.noteShow $ head $ Set.toList poolIds
H.note_ "Check stake pool was successfully registered"
T.unpack (serialiseToBech32 poolId) === stakePoolId
H.note_ "Check pledge was successfully delegated"
void $ H.execCli' execConfig
[ "query", "stake-address-info"
, "--address", poolownerstakeaddr
, "--testnet-magic", show @Int testnetMagic
, "--out-file", work </> "pledge-stake-address-info.json"
]
pledgeStakeAddrInfoJSON <- H.leftFailM . H.readJsonFile $ work </> "pledge-stake-address-info.json"
delegsAndRewardsMapPledge <- H.noteShowM $ H.jsonErrorFail $ J.fromJSON @DelegationsAndRewards pledgeStakeAddrInfoJSON
let delegsAndRewardsPledge = mergeDelegsAndRewards delegsAndRewardsMapPledge
pledgeStakeAddrInfo = filter (\(sAddr,_,_) -> poolownerstakeaddr == T.unpack (serialiseAddress sAddr)) delegsAndRewardsPledge
(pledgeSAddr, _rewards, pledgerDelegPoolId) = head pledgeStakeAddrInfo
H.note_ "Check pledge has been delegated to pool"
case pledgerDelegPoolId of
Nothing -> H.failMessage callStack "Pledge was not delegated to pool"
Just pledgerDelagator -> T.unpack (serialiseToBech32 pledgerDelagator) === stakePoolId
T.unpack (serialiseAddress pledgeSAddr) === poolownerstakeaddr
H.note_ "We have a fully functioning stake pool at this point. We now want to test Plutus staking script withdrawals."
H.note_ "We now create the Plutus script staking registration certificate"
H.note_ "Get updated UTxO"
void $ H.execCli' execConfig
[ "query", "utxo"
, "--address", utxoAddr
, "--cardano-mode"
, "--testnet-magic", show @Int testnetMagic
, "--out-file", work </> "utxo-3.json"
]
H.cat $ work </> "utxo-3.json"
utxo3Json <- H.leftFailM . H.readJsonFile $ work </> "utxo-3.json"
UTxO utxo3 <- H.noteShowM $ H.jsonErrorFail $ J.fromJSON @(UTxO AlonzoEra) utxo3Json
txin3 <- H.noteShow . head $ Map.keys utxo3
void $ H.execCli
[ "stake-address", "registration-certificate"
, "--stake-script-file", plutusStakingScript
, "--out-file", work </> "script.regcert"
]
void $ H.execCli' execConfig
[ "transaction", "build"
, "--alonzo-era"
, "--testnet-magic", show @Int testnetMagic
, "--change-address", utxoAddr
, "--tx-in", T.unpack $ renderTxIn txin3
, "--tx-out", scriptPaymentAddressWithStaking <> "+" <> show @Int 5000000
, "--witness-override", show @Int 3
, "--certificate-file", work </> "script.regcert"
, "--out-file", work </> "register-plutus-staking-script.txbody"
]
void $ H.execCli
[ "transaction", "sign"
, "--tx-body-file", work </> "register-plutus-staking-script.txbody"
, "--testnet-magic", show @Int testnetMagic
, "--signing-key-file", utxoSKeyFile
, "--out-file", work </> "register-plutus-staking-script.tx"
]
void $ H.execCli' execConfig
[ "transaction", "submit"
, "--tx-file", work </> "register-plutus-staking-script.tx"
, "--testnet-magic", show @Int testnetMagic
]
H.threadDelay 10000000
H.note_ "Check if Plutus staking script address was registered"
void $ H.execCli' execConfig
[ "query", "stake-address-info"
, "--address", plutusStakingAddr
, "--testnet-magic", show @Int testnetMagic
, "--out-file", work </> "pledge-stake-address-info.json"
]
plutusStakeAddrInfoJSON <- H.leftFailM . H.readJsonFile $ work </> "pledge-stake-address-info.json"
delegsAndRewardsMapPlutus <- H.noteShowM $ H.jsonErrorFail $ J.fromJSON @DelegationsAndRewards plutusStakeAddrInfoJSON
let delegsAndRewardsPlutus = mergeDelegsAndRewards delegsAndRewardsMapPlutus
plutusStakeAddrInfo = filter (\(sAddr,_,_) -> plutusStakingAddr == T.unpack (serialiseAddress sAddr)) delegsAndRewardsPlutus
(plutusSAddr, _rewards, _poolId) = head plutusStakeAddrInfo
H.note_ "Check if Plutus staking script has been registered"
T.unpack (serialiseAddress plutusSAddr) === plutusStakingAddr
H.note_ "Create delegation certificate for Plutus staking script to stake pool"
void $ H.execCli
[ "stake-address", "delegation-certificate"
, "--stake-script-file", plutusStakingScript
, "--cold-verification-key-file", poolcoldVkey
, "--out-file", work </> "plutus-script.delegcert"
]
H.note_ "Get updated UTxO"
void $ H.execCli' execConfig
[ "query", "utxo"
, "--address", utxoAddr
, "--cardano-mode"
, "--testnet-magic", show @Int testnetMagic
, "--out-file", work </> "utxo-4.json"
]
H.cat $ work </> "utxo-4.json"
utxo4Json <- H.leftFailM . H.readJsonFile $ work </> "utxo-4.json"
UTxO utxo4 <- H.noteShowM $ H.jsonErrorFail $ J.fromJSON @(UTxO AlonzoEra) utxo4Json
txin4 <- H.noteShow . head $ Map.keys utxo4
txinCollateral1 <- H.noteShow $ Map.keys utxo4 !! 1
H.note_ "Delegate Plutus staking script to stake pool"
void $ H.execCli' execConfig
[ "query", "protocol-parameters"
, "--testnet-magic", show @Int testnetMagic
, "--out-file", work </> "pparams.json"
]
void $ H.execCli' execConfig
[ "transaction", "build"
, "--alonzo-era"
, "--testnet-magic", show @Int testnetMagic
, "--change-address", utxoAddr
, "--tx-in", T.unpack $ renderTxIn txin4
, "--tx-in-collateral", T.unpack $ renderTxIn txinCollateral1
, "--tx-out", scriptPaymentAddressWithStaking <> "+" <> show @Int 5000000
, "--witness-override", show @Int 3
, "--certificate-file", work </> "plutus-script.delegcert"
, "--certificate-script-file", plutusStakingScript
, "--certificate-redeemer-file", plutusStakingScriptRedeemer
, "--protocol-params-file", work </> "pparams.json"
, "--out-file", work </> "delegate-staking-script.txbody"
]
void $ H.execCli
[ "transaction", "sign"
, "--tx-body-file", work </> "delegate-staking-script.txbody"
, "--testnet-magic", show @Int testnetMagic
, "--signing-key-file", utxoSKeyFile
, "--out-file", work </> "delegate-staking-script.tx"
]
void $ H.execCli' execConfig
[ "transaction", "submit"
, "--tx-file", work </> "delegate-staking-script.tx"
, "--testnet-magic", show @Int testnetMagic
]
-- Wait 5 seconds
H.threadDelay 5000000
H.note_ "Check to see if staking script was delegated"
void $ H.execCli' execConfig
[ "query", "stake-address-info"
, "--address", plutusStakingAddr
, "--testnet-magic", show @Int testnetMagic
, "--out-file", work </> "plutus-staking-script-delegation.json"
]
stakingScriptAddrInfoJSON <- H.leftFailM . H.readJsonFile $ work </> "plutus-staking-script-delegation.json"
delegsAndRewardsMapStakingScript <- H.noteShowM $ H.jsonErrorFail $ J.fromJSON @DelegationsAndRewards stakingScriptAddrInfoJSON
let delegsAndRewardsStakingScript = mergeDelegsAndRewards delegsAndRewardsMapStakingScript
stakingScriptAddrInfo = filter (\(sAddr,_,_) -> plutusStakingAddr == T.unpack (serialiseAddress sAddr)) delegsAndRewardsStakingScript
(_stakingSAddr, _rewards, poolIdPlutusDeleg) = head stakingScriptAddrInfo
H.note_ $ "Check plutus staking script: " <> (work </> "plutus-staking-script-delegation.json") <> " was delegated"
case poolIdPlutusDeleg of
Nothing -> H.failMessage callStack "Plutus script was not delegated to stake pool"
Just plutusDelegPoolId ->
T.unpack (serialiseToBech32 plutusDelegPoolId) === stakePoolId
H.note_ "Checking plutus staking script has ada at its corresponding payment address"
void $ H.execCli' execConfig
[ "query", "utxo"
, "--address", scriptPaymentAddressWithStaking
, "--cardano-mode"
, "--testnet-magic", show @Int testnetMagic
, "--out-file", work </> "utxo-plutus-staking-payment-address.json"
]
H.cat $ work </> "utxo-plutus-staking-payment-address.json"
utxoPlutusPaymentAddrJson <- H.leftFailM . H.readJsonFile $ work </> "utxo-plutus-staking-payment-address.json"
UTxO utxoPlutus <- H.noteShowM $ H.jsonErrorFail $ J.fromJSON @(UTxO AlonzoEra) utxoPlutusPaymentAddrJson
utxoPlutus /== mempty
H.note_ "Wait for rewards to be paid out. This will be current epoch + 4"
void $ H.execCli' execConfig
[ "query", "tip"
, "--testnet-magic", show @Int testnetMagic
, "--out-file", work </> "current-tip.json"
]
tipJSON <- H.leftFailM . H.readJsonFile $ work </> "current-tip.json"
tip <- H.noteShowM $ H.jsonErrorFail $ J.fromJSON @QueryTipLocalStateOutput tipJSON
currEpoch <-
case mEpoch tip of
Nothing ->
H.failMessage callStack "cardano-cli query tip returned Nothing for EpochNo"
Just currEpoch -> return currEpoch
let rewardsEpoch = currEpoch + 4
waitedEpoch <- waitUntilEpoch
(work </> "current-tip.json")
testnetMagic
execConfig
rewardsEpoch
H.note_ "Check we have reached 4 epochs ahead"
waitedEpoch === rewardsEpoch
void $ H.execCli' execConfig
[ "query", "tip"
, "--testnet-magic", show @Int testnetMagic
, "--out-file", work </> "current-tip-2.json"
]
tip2JSON <- H.leftFailM . H.readJsonFile $ work </> "current-tip-2.json"
tip2 <- H.noteShowM $ H.jsonErrorFail $ J.fromJSON @QueryTipLocalStateOutput tip2JSON
currEpoch2 <-
case mEpoch tip2 of
Nothing ->
H.failMessage callStack "cardano-cli query tip returned Nothing for EpochNo"
Just currEpoch2 -> return currEpoch2
H.note_ $ "Current Epoch: " <> show currEpoch2
H.note_ "Check rewards have been distributed to Plutus script staking address"
void$ H.execCli' execConfig
[ "query", "ledger-state"
, "--testnet-magic", show @Int testnetMagic
, "--out-file", work </> "ledger-state.json"
]
void $ H.execCli' execConfig
[ "query", "stake-address-info"
, "--address", plutusStakingAddr
, "--testnet-magic", show @Int testnetMagic
, "--out-file", work </> "plutus-staking-script-delegation-rewards.json"
]
stakingRewardsJSON <- H.leftFailM . H.readJsonFile $ work </> "plutus-staking-script-delegation-rewards.json"
delegsAndRewardsMapScriptRewards <- H.noteShowM $ H.jsonErrorFail $ J.fromJSON @DelegationsAndRewards stakingRewardsJSON
let delegsAndRewardsScriptRewards = mergeDelegsAndRewards delegsAndRewardsMapScriptRewards
stakingScriptRewardsAddrInfo = filter (\(sAddr,_,_) -> plutusStakingAddr == T.unpack (serialiseAddress sAddr)) delegsAndRewardsScriptRewards
(_, scriptRewards, _) = head stakingScriptRewardsAddrInfo
pr@(Lovelace plutusRewards) <-
case scriptRewards of
Nothing -> H.failMessage callStack "Plutus staking script has no rewards"
Just rwds -> H.assert (rwds > 0) >> return rwds
H.note_ $ "We now withdraw the rewards from our Plutus staking address: " <> show @Integer plutusRewards
H.note_ "Get updated UTxO"
void $ H.execCli' execConfig
[ "query", "utxo"
, "--address", utxoAddr
, "--cardano-mode"
, "--testnet-magic", show @Int testnetMagic
, "--out-file", work </> "utxo-5.json"
]
H.cat $ work </> "utxo-5.json"
utxo5Json <- H.leftFailM . H.readJsonFile $ work </> "utxo-5.json"
UTxO utxo5 <- H.noteShowM $ H.jsonErrorFail $ J.fromJSON @(UTxO AlonzoEra) utxo5Json
txin5 <- H.noteShow . head $ Map.keys utxo5
txinCollateral2 <- H.noteShow $ Map.keys utxo5 !! 1
void $ H.execCli' execConfig
[ "transaction", "build"
, "--alonzo-era"
, "--testnet-magic", show @Int testnetMagic
, "--change-address", utxoAddr
, "--tx-in", T.unpack $ renderTxIn txin5
, "--tx-in-collateral", T.unpack $ renderTxIn txinCollateral2
, "--tx-out", scriptPaymentAddressWithStaking <> "+" <> show @Integer plutusRewards
, "--withdrawal", plutusStakingAddr <> "+" <> show @Integer plutusRewards
, "--withdrawal-script-file", plutusStakingScript
, "--withdrawal-redeemer-file", plutusStakingScriptRedeemer
, "--protocol-params-file", work </> "pparams.json"
, "--out-file", work </> "staking-script-withdrawal.txbody"
]
void $ H.execCli
[ "transaction", "sign"
, "--tx-body-file", work </> "staking-script-withdrawal.txbody"
, "--testnet-magic", show @Int testnetMagic
, "--signing-key-file", utxoSKeyFile
, "--out-file", work </> "staking-script-withdrawal.tx"
]
void $ H.execCli' execConfig
[ "transaction", "submit"
, "--tx-file", work </> "staking-script-withdrawal.tx"
, "--testnet-magic", show @Int testnetMagic
]
H.threadDelay 1000000
H.note_ "Check UTxO at script staking address to see if withdrawal was successful"
void $ H.execCli' execConfig
[ "query", "utxo"
, "--address", scriptPaymentAddressWithStaking
, "--cardano-mode"
, "--testnet-magic", show @Int testnetMagic
, "--out-file", work </> "utxo-plutus-staking-payment-address-2.json"
]
H.cat $ work </> "utxo-plutus-staking-payment-address-2.json"
utxoPlutusPaymentAddrJson2 <- H.leftFailM . H.readJsonFile $ work </> "utxo-plutus-staking-payment-address-2.json"
UTxO utxoPlutus2 <- H.noteShowM $ H.jsonErrorFail $ J.fromJSON @(UTxO AlonzoEra) utxoPlutusPaymentAddrJson2
-- Get total lovelace at plutus script address
let lovelaceAtPlutusAddr = mconcat . map (\(TxOut _ v _) -> txOutValueToLovelace v) $ Map.elems utxoPlutus2
H.note_ "Check that the withdrawal from the Plutus staking address was successful"
lovelaceAtPlutusAddr === pr + 5000000 + 5000000 + 5000000 + 5000000