Skip to content

Commit

Permalink
15 implement shipyardpolicy (#23)
Browse files Browse the repository at this point in the history
* implemented shipyard policy.

* cleaned pellet code.

* fixed shipyard policy.

* renamed pellet tests.

* shipyard policy tests.

* burn tests.
  • Loading branch information
franciscojoray authored Apr 5, 2024
1 parent 2b5fd63 commit 7f6a4c3
Show file tree
Hide file tree
Showing 8 changed files with 588 additions and 64 deletions.
2 changes: 1 addition & 1 deletion onchain/docs/mvp-design/design.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ Pays the min ada locked in the `ShipState` UTxO back to the ship owner and burns
* no `ShipState` output.

### Ship minting policy or "ShipyardPolicy":
* Params: `SpaceTimeScript` validator address and Asteria validator address.
* Params: `SpaceTimeScript` validator address, Asteria validator address, ship's initial fuel and minimum initial distance from Asteria.

#### MINT:
* `AsteriaUTxO` is input.
Expand Down
4 changes: 2 additions & 2 deletions onchain/src/lib/asteria/types.ak
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,6 @@ pub type AsteriaRedeemer {
}

pub type ShipyardRedeemer {
Mint
Burn
MintShip
BurnShip
}
28 changes: 14 additions & 14 deletions onchain/src/lib/asteria/utils.ak
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
use aiken/bytearray.{length, take}
use aiken/dict.{keys}
use aiken/list.{any}
use aiken/transaction.{Input}
use aiken/transaction/value.{PolicyId, tokens}
use aiken/math
use aiken/transaction.{Output}
use aiken/transaction/value.{AssetName, PolicyId, tokens}

pub fn is_ship_token_input(
inputs: List<Input>,
shipyard_policy: PolicyId,
) -> Bool {
let ship_name = "SHIP"
any(
inputs,
fn(input) {
let token_names = keys(tokens(input.output.value, shipyard_policy))
any(token_names, fn(name) { take(name, length(ship_name)) == ship_name })
},
)
pub fn is_ship_token_in_utxo(utxo: Output, shipyard_policy: PolicyId) -> Bool {
let token_names = keys(tokens(utxo.value, shipyard_policy))
any(token_names, fn(name) { has_prefix("SHIP", name) })
}

pub fn has_prefix(prefix: ByteArray, name: AssetName) -> Bool {
take(name, length(prefix)) == prefix
}

pub fn distance(delta_x: Int, delta_y: Int) -> Int {
math.abs(delta_x) + math.abs(delta_y)
}
40 changes: 26 additions & 14 deletions onchain/src/plutus.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"plutusVersion": "v2",
"compiler": {
"name": "Aiken",
"version": "v1.0.24-alpha+982eff4"
"version": "v1.0.26-alpha+075668b"
},
"license": "Apache-2.0"
},
Expand All @@ -33,8 +33,8 @@
}
}
],
"compiledCode": "582801000032323223222253330064a229309b2b1919bb03004001300430050013758002ae695d0aba21",
"hash": "631aff3dfb3ee15c0a560797a3e575872b27afe17662be117974aa0a"
"compiledCode": "5898010000323232323232232232232253330084a229309b2b19299980399b874800000454ccc028c024dd50010a4c2c2a66600e66e1d20020011533300a300937540042930b0b18039baa00153330043370e900018029baa001132323232533300b300d002149858dd7180580098058011bad3009001300637540022c6466ec0c01c004c01cc020004dd6000ab9a5573aaae7955cfaba157441",
"hash": "27cbc8819bede902bc58445bb6fc3d8c91341d0f48f58b5ea7adb72e"
},
{
"title": "pellet.spend",
Expand All @@ -58,33 +58,45 @@
}
}
],
"compiledCode": "5903b00100003232323232323232322222323232533300a3232323232323232323232323232323232533301b3370e9001180d0030991919191919299981218138010991919191929998149816001099299981399b8748010c0980044c8c8c8c8c8c8c94ccc0b94ccc0b94ccc0b94ccc0b8010400c52808010a50100114a026464646600200203444a66606a00229404c8c94ccc0d0c8c8cc004004008894ccc0e800452809919299981c99b8f33371890001b8d48904534849500000248904534849500014a2266008008002607c0046eb8c0f0004c014c8c8c94ccc0dccdc3a4004002297adef6c60137566078606a004606a002660260020486eacc04cc0c8c04cc0c8008528899802002000981c801181b80098008009129998198008a5eb804cc0d0c0c4c0d4004cc008008c0d800452819baf0053374a9000198189ba8337020400446066605605266ebcc02cc0a8c02cc0a8030c02cc0a801ccdc39998041bab300a3029300a302900b375c601c60520506eb8c028c0a40a120023371203e03a6044002605a002604a0022c60566058605860480022c60540026600c014466e1cccc008dd5980218118009bae30083023022375c600860460449001111191919299981499b8748008004520001375a605c604e004604e00264a66605066e1d200200114c0103d87a8000132323300100100222533302e00114c103d87a8000132323232533302f3371e014004266e95200033033375000297ae0133006006003375a60600066eb8c0b8008c0c8008c0c0004dd5981698130011813000998020018011119198008008019129998148008a60103d87a8000132323232533302a3371e00e004266e9520003302e374c00297ae0133006006003375660560066eb8c0a4008c0b4008c0ac0048c09cc0a000458c094004cc0040208cdd79801980f0008021119198008008019129998128008a5eb804c8c94ccc090c0140084cc0a0008cc0100100044cc010010004c0a4008c09c0048c08c004c084004c06401858dd6180f800980f800980f0011bac301c0013014003301a001301a0023018001301000c375c602c002602c002602a00260280046eb4c048004c028020dd6980800098040028a4c26cac64a66601466e1d200000113232533300f3012002149858dd6980800098040028b18040021800802119299980499b87480000044c8c8c8c8c8c8c8c94ccc050c05c00852616375c602a002602a0046eb4c04c004c04c008dd6980880098088011bad300f0013007002163007001230053754002460066ea80055cd2ab9d5573caae7d5d02ba15745",
"hash": "58a25f995531669ea4fb67f420a94eb4c0e1575dc93e6663e5a7c274"
"compiledCode": "5903ab01000032323232323232223232322322533300932323232323232323253323301330013014375400a26464646464a666036603c0042646464646464a6660426048004264a66603e66e1d20043020375400226464a666042603c60446ea8c8cc004004048894ccc098004530103d87a800013232533302532323300100133002002325333028301630293754002297adef6c6013756605a60546ea8004cc034dd5980798149baa300f3029375400803644a66605600229404c94ccc0a4cdc7999b8c48000dc6a45045348495000375c605c00491104534849500014a2266006006002605c00244a666054002297ae013302b3028302c00133002002302d0011300c330290024bd70099802002000981500118140008991919299981219b8901b0191533302400315333024002100114a0294052819baf004300a33027375066e04060068c0a4c094dd501099baf300a30243754601460486ea802cc028c090dd500298079998031bab300930233754601260466ea8028dd7180698119baa020375c601260466ea808058c070004c090c084dd50008b18119812181218101baa0011630220013300700b2300b3330023756600a603e6ea8004dd71804980f9baa01c375c600a603e6ea8070888c94ccc07cc034c080dd50008a400026eb4c090c084dd500099299980f980698101baa00114c103d87a8000132330010013756604a60446ea8008894ccc090004530103d87a8000132323253330243371e00e6eb8c09400c4c02ccc0a0dd4000a5eb804cc014014008dd6981280118140011813000998020018011119198008008019129998108008a60103d87a8000132323253330213371e00c6eb8c08800c4c020cc094dd3000a5eb804cc014014008dd59811001181280118118009ba5480008c078c07c00458c070004cc0040188cdd79801980c9baa00100422323300100100322533301c00114bd7009919299980d980280109980f801198020020008998020020009810001180f0009180d000980c180a9baa005370e90010b1bac3016301730170023758602a00260226ea8c050008c04cc050004c03cdd50029bae3011301230123012002375a602000260186ea8020dd6980718059baa00314984d9594ccc01cc010c020dd500089919299980618078010a4c2c6eb4c034004c024dd50008b180080192999802980118031baa0011323232323232323253330103013002149858dd7180880098088011bad300f001300f002375a601a002601a0046eb4c02c004c01cdd50008b1b87480015cd2ab9d5573caae7d5d02ba157441",
"hash": "991579c92fe22adfa6a23a9e3b21f5c898fdde927f5fc27ee1f3a1da"
},
{
"title": "shipyard.mint",
"redeemer": {
"title": "_redeemer",
"title": "redeemer",
"schema": {
"$ref": "#/definitions/asteria~1types~1ShipyardRedeemer"
}
},
"parameters": [
{
"title": "_asteria_validator_address",
"title": "asteria_validator_address",
"schema": {
"$ref": "#/definitions/aiken~1transaction~1credential~1Address"
}
},
{
"title": "_spacetime_validator_address",
"title": "spacetime_validator_address",
"schema": {
"$ref": "#/definitions/aiken~1transaction~1credential~1Address"
}
},
{
"title": "initial_fuel",
"schema": {
"$ref": "#/definitions/Int"
}
},
{
"title": "min_distance",
"schema": {
"$ref": "#/definitions/Int"
}
}
],
"compiledCode": "5201000032222253330054a229309b2b2b9a01",
"hash": "6586e490115868362eb1a7305c802c314357f2ebc5887f8bc4833732"
"compiledCode": "59088b01000032323232323232322223223223232322533300c323232323232325333013300b3014375400c2646464646464646464a6466603a602a603c6ea80584c94ccc078c058c07cdd5000899299980f980198101baa00113232323232325333028302b0021325333026301d375a605000426464a666056605c004264a66605260406eb4c0ac0084c8c94ccc0b8c0c40084c94ccc0b0c040c0b4dd5000899191919191919191919191919191919191919192999820181219918008009129998228008a4000266e01200233002002304800102a15333040008153330400071533304000615333040005153330400041533304000315333040002100114a029405280a5014a029405280a5030363253330403037304137540022900009bad30453042375400264a666080606e60826ea8004530103d87a8000132330010013756608c60866ea8008894ccc114004530103d87a800013232325333045300e375c608c00626062660926ea00052f5c026600a00a0046eb4c118008c124008c11c004cc0a8dd5981318209baa01502c3371e6eb8c10cc110c110c110c110c110c100dd500900b18031bae30423043304330433043303f375402266e3cdd71820982118211821181f1baa0100293371206a6466e00c004dd69811981f1baa0103001375a6048607c6ea804094ccc0f0cdc4000a4000266e05200000110013370e6eb4c080c0f0dd500701b19b8f011330034890550494c4f540030043005375a603e60766ea8068c004cc009220104534849500030033004375a603c60746ea8064dc78091119b8a0020012373000246e64cc008dd4000a441003001001222533333303c00213232323232323300b0020013371491010128000025333039337100069007099b80483c80400c54ccc0e4cdc4001a410004266e00cdc0241002800690068b299981d800899b8a4881035b5d2900004133714911035b5f2000375c607466600e00266ec1300102415d00375266e292210129000042233760980103422c2000375266601001000466e28dd7181d8009bae303c001375860720046eb4c0dc004c8cdd81ba83037001374e60700026ea80084c94ccc0e40044cdc5245027b7d00002133714911037b5f2000375c607064646600200200644a66607800220062664466ec130103422c20003752666012012607800466e29221023a2000333009009303d002337146eb8c0f0004dd7181e800981f00099801001181f80099bb04c10342207d0037520046eac0084c94ccc0e40044cdc52441025b5d00002133714911035b5f2000375c607066600a00266ec1300102415d0037520044466ec1300103422c2000375266600c00c00466e28dd7181c8009bae303a001375800426600a6eb40080044c8c8cdc524410268270000132333001001337006e3400920013371491101270000322253330393371000490000800899191919980300319b8000548004cdc599b80002533303c33710004900a0a40c02903719b8b33700002a66607866e2000520141481805206e0043370c004901019b8300148080cdc70020011bae00222232330010010042253330390011004133003303b00133002002303c001223233001001003225333034302c00113371491101300000315333034337100029000099b8a489012d003300200233702900000089980299b8400148050cdc599b803370a002900a240c00066002002444a66606266e2400920001001133300300333708004900a19b8b3370066e14009201448180004c058004c0c4c0b8dd50008b180998169baa00116302f001323300100101922533302e00114bd7009919299981699baf3013302f375400405626606200466008008002266008008002606400460600022c6eb8c0a400458c0b0004cc0100408cc01922010550494c4f5400375c60500022c6eb8c09800458c0a4004cc0040348cc00d221045348495000375c604a00244646600200200644a666052002297adef6c60132325333028300500213302c00233004004001133004004001302d002302b001223371e666e312000371a004002004a666040603060426ea80044c8c8c8c94ccc09cc0a800852616375c605000260500046eb4c098004c088dd50008b181218109baa00116300630203754600a60406ea8c08cc080dd50008b19801007119baf300430203754600a60406ea80040744c94ccc078c058c07cdd5000899299980f980198101baa00113232325333025302800c153330223370e90009bad302400115333022301a375a601260486ea800c4c068dd6980518121baa00314a02c2c604c0166012002604860426ea800458c018c080dd5180298101baa3023302037540022c6600401c466ebcc010c080dd5180298101baa00101c370e90021119198008008019129998110008a60103d87a800013232533302130050021300d330250024bd7009980200200098130011812000918100009180f98100009180f180f980f8009299980c1808180c9baa00113232323232323232323232325333027302a002149858dd7181400098140011bae30260013026002375c604800260480046eb4c088004c088008dd6981000098100011bad301e001301a37540022c64a66602e601c60306ea800452f5bded8c026eacc070c064dd500099800991980080080291299980d8008a5eb7bdb1804c8c8c8c94ccc070cdc7a45000021003133020337606ea4008dd3000998030030019bab301d003375c6036004603e004603a00200644646600200200644a666038002298103d87a80001323232533301c3371e00c6eb8c07400c4c020cc080dd3000a5eb804cc014014008dd5980e8011810001180f0009ba548000dd7180c180a9baa006163756602e603060300046eb0c058004c058c058008dd6180a00098081baa301300230123013001300e375400229309b2b19299980598018008a99980718069baa00414985854ccc02cc00800454ccc038c034dd50020a4c2c2c60166ea800cdc3a40046e1d2000375a0026eb40055cd2ab9d5573caae7d5d02ba15744ae91",
"hash": "16dd8305a2af132cf9481d0aece85c006b73a7a7b046275c9639da95"
},
{
"title": "spacetime.spend",
Expand Down Expand Up @@ -120,8 +132,8 @@
}
}
],
"compiledCode": "58290100003232322223222253330084a229309b2b1919bb03006001300630070013758002ae695d0aba21",
"hash": "dbe87f98127efdba8e6c83f717f68c6b7e14e58569ed8a8f9584a3e0"
"compiledCode": "590112010000323232323232222322322322533300a4a229309b2b19299980499b87480000044c8c8c8c94ccc040c04800852616375a602000260200046eb4c038004c02cdd50010a99980499b87480080044c8c94ccc038c04000852616375a601c00260166ea800854ccc024cdc3a40080022a66601860166ea800852616153330093370e90030008a99980618059baa00214985858c024dd5000a99980319b8748000c01cdd50008991919191919191919191919299980a980b8010a4c2c6eb8c054004c054008dd7180980098098011bae30110013011002375a601e002601e0046eb4c034004c034008dd6980580098041baa0011632337606012002601260140026eb00055cd2ab9d5573caae7d5d0aba201",
"hash": "1e7937119c90ff4b7ca39a916afebf155d47a963a5f7ce39702ca280"
}
],
"definitions": {
Expand Down Expand Up @@ -432,13 +444,13 @@
"title": "ShipyardRedeemer",
"anyOf": [
{
"title": "Mint",
"title": "MintShip",
"dataType": "constructor",
"index": 0,
"fields": []
},
{
"title": "Burn",
"title": "BurnShip",
"dataType": "constructor",
"index": 1,
"fields": []
Expand Down
16 changes: 12 additions & 4 deletions onchain/src/validators/pellet.ak
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,24 @@ validator(admin_token: AssetClass) {
expect InlineDatum(out_datum) = own_output.datum
expect out_datum: PelletDatum = out_datum

expect Some(_) =
list.find(
inputs,
fn(input) { utils.is_ship_token_in_utxo(input.output, shipyard_policy) },
)

let has_enough_fuel = amount <= fuel
let own_input_has_admin_token =
quantity_of(own_input.output.value, admin_token.policy, admin_token.name) == 1
let value_not_changed = own_input.output.value == own_output.value
let datum_update_ok =
out_datum == PelletDatum { ..datum, fuel: fuel - amount }

has_enough_fuel && own_input_has_admin_token && value_not_changed && datum_update_ok && utils.is_ship_token_input(
inputs,
shipyard_policy,
)
and {
has_enough_fuel,
own_input_has_admin_token,
value_not_changed,
datum_update_ok,
}
}
}
103 changes: 97 additions & 6 deletions onchain/src/validators/shipyard.ak
Original file line number Diff line number Diff line change
@@ -1,12 +1,103 @@
use aiken/transaction.{ScriptContext}
use aiken/bytearray
use aiken/dict
use aiken/list
use aiken/string
use aiken/transaction.{InlineDatum, Mint, ScriptContext, Transaction}
use aiken/transaction/credential.{Address}
use asteria/types.{ShipyardRedeemer}
use aiken/transaction/value
use asteria/types.{AsteriaDatum,
BurnShip, MintShip, ShipDatum, ShipyardRedeemer}
use asteria/utils

validator(
_asteria_validator_address: Address,
_spacetime_validator_address: Address,
asteria_validator_address: Address,
spacetime_validator_address: Address,
initial_fuel: Int,
min_distance: Int,
) {
fn mint(_redeemer: ShipyardRedeemer, _ctx: ScriptContext) -> Bool {
True
pub fn mint(redeemer: ShipyardRedeemer, ctx: ScriptContext) -> Bool {
let ScriptContext { transaction, purpose } = ctx
let Transaction { inputs, outputs, mint, .. } = transaction
expect Mint(policy_id) = purpose
let minted_tokens =
mint
|> value.from_minted_value
|> value.tokens(policy_id)
|> dict.to_list()

when redeemer is {
MintShip -> {
expect Some(asteria_input) =
list.find(
inputs,
fn(input) { input.output.address == asteria_validator_address },
)
expect InlineDatum(asteria_datum) = asteria_input.output.datum
expect asteria_datum: AsteriaDatum = asteria_datum
expect [(ship_token_name, 1)] =
list.filter(
minted_tokens,
fn(token) { utils.has_prefix("SHIP", token.1st) },
)
expect [(pilot_token_name, 1)] =
list.filter(
minted_tokens,
fn(token) { utils.has_prefix("PILOT", token.1st) },
)

expect [ship_state] =
list.filter(
outputs,
fn(output) { output.address == spacetime_validator_address },
)
expect InlineDatum(ship_datum) = ship_state.datum
expect ship_datum: ShipDatum = ship_datum

let must_respect_ship_name =
ship_token_name == bytearray.concat(
"SHIP",
bytearray.from_string(string.from_int(asteria_datum.ship_counter)),
)
let must_respect_pilot_name =
pilot_token_name == bytearray.concat(
"PILOT",
bytearray.from_string(string.from_int(asteria_datum.ship_counter)),
)
let must_mint_two_assets = list.length(minted_tokens) == 2
let must_have_initial_fuel = ship_datum.fuel == initial_fuel
let must_respect_min_distance =
utils.distance(ship_datum.pos_x, ship_datum.pos_y) >= min_distance
let must_have_policy = ship_datum.shipyard_policy == policy_id
let must_have_ship_name = ship_datum.ship_token_name == ship_token_name
let must_have_pilot_name =
ship_datum.pilot_token_name == pilot_token_name
let must_hold_ship_token =
value.quantity_of(ship_state.value, policy_id, ship_token_name) == 1

and {
must_mint_two_assets,
must_respect_ship_name,
must_respect_pilot_name,
must_have_initial_fuel,
must_respect_min_distance,
must_have_policy,
must_have_ship_name,
must_have_pilot_name,
must_hold_ship_token,
}
}

BurnShip -> {
expect Some(ship_input) =
list.find(
inputs,
fn(input) { input.output.address == spacetime_validator_address },
)
expect InlineDatum(ship_datum) = ship_input.output.datum
expect ship_datum: ShipDatum = ship_datum
expect [(_, -1)] = minted_tokens
ship_datum.pos_x == 0 && ship_datum.pos_y == 0
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,10 @@ fn provide(options: ProvideTestOptions) -> Bool {
let value =
from_lovelace(2_000_000)
|> add(
options.shipyard_policy,
options.ship_token_name,
options.ship_token_amount,
)
options.shipyard_policy,
options.ship_token_name,
options.ship_token_amount,
)
Output { address, value, datum: NoDatum, reference_script: None }
}
let output_reference =
Expand Down Expand Up @@ -159,27 +159,27 @@ fn provide(options: ProvideTestOptions) -> Bool {
extra_signatories: [],
redeemers: dict.new()
|> dict.insert(
key: Spend(
OutputReference {
transaction_id: TransactionId { hash: transaction_id_1 },
output_index: 0,
},
),
value: {
let redeemer_data: Data = redeemer
redeemer_data
},
compare: test_utils.script_purpose_compare,
),
key: Spend(
OutputReference {
transaction_id: TransactionId { hash: transaction_id_1 },
output_index: 0,
},
),
value: {
let redeemer_data: Data = redeemer
redeemer_data
},
compare: test_utils.script_purpose_compare,
),
datums: dict.new()
|> dict.insert(
transaction_id_1,
{
let datum_data: Data = InlineDatum(datum_in)
datum_data
},
compare: bytearray.compare,
),
transaction_id_1,
{
let datum_data: Data = InlineDatum(datum_in)
datum_data
},
compare: bytearray.compare,
),
id: TransactionId { hash: transaction_id_1 },
}
let spend_ctx =
Expand Down
Loading

0 comments on commit 7f6a4c3

Please sign in to comment.