Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
dust committed May 27, 2022
1 parent 892b425 commit 01335f1
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 28 deletions.
17 changes: 14 additions & 3 deletions 2-oracles/DexianOracle/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)

## Oracle Basic Request Model
## Basic Request Model

![Basic Request Model](res/basic_req_model.png)

Expand Down Expand Up @@ -37,7 +37,7 @@
2. 授权与取消授权管理


基于scrypto的badge设计模式实现的
基于scrypto的badge设计模式实现, 数据提供者需要先注册到预言机


## Decentralized Model
Expand All @@ -47,5 +47,16 @@

Each data feed is updated by a decentralized oracle network. Each oracle in the set publishes data during an aggregation round.

## VFC
```
RESULT=$(resim publish ".")
export PACKAGE=$(echo "$RESULT" | sed -nr "s/Success! New Package: ([[:alnum:]_]+)/\1/p")
export pkg=015586c1be716163cfbd2128ecebae7026ad2dee38c0b91b1b1fb9
resim call-function $pkg DeXianOracle new 20
export comp=0269b1040c49308764fef17ff5b53e5f3a72d5aca766e7233b1b23
export badge=033a8a6d4e1e20c0da6a8db3c7754c2e83d32d90b781b6581553a0
167 changes: 142 additions & 25 deletions 2-oracles/DexianOracle/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,36 +1,153 @@
use scrypto::prelude::*;

blueprint! {
struct Hello {
// Define what resources and data will be managed by Hello components
sample_vault: Vault
struct DeXianOracle {
/// This is just a reular admin badge, for register/remove DataProvider
admin_badge: ResourceAddress,

// /// DataProvider badge ResourceDef
// dataprovider_badge_def: ResourceDef,
// minter
callback_minter: Vault,

// /// DataProvider badge ResourceDef
// dataprovider_badge_def: ResourceDef,

/// callbacks
callback_vaults: Vault,

/// callback that have not yet been triggered
unfilful_vec: Vec<NonFungibleId>,

/// fee
fee: Decimal,

/// oracle (price, epoch_at) for XRD/USD
price_map: HashMap<String, (Decimal, u64)>,

/// balance(fee) vault
vault: Vault
}

impl DeXianOracle {
pub fn new(
fee: Decimal
) -> (ComponentAddress, Bucket) {
assert!( fee >= Decimal::zero(), "invalid fee value.");

impl Hello {
// Implement the functions and methods which will manage those resources and data

// This is a function, and can be called directly on the blueprint once deployed
pub fn instantiate_hello() -> ComponentAddress {
// Create a new token called "HelloToken," with a fixed supply of 1000, and put that supply into a bucket
let my_bucket: Bucket = ResourceBuilder::new_fungible()
.metadata("name", "HelloToken")
.metadata("symbol", "HT")
.initial_supply(1000);

// Instantiate a Hello component, populating its vault with our supply of 1000 HelloToken
Self {
sample_vault: Vault::with_bucket(my_bucket)
let admin_badge : Bucket = ResourceBuilder::new_fungible()
.metadata("name","DeXianOracle Admin Badge").metadata("symbol","DXADM")
.initial_supply(Decimal::ONE);

let minter_badge = ResourceBuilder::new_fungible()
.divisibility(DIVISIBILITY_NONE)
.initial_supply(Decimal::ONE);

let callback_bucket = ResourceBuilder::new_non_fungible()
.metadata("name", "DeXianOracle Callback").metadata("symbol", "DXCB")
.mintable(rule!(require(admin_badge.resource_address())), LOCKED)
.burnable(rule!(require(admin_badge.resource_address())), LOCKED)
.no_initial_supply();

let component = Self {
admin_badge: admin_badge.resource_address(),
price_map: HashMap::new(),
vault: Vault::new(RADIX_TOKEN),
callback_vaults: Vault::new(callback_bucket),
unfilful_vec: Vec::new(),
callback_minter: Vault::with_bucket(minter_badge),
fee
}.instantiate();

let access_rules = AccessRules::new()
.method("feed_price", rule!(require(admin_badge.resource_address())))
.method("request_price", rule!(allow_all))
.method("get_price", rule!(allow_all));
// .method("register_dataprovider", rule(!require(admin_badge.resource_address())))
// .method("remove_dataprovider", rule(!require(admin_badge.resource_address())));

(component.add_access_check(access_rules).globalize(), admin_badge)

}

pub fn feed_price(&mut self, pair: String, price: String) -> bool {
self.price_map.insert(pair.clone(), (Decimal::from(price), Runtime::current_epoch()));
self.filfull_request(&pair);
true
}

pub fn get_price(&self, pair:String) -> (Decimal, u64){
assert!(self.price_map.contains_key(&pair), "the pair not exists!");
*self.price_map.get(&pair).unwrap()
}

pub fn request_price(&mut self, fee: Bucket, pair: String, component: ComponentAddress,
method: String, args: Vec<Vec<u8>>) -> NonFungibleId {
assert!(fee.amount() < self.fee, "Fees are lower than required!");

let callback_id = NonFungibleId::random();
let callback_data = CallbackData::new_instance(callback_id.clone(), component, method, pair, args);

let callback = self.callback_minter.authorize(|| {
let rm = borrow_resource_manager!(self.callback_vaults.resource_address());
rm.mint_non_fungible(&callback_id, callback_data)
});
// Store the Callback NFR inside this component
self.callback_vaults.put(callback);
self.unfilful_vec.push(callback_id.clone());
callback_id
}

fn filfull_request(&mut self, pair: &String) {
let mut i = 0;
while i < self.unfilful_vec.len() {
if self.callback_vaults.non_fungible_ids().contains(&self.unfilful_vec[i]){
let callback = self.callback_vaults.take_non_fungible(&self.unfilful_vec[i]);
let callback_data = callback.non_fungible::<CallbackData>().data();
if callback_data.pair.eq(pair) {
callback_data.call();
self.unfilful_vec.remove(i);
}
i += 1;
}
}
.instantiate()
.globalize()
}
}
}

#[derive(NonFungibleData)]
pub struct CallbackData {
/// request id
pub id: NonFungibleId,

pub pair: String,

// This is a method, because it needs a reference to self. Methods can only be called on components
pub fn free_token(&mut self) -> Bucket {
info!("My balance is: {} HelloToken. Now giving away a token!", self.sample_vault.amount());
// If the semi-colon is omitted on the last line, the last value seen is automatically returned
// In this case, a bucket containing 1 HelloToken is returned
self.sample_vault.take(1)
/// The target component of the callback
pub component: ComponentAddress,

/// The target method of the callback
pub method: String,

/// The args that should be passed to the target method
pub args: Vec<Vec<u8>>,
}

impl CallbackData {

pub fn new_instance(id: NonFungibleId, component: ComponentAddress,
method: String, pair: String, args: Vec<Vec<u8>>
) -> Self {

Self {
args: args.to_vec(),
pair,
id,
component,
method
}
}

pub fn call(&self){
Runtime::call_method(self.component, &self.method, self.args.to_vec());
}
}
7 changes: 7 additions & 0 deletions 2-oracles/DexianOracle/transactions/user_account_feed.rtm
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
CALL_METHOD
ComponentAddress("${user_account}")
"create_proof"
ResourceAddress("${badge}");


CALL_METHOD ComponentAddress("${comp}") "feed_price" "XRD/USD" "0.0813";

0 comments on commit 01335f1

Please sign in to comment.