0

Question

What is the correct way to compare two instances of Value data type?

Context

I would like to check if outgoing transaction identified by PubKeyHash has the same Value as Value which was locked into smartcontract but I keep getting weird errors like so: Command failed: transaction submit Error: Error while submitting tx: ShelleyTxValidationError ShelleyBasedEraAlonzo (ApplyTxError [UtxowFailure (WrappedShelleyEraFailure (UtxoFailure (UtxosFailure (ValidationTagMismatch (IsValid True) (FailedUnexpectedly [PlutusFailure "\nThe 3 arg plutus script (PlutusScript PlutusV1 ScriptHash \"d13196be073516394395be6399e6895957d1a16c960d215d8b1d5e9f\") fails...

It seems to me as if working with Value data type crashes smartcontract.

I have tried creating SC with functions like:

data LockFundsDatum = LockFundsDatum
    { beneficiary :: !PubKeyHash
    } deriving Show

lockedValue :: Value
lockedValue = valueLockedBy info (ownHash ctx)

validate :: Bool
validate = elem lockedValue (pubKeyOutputsAt (beneficiary datum) info)

or

findTxFromThisSc :: Maybe TxOut
findTxFromThisSc = case findOwnInput ctx of
  Just txInInfo -> Just (txInInfoResolved txInInfo)
  Nothing       -> Nothing

getValuePaidToPkh :: Value
getValuePaidToPkh = valuePaidTo info (beneficiary dat)
  
valueOutInLovelaces :: Value -> Integer
valueOutInLovelaces v = valueOf v adaSymbol adaToken

validate :: Bool
validate = case findTxFromThisSc of
      Just txo -> traceIfFalse "Value paid to pkh owner isn't equal to 2000000" (valueOutInLovelaces getValuePaidToPkh == 2000000)
      Nothing -> traceIfFalse "Tx from this sc was not found" False

But contract fails everytime. I think it is because I'm trying to use default compare with Value while it is not allowed.

Fullcode

data LockFundsDatum = LockFundsDatum
    { beneficiary     :: !PubKeyHash
    , lockedTokensID  :: !CurrencySymbol
    , lockedTokenName :: !TokenName
    } deriving Show

{-# INLINABLE mkValidator #-}
mkValidator ::LockFundsDatum -> () -> ScriptContext -> Bool
mkValidator dat _ ctx = validate
  where
    info :: TxInfo
    info = scriptContextTxInfo ctx

    lockedValue :: Value
    lockedValue = valuePaidTo info (beneficiary dat)

    valueOutInteger :: Value -> Integer
    valueOutInteger v = valueOf v (lockedTokensID dat) (lockedTokenName dat)

    findTxFromThisSc :: Maybe TxOut
    findTxFromThisSc = case findOwnInput ctx of
      Just txInInfo -> Just (txInInfoResolved txInInfo)
      Nothing       -> Nothing

    lockedValue' :: Maybe Value
    lockedValue' = case findTxFromThisSc of
      Just txo -> Just $ txOutValue txo
      Nothing  -> Nothing

    test0 :: Bool
    test0 = case lockedValue' of
      Just v  -> valueOutInteger v == valueOutInteger lockedValue
      Nothing -> False

    test1 :: Bool
    test1 = case lockedValue' of
      Just v -> traceIfTrue "value of test1 is 10 true" $ valueOutInteger v == 10
      Nothing -> False

    test2 :: Bool
    test2 = traceIfFalse "value of test2 is 10 is false" $ valueOutInteger lockedValue == 10

    test3 :: Bool
    test3 = case lockedValue' of
      Just v -> traceIfFalse "values are not equal" $ v == lockedValue
      Nothing -> False

    validate :: Bool
    validate = traceIfFalse "Final test failed" test0 && test1 && test2 && test3

In case when there are 10 of my custom token locked, test0, test1 and test2 passes but SmartContract crashes on test3

6
  • Can you paste the whole validator, i.e. the function that takes 3 arguments and returns a Bool. Jan 28 at 13:56
  • Can you show your offline code? Concretely, the give contract.
    – kindofdev
    Jan 30 at 13:17
  • @SjoerdVisscher Added full code which compiles and works fine without test3. @kinofdev I'm not using any off-chain code, just plain cardano-cli transactions which work except with test3 case which I just added
    – KugisMugis
    Jan 31 at 15:37
  • 1
    Are you using == from PlutusTx.Prelude or Prelude (Haskell) ?
    – kindofdev
    Feb 9 at 16:59
  • Good question. I don't know. How could I check?
    – KugisMugis
    Feb 10 at 8:32

1 Answer 1

0

According to Ledger.Value

Value is an instance of Eq class so you should just be free to compare Value data types for equality. It is not an instance of Ord class however and you might need to do a custom comparison for your data types if you want ordering.

2
  • In my case when I go: haskell compareTwoValues :: Value -> Value -> Bool compareTwoValues v1 v2 = v1 == v2 This just crashes
    – KugisMugis
    Jan 31 at 15:28
  • This will work for normal inbuilt types such as bools or numbers. For custom types (and types that don't have a comparison operator) you have to define the comparison function.
    – KryptoKing
    Mar 2 at 17:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.