Skip to content

Commit

Permalink
validators' boilerplate. (#14)
Browse files Browse the repository at this point in the history
* validators' boilerplate.

* redeemer and datum types.

* updated design with new names

* corrected minting policy
  • Loading branch information
franciscojoray authored Mar 22, 2024
1 parent bcd5fe2 commit d727845
Show file tree
Hide file tree
Showing 9 changed files with 104 additions and 91 deletions.
14 changes: 7 additions & 7 deletions onchain/docs/mvp-design/design.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,10 @@ Updates the `fuel` datum field of both the `ShipState` and `PelletState` UTxOs,
![gatherFuel diagram](img/gatherFuel.png)


### Collect Rewards:
### Mine Asteria:
Subtracts from the `AsteriaUTxO` at most `MAX_ASTERIA_MINING`% of the ada value, and pays that amount to the owner of the ship that reached Asteria, together with the min ada locked in the `ShipState` UTxO. The `ShipToken` is burnt.

![collect diagram](img/collect.png)
![mineAsteria diagram](img/mineAsteria.png)


### Quit Game:
Expand All @@ -107,19 +107,19 @@ Pays the min ada locked in the `ShipState` UTxO back to the ship owner and burns
### Asteria validator:
* Params: `AdminToken`.

#### *AddNewPlayer Redeemer*
#### *AddNewShip Redeemer*
* `AsteriaUTxO` output value equals input value plus the `SHIP_MINT_FEE`.
* `AdminToken` is in the input.
* datum doesn't change.

#### *Collect Redeemer*
#### *Mine Redeemer*
* `ShipToken` is present in some input.
* `AsteriaUTxO` output value has at most `MAX_ASTERIA_MINING`% adas less than input value.

### Pellet validator:
* Params: `AdminToken`.

#### *Gather Redeemer (includes gathering amount)*
#### *Provide Redeemer (includes gathering amount)*
* `ShipToken` is present in some input.
* the amount specified is not greater than the fuel available in the pellet.
* the amount specified is subtracted from the output `PelletState` fuel datum field, and the other fields remain unchanged.
Expand All @@ -139,15 +139,15 @@ Pays the min ada locked in the `ShipState` UTxO back to the ship owner and burns
* the output fuel datum field equals the input fuel minus the fuel required for the displacement.
* the distance advanced doesn't exceed the `MAX_SHIP_MOVEMENT_PER_TX`.

#### *Gather Redeemer (includes gathering amount)*
#### *GatherFuel Redeemer (includes gathering amount)*
* there is a single `ShipState` input.
* there is a single `ShipState` output.
* there is a `PelletState` input with the same x and y datum coordinates as the `ShipState` UTxO.
* the amount specified plus the fuel before charging does not exceed `MAX_SHIP_FUEL` capacity.
* the amount specified is added to the output `ShipState` fuel datum field, and the other fields remain unchanged.
* the `ShipState` output value is the same as the input.

#### *Collect Redeemer*
#### *MineAsteria Redeemer*
* there is a single `ShipState` input.
* `PilotToken` is present.
* `ShipState` position is (0,0).
Expand Down
Binary file modified onchain/docs/mvp-design/img/createShip.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified onchain/docs/mvp-design/img/gatherFuel.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
43 changes: 43 additions & 0 deletions onchain/src/lib/asteria/types.ak
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use aiken/transaction/value.{AssetName, PolicyId}

pub type ShipDatum {
fuel: Int,
pos_x: Int,
pos_y: Int,
shipyard_policy: PolicyId,
ship_token_name: AssetName,
pilot_token_name: AssetName,
}

pub type ShipRedeemer {
MoveShip { delta_x: Int, delta_y: Int }
GatherFuel { amount: Int }
MineAsteria
Quit
}

pub type PelletDatum {
fuel: Int,
pos_x: Int,
pos_y: Int,
shipyard_policy: PolicyId,
}

pub type PelletRedeemer {
Provide { amount: Int }
}

pub type AsteriaDatum {
ship_counter: Int,
shipyard_policy: PolicyId,
}

pub type AsteriaRedeemer {
AddNewShip
Mine
}

pub type ShipyardRedeemer {
Mint
Burn
}
13 changes: 13 additions & 0 deletions onchain/src/validators/asteria.ak
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use aiken/transaction.{ScriptContext}
use aiken/transaction/value.{AssetName, PolicyId}
use asteria/types.{AsteriaDatum, AsteriaRedeemer}

