This section contains a few selected, advanced use cases of OpShin.
OpShin supports the command-line flag
--constant-folding or short
With this flag, every expression is evaluated at compile time
by the python
On one hand this enables the precomputation of expensive constants in your code.
Specifically it evaluates all expressions that invoke only constants or variables that are
declared exactly once in the contract.
0 == 1 # evaluates to False @dataclass class A(PlutusData): a: int b: bytes A(0, b"") # evaluates to the object def foo(x): return x foo(0) # evaluates to 0 bar = 2 bar = 1 bar + 1 # is not evaluated at compile time
By setting the flag
--force-three-params you can enable the contract to act
with any script purpose (i.e. minting, spending, certification and withdrawal).
When a script invoked with a minting, certificaton or withdrawal purpose,
the validator function is called such that the first parameter of the contract (the datum)
is set to
Nothing() (a PlutusData object with no fields and constructor id 6).
Therefore, the compiler enforces a union type that includes
Nothing as an
option when using the three parameter force flag.
An example of a script that acts as both minting and spending validator can be found
wrapped_token example script.
OpShin never checks that an object adheres to the structure that is declared for its parameters.
The simple reason is that this is costly and usually not necessary.
Most of the time an equality comparison (
==) between PlutusData objects
is sufficient (and fast).
There are cases where you want to ensure the integrity of a datum however.
For example in an AMM setting where the pool datum will be re-used and potentially re-written
in subsequent calls.
In order to prevent malicious actors from making the datum too big to fit in subsequent transactions
or to prevent them from writing values of invalid types into the object, you may use
An example use case is found below. This contract will fail if anything but a PlutusData object with constructor id 2 and two fields, first integer and second bytes, is passed as a datum into the contract.
Note: Yes, this implies that without the explicit check the contract may pass with whatever type d is, since its field or constructor id are never explicitly accessed.
from opshin.prelude import * from opshin.std.integrity import check_integrity @dataclass class A(PlutusData) CONSTR_ID = 2 a: int b: bytes def validator(d: A, r: int, c: ScriptContext): check_integrity(d)