forked from input-output-hk/plutus-pioneer-program
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathHomework1.hs
160 lines (142 loc) · 5.81 KB
/
Homework1.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
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
module Week05.Homework1 where
import Control.Monad hiding (fmap)
import Data.Aeson (ToJSON, FromJSON)
import Data.Default (Default (..))
import Data.Text (Text)
import Data.Void (Void)
import GHC.Generics (Generic)
import Plutus.Contract as Contract
import Plutus.Trace.Emulator as Emulator
import qualified PlutusTx
import PlutusTx.Prelude hiding (Semigroup(..), unless)
import Ledger hiding (mint, singleton)
import Ledger.Constraints as Constraints
import Ledger.TimeSlot
import qualified Ledger.Typed.Scripts as Scripts
import Ledger.Value as Value
import Playground.Contract (ToSchema)
import Playground.TH (mkKnownCurrencies, mkSchemaDefinitions)
import Playground.Types (KnownCurrency (..))
import Prelude (IO, Semigroup (..), Show (..), String, fromIntegral)
import Text.Printf (printf)
import Wallet.Emulator.Wallet
{-# INLINABLE mkPolicy #-}
-- This policy should only allow minting (or burning) of tokens if the owner of the specified PubKeyHash
-- has signed the transaction and if the specified deadline has not passed.
mkPolicy :: PubKeyHash -> POSIXTime -> () -> ScriptContext -> Bool
mkPolicy pkh deadline () ctx = traceIfFalse "not signed properly" checkSign &&
traceIfFalse "deadline reached" checkDeadline
where
info :: TxInfo
info = scriptContextTxInfo ctx
checkSign :: Bool
checkSign = txSignedBy info pkh
checkDeadline :: Bool
checkDeadline = to deadline `contains` txInfoValidRange info
policy :: PubKeyHash -> POSIXTime -> Scripts.MintingPolicy
policy pkh deadline = mkMintingPolicyScript $
$$(PlutusTx.compile [|| \pkh' deadline' -> Scripts.wrapMintingPolicy $ mkPolicy pkh' deadline' ||])
`PlutusTx.applyCode`
PlutusTx.liftCode pkh
`PlutusTx.applyCode`
PlutusTx.liftCode deadline
curSymbol :: PubKeyHash -> POSIXTime -> CurrencySymbol
curSymbol pkh deadline = scriptCurrencySymbol $ policy pkh deadline
data MintParams = MintParams
{ mpTokenName :: !TokenName
, mpDeadline :: !POSIXTime
, mpAmount :: !Integer
} deriving (Generic, ToJSON, FromJSON, ToSchema)
type SignedSchema = Endpoint "mint" MintParams
mint :: MintParams -> Contract w SignedSchema Text ()
mint mp = do
pkh <- pubKeyHash <$> Contract.ownPubKey
now <- Contract.currentTime
let deadline = mpDeadline mp
if now > deadline
then Contract.logError @String "deadline passed"
else do
let val = Value.singleton (curSymbol pkh deadline) (mpTokenName mp) (mpAmount mp)
lookups = Constraints.mintingPolicy $ policy pkh deadline
tx = Constraints.mustMintValue val <> Constraints.mustValidateIn (to $ deadline - fromIntegral (scSlotLength def))
-- tx = Constraints.mustMintValue val <> Constraints.mustValidateIn (to $ now + 5000)
-- tx = Constraints.mustMintValue val <> Constraints.mustValidateIn (to deadline)
ledgerTx <- submitTxConstraintsWith @Void lookups tx
void $ awaitTxConfirmed $ txId ledgerTx
Contract.logInfo @String $ printf "forged %s" (show val)
endpoints :: Contract () SignedSchema Text ()
endpoints = mint' >> endpoints
where
mint' = endpoint @"mint" >>= mint
mkSchemaDefinitions ''SignedSchema
mkKnownCurrencies []
test :: IO ()
test = runEmulatorTraceIO $ do
let tn = "ABC"
deadline = slotToBeginPOSIXTime def 10
h <- activateContractWallet (Wallet 1) endpoints
callEndpoint @"mint" h $ MintParams
{ mpTokenName = tn
, mpDeadline = deadline
, mpAmount = 555
}
void $ Emulator.waitNSlots 15
callEndpoint @"mint" h $ MintParams
{ mpTokenName = tn
, mpDeadline = deadline
, mpAmount = 555
}
void $ Emulator.waitNSlots 1
test2 :: IO ()
test2 = runEmulatorTraceIO $ do
let tn = "ABC"
let tn' = "DEF"
deadline = slotToBeginPOSIXTime def 10
h <- activateContractWallet (Wallet 1) endpoints
callEndpoint @"mint" h $ MintParams
{ mpTokenName = tn
, mpDeadline = deadline
, mpAmount = 555
}
void $ Emulator.waitNSlots 1
callEndpoint @"mint" h $ MintParams
{ mpTokenName = tn'
, mpDeadline = deadline
, mpAmount = 333
}
void $ Emulator.waitUntilSlot 15
callEndpoint @"mint" h $ MintParams
{ mpTokenName = tn
, mpDeadline = deadline
, mpAmount = 222
}
void $ Emulator.waitNSlots 1
test3 :: IO ()
test3 = runEmulatorTraceIO $ do
let tn = "ABC"
deadline1 = slotToBeginPOSIXTime def 10
deadline2 = slotToBeginPOSIXTime def 17
h <- activateContractWallet (Wallet 1) endpoints
callEndpoint @"mint" h $ MintParams
{ mpTokenName = tn
, mpDeadline = deadline1
, mpAmount = 555
}
void $ Emulator.waitUntilSlot 15
callEndpoint @"mint" h $ MintParams
{ mpTokenName = tn
, mpDeadline = deadline2
, mpAmount = 333
}
void $ Emulator.waitNSlots 1