validator(_admin_token: (PolicyId, AssetName)) {
fn spend(
_datum: AsteriaDatum,
_redeemer: AsteriaRedeemer,
_ctx: ScriptContext,
) -> Bool {
True
}
}
13 changes: 13 additions & 0 deletions onchain/src/validators/pellet.ak
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use aiken/transaction.{ScriptContext}
use aiken/transaction/value.{AssetName, PolicyId}
use asteria/types.{PelletDatum, PelletRedeemer}

validator(_admin_token: (PolicyId, AssetName)) {
fn spend(
_datum: PelletDatum,
_redeemer: PelletRedeemer,
_ctx: ScriptContext,
) -> Bool {
True
}
}
12 changes: 12 additions & 0 deletions onchain/src/validators/shipyard.ak
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use aiken/transaction.{ScriptContext}
use aiken/transaction/credential.{Address}
use asteria/types.{ShipyardRedeemer}

validator(
_asteria_validator_address: Address,
_spacetime_validator_address: Address,
) {
fn mint(_redeemer: ShipyardRedeemer, _ctx: ScriptContext) -> Bool {
True
}
}
100 changes: 16 additions & 84 deletions onchain/src/validators/spacetime.ak
Original file line number Diff line number Diff line change
@@ -1,86 +1,18 @@
use aiken/list
use aiken/math
use aiken/transaction.{InlineDatum, ScriptContext, Spend, Transaction}
use aiken/transaction/value.{PolicyId, quantity_of}

type Datum {
pilot_token: ByteArray,
pos_x: Int,
pos_y: Int,
fuel: Int,
}

type MoveRedeemer {
delta_x: Int,
delta_y: Int,
}

type GatherRedeemer {GatherRedeemer}

type PotRedeemer {PotRedeemer}

fn required_fuel(distance: Int, fuel_per_step: Int) -> Int {
distance * fuel_per_step
}

fn distance(delta_x: Int, delta_y: Int) -> Int {
math.abs(delta_x) + math.abs(delta_y)
}

// we need to enforce:
// [x] that the speed (manhattan_distance/slot) doesn't exceed an upper bound
// [ ] that the ship has enough fuel (token) to move the desired delta
// [ ] that the new position of the ship utxo equals the last position + delta
// [ ] that the fuel required for the delta has been burned
// [ ] that the tx is signed by the owner of the ship (token holder)

validator(ship_policy_id: PolicyId, max_speed: Int, fuel_per_step: Int) {
fn spend(datum: Datum, redeemer: Redeemer, ctx: ScriptContext) -> Bool {
let Redeemer { delta_x, delta_y } = redeemer

let Datum { ship_id, pos_x, pos_y, fuel } = datum

let ScriptContext { transaction, purpose } = ctx

let Transaction { inputs, outputs, .. } = transaction

expect Spend(utxo_ref) = purpose

expect Some(own_input) =
list.find(inputs, fn(input) { input.output_reference == utxo_ref })

expect Some(own_output) =
list.find(
outputs,
fn(output) { quantity_of(output.value, ship_policy_id, ship_id) == 1 },
)

let must_hold_ship_asset =
quantity_of(own_input.output.value, ship_policy_id, ship_id) == 1

let distance = distance(delta_x, delta_y)
let required_fuel = required_fuel(distance, fuel_per_step)

// speed = distance since we consider each block the unit of time
let must_respect_max_speed = distance <= max_speed

let must_have_enough_fuel = fuel >= required_fuel

expect InlineDatum(out_data) = own_output.datum

expect out_data: Datum = out_data

let final_pos_must_respect_movement =
out_data.pos_x == pos_x + delta_x && out_data.pos_y == pos_y + delta_y

let final_ship_id_must_match = out_data.ship_id == ship_id

and {
must_hold_ship_asset,
must_respect_max_speed,
must_have_enough_fuel,
final_pos_must_respect_movement,
final_ship_id_must_match,
}
use aiken/transaction.{ScriptContext}
use aiken/transaction/credential.{Address}
use aiken/transaction/value.{AssetName, PolicyId}
use asteria/types.{ShipDatum, ShipRedeemer}

validator(
_pellet_validator_address: Address,
_asteria_validator_address: Address,
_admin_token: (PolicyId, AssetName),
) {
fn spend(
_datum: ShipDatum,
_redeemer: ShipRedeemer,
_ctx: ScriptContext,
) -> Bool {
True
}
}

0 comments on commit d727845

Please sign in to comment.