I would like to write a factory script that can initialize another parameterized script address by sending it an NFT. The factory validator gets the parameters of the target script as redeemer and has to check if the NFT is actually sent to correct script address. Testing this with EmulatorTrace gives me an error that lets me doubt if calculating/validating a parameterized address is possible on-chain.
Writing it in Plutus looks like this:
{-# INLINABLE validateCreate #-}
validateCreate :: Factory
-> [TargetParams] -- Datum: List of already created scripts
-> TargetParams -- Redeemer: parameters for new script to be created
-> ScriptContext
-> Bool
validateCreate factory existingScriptParams newScritpParam ctx =
someOtherValidationLogic &&
Constraints.checkTxConstraint ctx
(MustPayToOtherScript (Scripts.validatorHash $ targetInst newScritpParam)
calculateDatumLogic nftValue)
where
someOtherValidationLogic :: Bool
calculateDatumLogic :: TargetDatum
nftValue :: Value
With the targetInst function looking pretty standard:
{-# INLINABLE targetInst #-}
targetInst :: TargetParams -> Scripts.TypedValidator Target
targetInst p = Scripts.mkTypedValidator @Target
($$(PlutusTx.compile [|| mkTargetValidator ||])
`PlutusTx.applyCode` PlutusTx.liftCode p)
$$(PlutusTx.compile [|| wrap ||])
where
wrap = Scripts.wrapValidator @Integer @TargetAction
This loads in cabal repl
without problems. But when executing the EmulatorTrace, it yields the following error:
*** Exception: Error: Unsupported feature: Type constructor: GHC.Prim.ByteArray#
Context: Compiling definition of: Target.targetInst
Context: Compiling definition of: Factory.validateCreate
Context: Compiling definition of: Factory.mkFactoryValidator
Context: Compiling expr at "ProjectName-0.1.0.0-inplace:Offchain:(84,9)-(84,52)"
I do not know what is going on in the template Haskell of targetInst. It looks to me like the calculation of a script address with the parameters given in the redeemer is not possible in the on-chain validator.
This raises a couple of questions for me:
- Is it just a stupid mistake on my side?
- Is there another way to calculate or validate script addresses with parameters given at runtime?
- Would another architecture be better for what I am trying to accomplish? My goal is to separate different instances of my target script while ensuring that there is only one for each set of parameters.
I think this question is related to this one. But there were no helpful answers and I would like to give a more detailed description.
Thanks for your help.