-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: Initial Oracle Datum Implementation
- Loading branch information
0 parents
commit 6155160
Showing
6 changed files
with
301 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
name: Tests | ||
|
||
on: | ||
push: | ||
branches: ["main"] | ||
pull_request: | ||
|
||
jobs: | ||
build: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v3 | ||
|
||
- uses: aiken-lang/[email protected] | ||
with: | ||
version: v1.0.29-alpha | ||
|
||
- run: aiken fmt --check | ||
- run: aiken check -D | ||
- run: aiken build |
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,6 @@ | ||
# Aiken compilation artifacts | ||
artifacts/ | ||
# Aiken's project working directory | ||
build/ | ||
# Aiken's default documentation export | ||
docs/ |
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,76 @@ | ||
# Oracle Integration in Aiken | ||
|
||
This repository demonstrates how to integrate oracles into Cardano smart contracts using the Aiken programming language. It includes an oracle datum module and will feature example implementations, such as a betting contract, to showcase practical applications of oracle data in Cardano dApps. | ||
|
||
## Project Structure | ||
|
||
- `lib/`: Houses the core oracle integration module. | ||
- `oracle_datum.ak`: Contains the oracle datum definitions, functions, and associated tests. | ||
- `types.ak`: Defines common types used across the project. | ||
- `validators/`: Will contain the validator scripts, including the betting contract (to be implemented). | ||
- `aiken.toml`: Project configuration file. | ||
- `README.md`: This file, providing project overview and instructions. | ||
|
||
## Oracle Datum Module | ||
|
||
The oracle datum module in `lib/oracle_datum.ak` provides: | ||
|
||
- Definitions for oracle data structures | ||
- Functions for handling oracle data | ||
- Tests for the oracle datum functionality | ||
|
||
All tests for the oracle datum are included directly in the `oracle_datum.ak` file, allowing for easy reference and maintenance alongside the implementation. | ||
|
||
## Building | ||
|
||
To build the project, run: | ||
|
||
```sh | ||
aiken build | ||
``` | ||
|
||
This will compile all Aiken modules and generate the necessary Plutus scripts. | ||
|
||
## Testing | ||
|
||
Since tests are included in the `oracle_datum.ak` file, you can run them using: | ||
|
||
```sh | ||
aiken check | ||
``` | ||
|
||
To run tests matching a specific string (e.g., "oracle"), use: | ||
|
||
```sh | ||
aiken check -m oracle | ||
``` | ||
|
||
## Usage | ||
|
||
To use the oracle integration in your own project: | ||
|
||
1. Copy the `lib/oracle_datum.ak` file to your project's `lib/` directory. | ||
2. Import the oracle module in your validator: | ||
|
||
```aiken | ||
use oracle_datum | ||
validator { | ||
fn example(datum: Data, redeemer: Data, context: Data) -> Bool { | ||
// Use oracle functions here | ||
// e.g., oracle_datum.get_price(datum) | ||
} | ||
} | ||
``` | ||
|
||
## Documentation | ||
|
||
Generate HTML documentation for the project: | ||
|
||
```sh | ||
aiken docs | ||
``` | ||
|
||
## Contributing | ||
|
||
We welcome contributions! Please feel free to submit a Pull Request. |
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,15 @@ | ||
# This file was generated by Aiken | ||
# You typically do not need to edit this file | ||
|
||
[[requirements]] | ||
name = "aiken-lang/stdlib" | ||
version = "1.9.0" | ||
source = "github" | ||
|
||
[[packages]] | ||
name = "aiken-lang/stdlib" | ||
version = "1.9.0" | ||
requirements = [] | ||
source = "github" | ||
|
||
[etags] |
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,16 @@ | ||
name = "charli3/betting_contract" | ||
version = "0.0.0" | ||
compiler = "v1.0.29-alpha" | ||
plutus = "v2" | ||
license = "Apache-2.0" | ||
description = "A betting contract using Charli3 price feeds" | ||
|
||
[repository] | ||
user = "charli3" | ||
project = "betting_contract" | ||
platform = "github" | ||
|
||
[[dependencies]] | ||
name = "aiken-lang/stdlib" | ||
version = "1.9.0" | ||
source = "github" |
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,168 @@ | ||
use aiken/cbor | ||
use aiken/hash.{Blake2b_224, Hash} | ||
use aiken/pairs | ||
use aiken/transaction/credential.{Script} | ||
|
||
pub type PriceMap = | ||
Pairs<Int, Int> | ||
|
||
pub type PriceData { | ||
SharedData | ||
ExtendedData | ||
GenericData { price_map: PriceMap } | ||
} | ||
|
||
pub type OracleDatum { | ||
price_data: PriceData, | ||
} | ||
|
||
pub type ValidatorHash = | ||
Hash<Blake2b_224, Script> | ||
|
||
// Function to get the price from PriceData | ||
pub fn get_price(price_data: PriceData) -> Int { | ||
when price_data is { | ||
GenericData { price_map } -> | ||
when pairs.get_first(price_map, 0) is { | ||
Some(price) -> price | ||
None -> fail @"Price not found" | ||
} | ||
_ -> fail @"Invalid PriceData variant" | ||
} | ||
} | ||
|
||
// Function to get the timestamp from PriceData | ||
pub fn get_timestamp(price_data: PriceData) -> Int { | ||
when price_data is { | ||
GenericData { price_map } -> | ||
when pairs.get_first(price_map, 1) is { | ||
Some(timestamp) -> timestamp | ||
None -> fail @"Timestamp not found" | ||
} | ||
_ -> fail @"Invalid PriceData variant" | ||
} | ||
} | ||
|
||
// Function to get the expiry from PriceData | ||
pub fn get_expiry(price_data: PriceData) -> Int { | ||
when price_data is { | ||
GenericData { price_map } -> | ||
when pairs.get_first(price_map, 2) is { | ||
Some(expiry) -> expiry | ||
None -> fail @"Expiry not found" | ||
} | ||
_ -> fail @"Invalid PriceData variant" | ||
} | ||
} | ||
|
||
// Function to check if the oracle data is valid (not expired) | ||
pub fn is_oracle_valid(oracle_datum: OracleDatum, current_time: Int) -> Bool { | ||
current_time <= get_expiry(oracle_datum.price_data) | ||
} | ||
|
||
// Function to get the price from OracleDatum | ||
pub fn get_oracle_price(oracle_datum: OracleDatum) -> Int { | ||
get_price(oracle_datum.price_data) | ||
} | ||
|
||
// Function to get the timestamp from OracleDatum | ||
pub fn get_oracle_timestamp(oracle_datum: OracleDatum) -> Int { | ||
get_timestamp(oracle_datum.price_data) | ||
} | ||
|
||
// Test for get_price() | ||
test create_and_get_price() { | ||
let datum = | ||
OracleDatum { | ||
price_data: GenericData( | ||
[Pair(0, 2723), Pair(1, 1720056807332), Pair(2, 1720078407332)], | ||
), | ||
} | ||
get_price(datum.price_data) == 2723 && get_oracle_price(datum) == 2723 | ||
} | ||
|
||
// Test for get_timestamp() | ||
test create_and_get_timestamp() { | ||
let datum = | ||
OracleDatum { | ||
price_data: GenericData( | ||
[Pair(0, 2723), Pair(1, 1720056807332), Pair(2, 1720078407332)], | ||
), | ||
} | ||
get_timestamp(datum.price_data) == 1720056807332 && get_oracle_timestamp( | ||
datum, | ||
) == 1720056807332 | ||
} | ||
|
||
// Test for get_expiry() | ||
test create_and_get_expiry() { | ||
let datum = | ||
OracleDatum { | ||
price_data: GenericData( | ||
[Pair(0, 2723), Pair(1, 1720056807332), Pair(2, 1720078407332)], | ||
), | ||
} | ||
get_expiry(datum.price_data) == 1720078407332 | ||
} | ||
|
||
// Test for is_oracle_valid() | ||
test is_oracle_valid_test() { | ||
let datum = | ||
OracleDatum { | ||
price_data: GenericData( | ||
[Pair(0, 2723), Pair(1, 1720056807332), Pair(2, 1720078407332)], | ||
), | ||
} | ||
is_oracle_valid(datum, 1720056807332) == True && is_oracle_valid( | ||
datum, | ||
1720078407333, | ||
) == False | ||
} | ||
|
||
test oracle_datum_diagnostic() { | ||
let datum = | ||
OracleDatum { | ||
price_data: GenericData( | ||
[Pair(0, 490850), Pair(1, 1707172554600), Pair(2, 1707176154600)], | ||
), | ||
} | ||
let expected_diagnostic = | ||
@"121([_ 123([_ {_ 0: 490850, 1: 1707172554600, 2: 1707176154600 }])])" | ||
|
||
cbor.diagnostic(datum) == expected_diagnostic | ||
} | ||
|
||
test oracle_datum_serialise() { | ||
let datum = | ||
OracleDatum { | ||
price_data: GenericData( | ||
[Pair(0, 490850), Pair(1, 1707172554600), Pair(2, 1707176154600)], | ||
), | ||
} | ||
let expected_cbor = | ||
#"d8799fd87b9fa3001a00077d62011b0000018d7b69e768021b0000018d7ba0d5e8ffff" | ||
|
||
cbor.serialise(datum) == expected_cbor | ||
} | ||
|
||
test oracle_datum_getters() { | ||
let datum = | ||
OracleDatum { | ||
price_data: GenericData( | ||
[Pair(0, 2723), Pair(1, 1720056807332), Pair(2, 1720078407332)], | ||
), | ||
} | ||
|
||
get_oracle_price(datum) == 2723 && get_oracle_timestamp(datum) == 1720056807332 && get_expiry( | ||
datum.price_data, | ||
) == 1720078407332 | ||
} | ||
|
||
test valid_price_data() { | ||
let valid_price_data = | ||
GenericData([Pair(0, 100), Pair(1, 1720056807332), Pair(2, 1720078407332)]) | ||
|
||
let result = get_price(valid_price_data) | ||
|
||
result == 100 | ||
} |