This project includes the following:
.
├── contract
│ ├── offChain
│ └── onChain
├── docs
├── webapp
│ └── components
│ └── pages
│ └── prisma
│ └── oura
└── README.mdThe contract folder contains the onChain and offChain code written in Aiken and Lucid. Next, the docs folder provides documentation on the architecture, design, and contract endpoints. The webapp folder encompasses the React implementation of the webpage. Within this, the components folder houses the TypeScript code and the functions essential for building transactions, while the pages folder contains the code that facilitates the rendering of these components. The prisma folder is dedicated to the database configuration and its respective migrations. Finally, the oura directory contains the configuration file and the filter used when running the Oura daemon.
The following is a brief guide for getting everything running. It's recommended for developers with some experience with Cardano.
You can easily try out the app by running
$ docker-compose upThis will build the docker images for the webapp (including the frontend and the database), the contract backend and the oura daemon, and run them as containers. The app will be accesible from http://localhost:4202/.
You will need to set up the appropiate environment files (see Environment files)
The client side will run the dApp webpage service. We need to ensure we are using node 16.x version, which is as simple as:
$> nvm install 16.14.2
$> nvm use 16If you experiment dependencies broken error, use the option --legacy-peer-deps when running npm i
Run aiken build inside the contracts/onchain folder. This command will generate the scripts for both the main validator, and the minting policy.
Run the following command inside the webapp folder, to create the sqlite database:
$> npx prisma migrate dev --name initInstall from source (GNU/Linux):
-
Clone the github repository of Oura.
$> git clone git@github.com:txpipe/oura.git -
Compile using the following command, inside the oura folder:
$> cd oura $> cargo build --release --all-features
-
Move the local compilation
$> sudo mv target/release/ /usr/local/bin/
We need to have a few enviroment files where we set up the conection to blockfrost server.
For our example it is necessary to have a file named .env.local in webapp, with the following content:
NEXT_PUBLIC_BLOCKFROST_PROJECT_ID = preprodMySecretBlockFrostProjectId;And the following environment variables inside the contract/offchain/.env file:
BLOCKFROST_PROJECT_ID=preprodMySecretBlockFrostProjectId
PORT=3001
NETWORK=Preprod
SEED=...Where the preprodMySecretBlockFrostProjectId can be generated by following this tutorial.
The SEED variable represents the wallet used to submit transactions in the deploy operation script (see Deploying your own Validator and Minting Policy).
Run npm install inside the contract/offchain, and afterwards do npm start.
Run the daemon inside the webapp directory, with the following command:
$> oura daemon --config oura/daemon.tomlThen in the webapp folder run npm install and npm run dev. A browser webpage should prompt with the home page of the order dApp. The webpage will be running on http://localhost:4202/.
If you have changed the Aiken code of the multi-validator, you must then run aiken build inside the contracts/onchain folder. This will create a plutus.json file with the new information. For these changes to take effect, you must then run npm run deploy inside the offchain folder. This will pay a UTxO to a burn address, containing the multi-validator as a reference script. The hash of the transaction will be saved in the referenceScript.txt file. Also, two additional files will be created: policyId.txt (inside offchain/operations/), and orderAddress.txt (inside webapp/utils). The policy_id constant in webapp/oura/filter.js should be replaced by the new one in policyId.txt.
When working with Aiken multi-validator setups, it's crucial to wrap your redeemers with a special constructor to enable on-chain detection of which validator is being targeted. Specifically, this wrapping is necessary for redeemers expected by the spend validator, helping to differentiate between spend and mint validators. The process involves wrapping the original redeemer data with an additional constructor layer, as specified in the RedeemerWrapper$types/OrderRedeemer schema found in the plutus.json file generated when compiling the contract with Aiken.
Here's a simplified example of how to wrap a redeemer:
const wrapRedeemer = (redeemer) => new Constr(1, [redeemer]);This approach ensures that the on-chain code can correctly identify and process the redeemer, making it possible to support complex dApp functionalities involving multiple validators.
To run the tests, navigate to the onchain folder and execute the following command:
aiken check