-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
18 changed files
with
227 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Glossary | ||
|
||
- **Distance**: in the context of Asteria, the distance between two coordinates of a the grid is computed using [Manhattan distance](https://en.wikipedia.org/wiki/Taxicab_geometry). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"creating_ship": "Creating a Ship", | ||
"moving_ship": "Moving a Ship" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
|
||
# Creating a Ship | ||
|
||
Creates a `ShipState` UTxO locking min ada and a `ShipToken` (minted in this tx), specifying in the datum the initial `pos_x` and `pos_y` coordinates of the ship, and setting `fuel` to an initial amount. Also adds to the `AsteriaUTxO` value the `SHIP_MINT_FEE` paid by the user. | ||
|
||
![createShip diagram](/txs/createShip.png) | ||
|
||
## Lucid Example | ||
|
||
```ts | ||
import { fromText } from "https://deno.land/x/[email protected]/mod.ts"; | ||
import { AssetClassT } from "../types.ts"; | ||
import { createShip } from "../transactions/create-ship.ts"; | ||
|
||
const admin_token: AssetClassT = { | ||
policy: "0298aa99f95e2fe0a0132a6bb794261fb7e7b0d988215da2f2de2005", | ||
name: fromText("tokenA"), | ||
}; | ||
const ship_mint_lovelace_fee = 3000n; | ||
const initial_fuel = 15n; | ||
const pos_x = 20n; | ||
const pos_y = -13n; | ||
|
||
const txHash = await createShip( | ||
admin_token, | ||
ship_mint_lovelace_fee, | ||
initial_fuel, | ||
pos_x, | ||
pos_y | ||
); | ||
|
||
console.log(txHash); | ||
``` |
Empty file.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
|
||
# Moving a Ship | ||
|
||
Updates the `pos_x`, `pos_y` and `fuel` datum fields of the `ShipState` UTxO by adding the `delta_x` and `delta_y` values specified in the redeemer, and subtracting the fuel amount needed for the displacement. | ||
|
||
![moveShip diagram](/txs/moveShip.png) | ||
|
||
```ts | ||
import { | ||
Data, | ||
toUnit, | ||
TxHash, | ||
Constr, | ||
UTxO, | ||
} from "https://deno.land/x/[email protected]/mod.ts"; | ||
import { distance, lucidBase, required_fuel } from "../utils.ts"; | ||
import { ShipDatum, ShipDatumT } from "../types.ts"; | ||
|
||
// look up these values for the specific challenge you're particpating | ||
const FUEL_PER_STEP = 5; | ||
|
||
async function moveShip( | ||
fuel_per_step: bigint, | ||
delta_x: bigint, | ||
delta_y: bigint, | ||
ship_token_name: string, | ||
pilot_token_name: string, | ||
shipTxHash: TxHash | ||
): Promise<TxHash> { | ||
const lucid = await lucidBase(); | ||
|
||
const spacetimeRefTxHash: { txHash: string } = JSON.parse( | ||
await Deno.readTextFile("./spacetime-ref.json") | ||
); | ||
const spacetimeRef = await lucid.utxosByOutRef([ | ||
{ | ||
txHash: spacetimeRefTxHash.txHash, | ||
outputIndex: 0, | ||
}, | ||
]); | ||
const spacetimeValidator = spacetimeRef[0].scriptRef; | ||
if (!spacetimeValidator) { | ||
throw Error("Could not read spacetime validator from ref UTxO"); | ||
} | ||
const spacetimeAddressBech32 = | ||
lucid.utils.validatorToAddress(spacetimeValidator); | ||
|
||
const shipyardPolicyId = lucid.utils.mintingPolicyToId(spacetimeValidator); | ||
const shipTokenUnit = toUnit(shipyardPolicyId, ship_token_name); | ||
const pilotTokenUnit = toUnit(shipyardPolicyId, pilot_token_name); | ||
|
||
const ship: UTxO = ( | ||
await lucid.utxosByOutRef([ | ||
{ | ||
txHash: shipTxHash, | ||
outputIndex: 0, | ||
}, | ||
]) | ||
)[0]; | ||
if (!ship.datum) { | ||
throw Error("Ship datum not found"); | ||
} | ||
const shipAda = ship.assets.lovelace; | ||
|
||
const shipInputDatum = Data.from<ShipDatumT>( | ||
ship.datum as string, | ||
ShipDatum as unknown as ShipDatumT | ||
); | ||
|
||
const moved_distance = distance(delta_x, delta_y); | ||
const spent_fuel = required_fuel(moved_distance, fuel_per_step); | ||
const shipInfo = { | ||
fuel: shipInputDatum.fuel - spent_fuel, | ||
pos_x: shipInputDatum.pos_x + delta_x, | ||
pos_y: shipInputDatum.pos_y + delta_y, | ||
ship_token_name: shipInputDatum.ship_token_name, | ||
pilot_token_name: shipInputDatum.pilot_token_name, | ||
}; | ||
const shipOutputDatum = Data.to<ShipDatumT>( | ||
shipInfo, | ||
ShipDatum as unknown as ShipDatumT | ||
); | ||
|
||
const moveShipRedeemer = Data.to( | ||
new Constr(1, [new Constr(0, [delta_x, delta_y])]) | ||
); | ||
|
||
const tx = await lucid | ||
.newTx() | ||
.collectFrom([ship], moveShipRedeemer) | ||
.readFrom(spacetimeRef) | ||
.payToContract( | ||
spacetimeAddressBech32, | ||
{ inline: shipOutputDatum }, | ||
{ | ||
[shipTokenUnit]: BigInt(1), | ||
lovelace: shipAda, | ||
} | ||
) | ||
.payToAddress(await lucid.wallet.address(), { | ||
[pilotTokenUnit]: BigInt(1), | ||
}) | ||
.complete(); | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,26 +1,24 @@ | ||
|
||
# Asteria | ||
# Introduction | ||
|
||
A Cardano bot challenge to showcase the capabilities of the eUTxO model. | ||
Asteria is a Cardano bot challenge to showcase the capabilities of the eUTxO model. In particular, it's concurrency benefits. | ||
|
||
## Mechanics | ||
Developers participate by building their own bots (automated agents) that interact directly with the Cardano blockchain. Each bot can be defined as an off-chain process that controls particular UTxOs that are constrained by on-chain validators. | ||
|
||
In this bot challenge you compete by moving a ship (your bot) through a 2D grid. The ship that reaches the center is allowed to collect the rewards. | ||
Once the challenge has been layed out by the administrators, all following interactions and rewards are fully decentralized. There're no _admin keys_ to adjust any of the mechanics. | ||
|
||
Ships are implemented as UTxOs with a datum holding a pair of (x, y) coordinates that represent their position in the 2D grid. To move a ship, a transaction must consume the UTxO and create a new one with holding the new position. | ||
## Game Overview | ||
|
||
![grid](/introduction1.svg) | ||
- Your bot is in charge of controlling a (space) ship that moves in a 2D grid. | ||
- The goal is to reach coordinates (0, 0) allowing the rewards of the challenge to be claimed. | ||
- Your movement is constrained by a maximum speed and the availability of a fuel resource. | ||
- Fuel is freely available at fixed coordinates in the grid, ships can gather the fuel if their coordinates overlap. | ||
|
||
Movement of the ships is constrained by a _Space-Time_ on-chain script that limits their velocity. Strictly speaking, the max distance that a ship can move in any given transaction has a constant upper bound. Distances are defined using [Manhattan distance] to simplify the math. | ||
|
||
![move tx](/introduction2.svg) | ||
## Ongoing Challenges | ||
|
||
Movement of the ships is also constrained by a _fuel_ token that is required for any change in position. An specifc amount of _fuel_ is required per distance unit. The lack of the required fuel amount will block the movement of the ship. | ||
There might be any number of open challenges (games) ongoing at any point. Everything in Asteria is open-source, so you can even run your own challenge. | ||
|
||
![gather tx](/introduction3.svg) | ||
|
||
To accumulate fuel, ships must _gather_ these tokens which are distributed randomly across the same grid. To gather a fuel token, your ship needs to be in the same coordinates as the fuel. | ||
|
||
To create a ship, a participant must mint the corresponding NFT from the valid policy id. A minimum amount of ADA will be requried for the mint. This ADA used to mint the ships will be increment the rewards locked for the winner. The initial position of the ship is decided by the player but is contrainted to the external boundary of the grid. | ||
|
||
A unique UTxO will be place at the center of the grid to hold the rewards for the winner of the challenge. To claim rewards, a ship must be located at the center of the grid. Each claim is allowed to collect 1/2 of the total rewards. | ||
|Name|Network|Shipyard Policy| | ||
|--|--|--| | ||
|alpha|`preview`|`000000`| |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
# Components | ||
|
||
## Grid | ||
|
||
- the grid is a virtual space in 2 dimensions (`x`, `y`). | ||
- there's no on-chain representation of the grid | ||
- coordinates on each dimension are discrete (integer values) | ||
- the coordinates `(0, 0)` are considered the center of the grid | ||
|
||
## Ship | ||
|
||
- a ship is identified by a Cardano native asset token of a specific policy id. We call this class of token `ShipToken`. | ||
- the UTxO that holds the `ShipToken` defines the state of the ship. We call this class of UTxOs `ShipState`. | ||
- the datum of the `ShipState` UTxO contains information about current coordinates and available fuel. | ||
- all `ShipState` UTxOs belong to a script address that constraints changes that can be applies to the state. We call this script `SpaceTimeScript`. | ||
|
||
## Pilot | ||
|
||
- the pilot is a Cardano native token from a particular policy id that is locked in an address managed by the participant. We call this class of token `PilotToken`. | ||
- the goal of this token is to ensure that changes to the `ShipState` are triggered by the rightful owner of the ship. | ||
- the pilot token needs to be present in any of the inputs of a transaction that progresses the state of the ship. | ||
|
||
## Fuel Pellet | ||
|
||
- a fuel pellet is freely available source of fuel tokens that are located at a fixed position in the grid. | ||
- a fuel pellet is represented by a UTxO that contains any amount of `FuelToken` and is locked at a specific script address. We call this class of UTxO `PelletState` | ||
- the datum of a `PelletState` defines the position of the pellet within the _grid_. | ||
- the amount of fuel tokens in the `PelletState` represents the available fuel. | ||
|
||
## Asteria | ||
|
||
- Asteria is an asteroid located at the center of the grid that represents the end goal of the challenge. | ||
- Asteria is represented by an UTxO that called `AsteriaUtxo`. | ||
- This UTxO will hold the aggregated rewards of the challenge. | ||
- This UTxO holds a datum with a counter that controls a sequence used to enforce ship uniqueness. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# Gameplay | ||
|
||
## Building a ship | ||
|
||
- to create a ship, the participant has to mint a new `ShipToken` and matching `PilotToken` through a mint validator called `ShipyardPolicy`. | ||
- each Pilot / Ship token pair will be unique. The validator will ensure uniqueness by incrementing a "counter" datum locked in the `AsteriaUtxo`. | ||
- the asset name of the `ShipToken` and `PilotToken` will contain the counter value as a suffix. Eg: `SHIP23` and `PILOT23`. | ||
- the `ShipToken` needs to be locked in the `SpaceTimeScript` and the `PilotToken` needs to go to an address controlled by the participant. | ||
- the mint process will require locking an ADA payment adding to the reward pot. The amount of this payment is defined by our constant `SHIP_MINT_FEE`. | ||
|
||
## Moving your ship | ||
|
||
- movement of a ship through the grid is achieved by a transaction the consumes the `ShipState` UTxO and outputs a new one with the updated state. | ||
- the maximum _distance_ that can be achieved in a single transaction is constrained by the constant `MAX_SHIP_MOVEMENT_PER_TX`. | ||
- moving the ship will consume a quantity of fuel proportional to the distance. The ratio of fuel required per distance unit is defined by the constant `FUEL_PER_DISTANCE_UNIT`. | ||
|
||
## Gathering fuel | ||
|
||
- gathering fuel is achieved by a transaction that consumes the `ShipUtxo` and a `PelletUtxo` and outputs a new `ShipUtxo` with increased fuel value. | ||
- to consume a fuel pellet, the position of the ship must overlap with the position of the pellet. | ||
- the total amount of fuel that ship has can't exceed the `MAX_SHIP_FUEL` parameter. | ||
- if the fuel pellet isn't totally consumed, a new `PelletUtxo` needs to be generated with the remaining of the fuel and maintaining the same location in the grid. | ||
|
||
## Mining Asteria | ||
|
||
- this action is achieved by a transaction that consumes the `ShipUtxo` and `AsteriaUtxo` and outputs a new one that extracts assets from the `AsteriaUtxo` into a wallet defined by the participant. | ||
- the amount of assets that can be extracted from the `AsteriaUtxo` must not exceed a percentage of the total available defined by the `MAX_ASTERIA_MINING`. | ||
- to execute this action, the `ShipUtxo` must be present at coordinates `(0, 0)`. |
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.
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.
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.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.