aiken_design_patterns/parameter_validation

In some cases, validators need to be aware of instances of a parameterized script in order to have a more robust control over the flow of assets.

As a simple example, consider a minting script that needs to ensure the destination of its tokens can only be instances of a specific spending script, e.g. parameterized by users’ wallets.

Since each different wallet leads to a different script address, without verifying instances, instances can only be seen as arbitrary scripts from the minting script’s point of view.

This can be resolved by validating an instance is the result of applying specific parameters to a given parameterized script.

To allow this validation on-chain, some restrictions are needed:

  1. Parameters of the script must have constant lengths, which can be achieved by having them hashed
  2. Consequently, for each transaction, the resolved value of those parameters must be provided through the redeemer
  3. The dependent script must be provided with CBOR bytes of instances before and after the parameter(s)
  4. Wrapping of instances’ logics in an outer function so that there’ll be single occurances of each parameter

This pattern provides two sets of functions. One for applying parameter(s) in the dependent script (i.e. the minting script in the example above), and one for wrapping your parameterized scripts with.

After defining your parameterized scripts, you’ll need to generate instances of them with dummy data in order to obtain the required prefix value for your target script to utilize. Note that your prefix should be from a single CBOR encoded result.

Types

Datatype for parameterized scripts that don’t need a redeemer.

Constructors

  • Parameter { param: p }

Constructors

  • Parameter2 { param_0: p, param_1: q }

Constructors

  • Parameter3 { param_0: p, param_1: q, param_2: s }

Datatype for redeemer of your single parameterized scripts.

Constructors

  • ParameterizedRedeemer { param: p, redeemer: r }

Constructors

  • ParameterizedRedeemer2 { param_0: p, param_1: q, redeemer: r }

Constructors

  • ParameterizedRedeemer3 { param_0: p, param_1: q, param_2: s, redeemer: r }

Functions

apply_param(version: Int, prefix: ByteArray, param: ByteArray) -> ScriptHash

Use this inside your contracts that depend on scripts with single parameters. The parameter must be serialised before getting passed here. It’ll be hashed with blake2b_224 before placement after prefix.

Note that your prefix should be from a single CBOR encoded result. And also, the version should either be 1, 2, or 3 depending on your script.

apply_prehashed_param(
  version: Int,
  prefix: ByteArray,
  param: ByteArray,
) -> ScriptHash

Similar to apply_param, but for scripts that their parameters don’t need to be resolved (e.g. have a script hash as their parameter).

Can be used for any hashing algorithms, i.e. the length of the provided hash does not matter (prefix covers it).

apply_param_2(
  version: Int,
  prefix: ByteArray,
  param_0: ByteArray,
  param_1: ByteArray,
) -> ScriptHash

Similar to apply_param, but for scripts with 2 parameters.

apply_prehashed_param_2(
  version: Int,
  prefix: ByteArray,
  param_0: ByteArray,
  param_1: ByteArray,
) -> ScriptHash

Similar to apply_prehashed_param, but for scripts with 2 parameters.

Note that while the first parameter (param_0) can still be of any length, blake2b_224 is the presumed hashing algorithm for the second parameter, i.e. the parameter is expected to be 28 bytes long.

apply_param_3(
  version: Int,
  prefix: ByteArray,
  param_0: ByteArray,
  param_1: ByteArray,
  param_2: ByteArray,
) -> ScriptHash

Similar to apply_param, but for scripts with 3 parameters.

apply_prehashed_param_3(
  version: Int,
  prefix: ByteArray,
  param_0: ByteArray,
  param_1: ByteArray,
  param_2: ByteArray,
) -> ScriptHash

Similar to apply_prehashed_param, but for scripts with 3 parameters.

Here again the first parameter can be of arbitrary length, while the other two must be 28 bytes long.

wrapper(
  hashed_parameter: Hash<Blake2b_224, p>,
  parameter_serialiser: fn(p) -> ByteArray,
  outer_redeemer: ParameterizedRedeemer<p, redeemer>,
  validator_function: fn(p, redeemer) -> Bool,
) -> Bool

Helper function for parameterized scripts, which takes care of validating resolved parameter hashes, provides you with both the parameter, and your custom redeemer.

wrapper_2(
  hashed_parameter_0: Hash<Blake2b_224, p>,
  hashed_parameter_1: Hash<Blake2b_224, q>,
  parameter_serialiser_0: fn(p) -> ByteArray,
  parameter_serialiser_1: fn(q) -> ByteArray,
  outer_redeemer: ParameterizedRedeemer2<p, q, r>,
  validator_function: fn(p, q, r) -> Bool,
) -> Bool

wrapper_3(
  hashed_parameter_0: Hash<Blake2b_224, p>,
  hashed_parameter_1: Hash<Blake2b_224, q>,
  hashed_parameter_2: Hash<Blake2b_224, s>,
  parameter_serialiser_0: fn(p) -> ByteArray,
  parameter_serialiser_1: fn(q) -> ByteArray,
  parameter_serialiser_2: fn(s) -> ByteArray,
  outer_redeemer: ParameterizedRedeemer3<p, q, s, r>,
  validator_function: fn(p, q, s, r) -> Bool,
) -> Bool

wrapper_no_redeemer(
  hashed_parameter: Hash<Blake2b_224, p>,
  parameter_serialiser: fn(p) -> ByteArray,
  outer_redeemer: Parameter<p>,
  validator_function: fn(p) -> Bool,
) -> Bool

Wrapper function for scripts with one parameter that don’t need a redeemer.

wrapper_no_redeemer_2(
  hashed_parameter_0: Hash<Blake2b_224, p>,
  hashed_parameter_1: Hash<Blake2b_224, q>,
  parameter_serialiser_0: fn(p) -> ByteArray,
  parameter_serialiser_1: fn(q) -> ByteArray,
  outer_redeemer: Parameter2<p, q>,
  validator_function: fn(p, q) -> Bool,
) -> Bool

wrapper_no_redeemer_3(
  hashed_parameter_0: Hash<Blake2b_224, p>,
  hashed_parameter_1: Hash<Blake2b_224, q>,
  hashed_parameter_2: Hash<Blake2b_224, q>,
  parameter_serialiser_0: fn(p) -> ByteArray,
  parameter_serialiser_1: fn(q) -> ByteArray,
  parameter_serialiser_2: fn(s) -> ByteArray,
  outer_redeemer: Parameter3<p, q, s>,
  validator_function: fn(p, q, s) -> Bool,
) -> Bool

Search Document