pycardano icon indicating copy to clipboard operation
pycardano copied to clipboard

Apply parameters on plutus scripts

Open mpizenberg opened this issue 8 months ago • 6 comments

Many plutus scripts are compiled first without all its parameters fixed. Then we can "apply parameters" to them to get their final form before using the scripts.

On most offchain frameworks, there is a function to do this.

  • lucid evo: https://github.com/Anastasia-Labs/lucid-evolution/blob/81c450f1773da6c6c283b959b027b93ccddcfd01/packages/uplc/src/node/uplc_tx.d.ts#L31
  • mesh: https://github.com/MeshJS/mesh/blob/fdf5fd4b0ff71c71cd1b855cc6c7de88225a9919/packages/mesh-core/src/core.ts#L13
  • elm-cardano: https://github.com/elm-cardano/elm-cardano/blob/97fa1f56da482ae7c6e580677f6807aee6db3fb9/src/Cardano/Uplc.elm#L142

It would be very useful if we had the capabilities to do that with pycardano. I’ve seen that opshin can do it, but opshin isn’t maintained up-to-date with the chain and doesn’t support PlutusV3 it seems.

mpizenberg avatar Apr 30 '25 02:04 mpizenberg

In case useful, the next version of Aiken will include this PR, which enables usage of aiken blueprint apply --in some/plutus.json ... outside of an aiken project. This is pretty convenient to call it with subprocess.run() in python with just the path to a blueprint json file instead of needing to be inside an aiken project directory. https://github.com/aiken-lang/aiken/pull/1163

mpizenberg avatar May 02 '25 09:05 mpizenberg

The Opshin repository contains a Plutus contract class that can load blueprints and apply parameters: https://github.com/OpShin/opshin/blob/56926395a799810bc3106d5fc3cba0f4c2a68790/opshin/builder.py#L146

It might make sense to merge this into pycardano if it is used more since it is independent of which language the contracts were written in.

nielstron avatar Jun 27 '25 05:06 nielstron

I'm interested in this too, but not confident enough with Plutus to try mixing OpShin and PyCardano code yet. Is the best thing for now to use aiken blueprint apply via subprocess?

jefdaj avatar Jul 30 '25 20:07 jefdaj

I would assume that yes, Aiken blueprint apply is the most stable tool currently

nielstron avatar Jul 30 '25 20:07 nielstron

Here's a hacky first attempt in case it helps someone. My use case involves applying a string and then an output reference. I'm not sure how to do the hex encodings in general yet.

from pycardano import *
from dataclass import dataclass
from typing import List
import tempfile
import subprocess

@dataclass
class OutputReferenceHack(PlutusData):
    CONSTR_ID = 0
    transaction_id: bytes
    index: int

def aiken_blueprint_apply_hex_params(plutus_json_path: str, hex_params: List[str]) -> dict:
    """
    Apply a list of hex-encoded parameters to a Plutus blueprint using `aiken blueprint apply`.

    :param plutus_json_path: Path to the initial plutus.json file
    :param hex_params: List of parameters to apply (as hex-encoded strings)
    :return: Fully parameterized blueprint as a dictionary

    **Example**::

        >>> desc = cbor2.dumps(b'my cool validator').hex()
        >>> oref = OutputReferenceHack(utxo.input.transaction_id.to_cbor(), utxo.input.index).to_cbor().hex()
        >>> blueprint = aiken_blueprint_apply_hex_params('./plutus.json', [desc, oref])
    """
    with tempfile.NamedTemporaryFile(mode='w+', delete=False, suffix='.json') as temp_out:
        temp_out_path = temp_out.name
        current_blueprint_path = plutus_json_path
        for hex_param in hex_params:
            cmd = [
                'aiken', 'blueprint', 'apply',
                '--in', current_blueprint_path,
                hex_param,
                '--out', temp_out_path
            ]
            result = subprocess.run(cmd, capture_output=True, text=True)
            if result.returncode != 0:
                err_msg = f"Blueprint application failed for parameter {hex_param}: {result.stderr}"
                raise RuntimeError(err_msg)
            current_blueprint_path = temp_out_path
        with open(current_blueprint_path, 'r') as f:
            final_blueprint = json.load(f)
        return final_blueprint

jefdaj avatar Jul 31 '25 18:07 jefdaj

It might make sense to merge this into pycardano if it is used more since it is independent of which language the contracts were written in.

Conceptually it makes sense, but it seems like we can't simply copy apply_parameter out of the box from opshin to pycardano because it would cause circular dependencies.

cffls avatar Aug 10 '25 17:08 cffls