{-# LANGUAGE BangPatterns        #-}
{-# LANGUAGE DataKinds           #-}
{-# LANGUAGE FlexibleContexts    #-}
{-# LANGUAGE NoImplicitPrelude   #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell     #-}
{-# LANGUAGE TypeApplications    #-}
{-# LANGUAGE TypeFamilies        #-}
{-# LANGUAGE TypeOperators       #-}

module PlutusExample.PlutusVersion1.Sum
  where

import Prelude hiding (($), (+), (-), (==))

import Cardano.Api.Shelley (PlutusScript (..), PlutusScriptV1)

import Codec.Serialise
import Data.ByteString.Lazy qualified as LBS
import Data.ByteString.Short qualified as SBS

import Plutus.Script.Utils.Typed qualified as Scripts
import Plutus.V1.Ledger.Api (ScriptContext)
import Plutus.V1.Ledger.Scripts qualified as Plutus
import PlutusTx qualified
import PlutusTx.Prelude hiding (Semigroup (..), unless, (.))


smartSum :: Integer -> Integer
smartSum :: Integer -> Integer
smartSum Integer
a = Integer -> Integer -> Integer
forall t. (Eq t, Num t, AdditiveGroup t) => t -> t -> t
loop Integer
a Integer
0
 where
  loop :: t -> t -> t
loop !t
n !t
acc = if t
nt -> t -> Bool
forall a. Eq a => a -> a -> Bool
==t
0
    then t
acc
    else t -> t -> t
loop (t
n t -> t -> t
forall a. AdditiveGroup a => a -> a -> a
- t
1) (t
n t -> t -> t
forall a. AdditiveSemigroup a => a -> a -> a
+ t
acc)

-- | The validation function
{-# INLINABLE validateSum #-}
validateSum :: Integer -> Integer -> ScriptContext -> Bool
validateSum :: Integer -> Integer -> ScriptContext -> Bool
validateSum Integer
n Integer
s ScriptContext
_ = Integer -> Integer -> Bool
isGoodSum Integer
n Integer
s

{-# INLINABLE isGoodSum #-}
isGoodSum :: Integer -> Integer -> Bool
isGoodSum :: Integer -> Integer -> Bool
isGoodSum Integer
n Integer
s = Integer -> Integer
smartSum Integer
n Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
s

validator :: Plutus.Validator
validator :: Validator
validator = CompiledCode (BuiltinData -> BuiltinData -> BuiltinData -> ())
-> Validator
Plutus.mkValidatorScript $$(PlutusTx.compile [|| wrap ||])
 where
     wrap :: BuiltinData -> BuiltinData -> BuiltinData -> ()
wrap = (Integer -> Integer -> ScriptContext -> Bool)
-> BuiltinData -> BuiltinData -> BuiltinData -> ()
forall sc d r.
(IsScriptContext sc, UnsafeFromData d, UnsafeFromData r) =>
(d -> r -> sc -> Bool)
-> BuiltinData -> BuiltinData -> BuiltinData -> ()
Scripts.mkUntypedValidator Integer -> Integer -> ScriptContext -> Bool
validateSum

script :: Plutus.Script
script :: Script
script = Validator -> Script
Plutus.unValidatorScript Validator
validator

sumScriptShortBs :: SBS.ShortByteString
sumScriptShortBs :: ShortByteString
sumScriptShortBs = ByteString -> ShortByteString
SBS.toShort (ByteString -> ShortByteString)
-> (ByteString -> ByteString) -> ByteString -> ShortByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
LBS.toStrict (ByteString -> ShortByteString) -> ByteString -> ShortByteString
forall a b. (a -> b) -> a -> b
$ Script -> ByteString
forall a. Serialise a => a -> ByteString
serialise Script
script

sumScript :: PlutusScript PlutusScriptV1
sumScript :: PlutusScript PlutusScriptV1
sumScript = ShortByteString -> PlutusScript PlutusScriptV1
forall lang. ShortByteString -> PlutusScript lang
PlutusScriptSerialised ShortByteString
sumScriptShortBs