Skip to content

Latest commit

 

History

History
122 lines (91 loc) · 4.09 KB

SCRIPTS.md

File metadata and controls

122 lines (91 loc) · 4.09 KB

Writing Aiken Scripts With Naumachia

Check out the full code here Learn more about Aiken here

In order to use your Aiken script within your Naumachia contract you will need a few steps:

  1. Create your Aiken project
  2. Compile your empty project
  3. Load the script from file
  4. Write tests for your Scripts
  5. Implement and iterate...

Create Your Aiken Project

Follow the Aiken documentation to learn how to create an Aiken project.

For now, we are still just using the always succeeds script. Here is an example of that code:

validator {
    fn spend(_datum: Void, _redeemer: Void, _ctx) -> Bool {
        False 
    }
}

Compile the Script

Your Rust project root should include a build.rs file that will compile your Aiken script into a binary. Here is an example of that file:

const PROJECT: &str = "./always_succeeds";

fn main() {
    let mut project = Project::new(PROJECT.into(), Terminal::default())
        .expect(&format!("Project not found: {:?}", PROJECT));
    let build_result = project.build(false, Tracing::KeepTraces);

    if let Err(err) = build_result {
        err.iter().for_each(|e| e.report());
        panic!("🍂 Failed to build Aiken code 🍂");
    }
}

Where PROJECT is the path to your Aiken project.

Load the Script

Now that you have compiled your Aiken script, you can load it into your Naumachia contract. Here is an example of how to do that:

const BLUEPRINT: &str = include_str!("../../always_succeeds/plutus.json");
const VALIDATOR_NAME: &str = "always_true.spend";

pub fn get_script() -> ScriptResult<RawPlutusValidator<(), ()>> {
    let script_file: BlueprintFile = serde_json::from_str(BLUEPRINT)
        .map_err(|e| ScriptError::FailedToConstruct(e.to_string()))?;
    let validator_blueprint =
        script_file
            .get_validator(VALIDATOR_NAME)
            .ok_or(ScriptError::FailedToConstruct(format!(
                "Validator not listed in Blueprint: {:?}",
                VALIDATOR_NAME
            )))?;
    let raw_script_validator = RawPlutusValidator::from_blueprint(validator_blueprint)
        .map_err(|e| ScriptError::FailedToConstruct(e.to_string()))?;
    Ok(raw_script_validator)
}

Where BLUEPRINT is the path to your compiled Aiken Blueprint, and VALIDATOR_NAME is the name of the validator you want to use within the Blueprint file generated by Aiken.

Testing

Now that you have your script loaded, you can write tests for it. Here is an example of how to do that:

    #[test]
    fn test() {
        let script = get_script().unwrap();

        let owner = Address::from_bech32("addr_test1qpmtp5t0t5y6cqkaz7rfsyrx7mld77kpvksgkwm0p7en7qum7a589n30e80tclzrrnj8qr4qvzj6al0vpgtnmrkkksnqd8upj0").unwrap();

        let owner_pkh = pub_key_hash_from_address_if_available(&owner).unwrap();
        let ctx = ContextBuilder::new(owner_pkh).build_spend(&vec![], 0);
        script.execute((), (), ctx).unwrap();
    }

Since this validator always succeeds, there isn't a lot of testing to do.

The execute() method takes three parameters:

  1. The datum
  2. The redeemer
  3. The context

ContextBuilder

If you look at the above test, you can see that we are using a ContextBuilder to build our script context. All scripts take a context as its final parameter, and you can use the ContextBuilder to specifiy all the values in your context for doing a full range of tests. As of now, the builder is overly-expressive, in that it can define contexts that could never exist on chain. So expect improvements over time.

Writing Your Scripts

You may have noticed the script we included above would fail the test. We had the script always return False instead of True. Now that you have a failing test, you can go back and update your code:

validator {
    fn spend(_datum: Void, _redeemer: Void, _ctx) -> Bool {
         True
    }
}

The test should now pass! That's Test Driven Development! Feel free to use the testing framework how you see fit though :).

Next: Trireme