Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
b169531
Add update pool box transaction builder
sethdusek Jul 22, 2022
260366b
Fix Ballot Contract registers + convert build_update_pool_box_tx to R…
sethdusek Jul 23, 2022
1700710
Add update pool box with new reward tokens + return TransactionContext
sethdusek Jul 25, 2022
3004f62
Count votes based on ballot tokens + initial cli command work
sethdusek Jul 26, 2022
d06ba77
Fix scans
sethdusek Jul 27, 2022
866494a
Add update pool CLI command
sethdusek Jul 29, 2022
148f021
Merge branch 'develop' into updatepool
sethdusek Jul 29, 2022
22b46bf
Initial rebase work
sethdusek Jul 30, 2022
1e756e5
Initial update bootstrap command work
sethdusek Aug 1, 2022
bc6a83b
Add testnet parameter to bootstrap
sethdusek Aug 2, 2022
fd5ff58
More update command work + make OracleContractParameters serializable…
sethdusek Aug 2, 2022
72d5f3b
Update explorer link
sethdusek Aug 3, 2022
2bfd6a6
Add remaining parameters (update, pool) to update command + update Ba…
sethdusek Aug 4, 2022
705ee00
Use new oracle_config_updated.yaml format for update-pool command
sethdusek Aug 4, 2022
cdd9821
Clippy
sethdusek Aug 4, 2022
0ea3b21
Add ToScanBytes trait
sethdusek Aug 4, 2022
fb6e019
Add update command unit test
sethdusek Aug 4, 2022
3482035
Use new update contract
sethdusek Aug 4, 2022
8e11e56
Allow for optional CastVoteParameters in Ballot Box
sethdusek Aug 4, 2022
ef4be44
Improve error message for ballot tokens in wallet
sethdusek Aug 4, 2022
7bcfc5e
Rename update command
sethdusek Aug 5, 2022
4852efa
Remove unnecessary node API call + remove unneeded reward token incre…
sethdusek Aug 6, 2022
174dd84
Remove height parameter in update-pool + write docs for update-pool /…
sethdusek Aug 6, 2022
1e5f6ec
Update token arguments for update_pool
sethdusek Aug 6, 2022
c788c07
Rework target tokens selection
sethdusek Aug 6, 2022
b8253e6
Add VoteBallotBoxesWrapper
sethdusek Aug 7, 2022
7eed4a6
Rename update.rs
sethdusek Aug 7, 2022
e5048bb
Change CastBallotBoxVoteParameters::reward_token_quantity to u64
sethdusek Aug 7, 2022
57effa2
Clippy
sethdusek Aug 7, 2022
a974c1a
Add update box creation height to CastBallotBoxVoteParameters
sethdusek Aug 7, 2022
420740e
Merge branch 'develop' into updatepool
sethdusek Aug 10, 2022
4bb37d6
Merge branch 'updatepool' of github.com:SethDusek/oracle-core into up…
sethdusek Aug 10, 2022
9b78803
Rebase
sethdusek Aug 10, 2022
a59227f
Update comment core/src/main.rs
sethdusek Aug 11, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions core/src/box_kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ mod ballot_box;
mod oracle_box;
mod pool_box;
mod refresh_box;
mod update_box;

pub use ballot_box::*;
pub use oracle_box::*;
pub use pool_box::*;
pub use refresh_box::*;
pub use update_box::*;
189 changes: 145 additions & 44 deletions core/src/box_kind/ballot_box.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std::convert::TryInto;

use crate::{
contracts::ballot::{BallotContract, BallotContractError},
oracle_config::{BallotBoxWrapperParameters, CastBallotBoxVoteParameters},
Expand Down Expand Up @@ -59,23 +57,14 @@ pub trait BallotBox {
fn get_box(&self) -> &ErgoBox;
}

#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct BallotBoxWrapper {
ergo_box: ErgoBox,
contract: BallotContract,
}

impl BallotBoxWrapper {
pub fn new(ergo_box: ErgoBox, inputs: BallotBoxWrapperInputs) -> Result<Self, BallotBoxError> {
let CastBallotBoxVoteParameters {
reward_token_id,
reward_token_quantity,
pool_box_address_hash,
} = inputs
.parameters
.vote_parameters
.as_ref()
.ok_or(BallotBoxError::ExpectedVoteCast)?;
let ballot_token_id = &ergo_box
.tokens
.as_ref()
Expand All @@ -98,42 +87,54 @@ impl BallotBoxWrapper {
return Err(BallotBoxError::UnexpectedGroupElementInR4);
}

if ergo_box
.get_register(NonMandatoryRegisterId::R5.into())
.ok_or(BallotBoxError::NoUpdateBoxCreationHeightInR5)?
.try_extract_into::<i32>()
.is_err()
if let Some(CastBallotBoxVoteParameters {
reward_token_id,
reward_token_quantity,
pool_box_address_hash,
update_box_creation_height,
}) = inputs.parameters.vote_parameters.as_ref()
{
return Err(BallotBoxError::NoUpdateBoxCreationHeightInR5);
}
let register_update_box_creation_height = ergo_box
.get_register(NonMandatoryRegisterId::R5.into())
.ok_or(BallotBoxError::NoUpdateBoxCreationHeightInR5)?
.try_extract_into::<i32>()?;

let register_pool_box_address_hash = ergo_box
.get_register(NonMandatoryRegisterId::R6.into())
.ok_or(BallotBoxError::NoPoolBoxAddressInR6)?
.try_extract_into::<Digest32>()?;
let pb: Digest32 = base16::decode(pool_box_address_hash)
.unwrap()
.try_into()
.unwrap();
if pb != register_pool_box_address_hash {
warn!("Pool box address in R6 register differs to config. Could be due to vote.");
}
if register_update_box_creation_height != *update_box_creation_height {
warn!("Update box creation height in R5 register differs to config. Could be due to vote.");
}

let register_reward_token_id = ergo_box
.get_register(NonMandatoryRegisterId::R7.into())
.ok_or(BallotBoxError::NoRewardTokenIdInR7)?
.try_extract_into::<TokenId>()?;
if register_reward_token_id != *reward_token_id {
warn!("Reward token id in R7 register differs to config. Could be due to vote.");
}
let register_pool_box_address_hash = ergo_box
.get_register(NonMandatoryRegisterId::R6.into())
.ok_or(BallotBoxError::NoPoolBoxAddressInR6)?
.try_extract_into::<Digest32>()?;

let register_reward_token_quantity = ergo_box
.get_register(NonMandatoryRegisterId::R8.into())
.ok_or(BallotBoxError::NoRewardTokenQuantityInR8)?
.try_extract_into::<i32>()? as u32;
if *pool_box_address_hash != register_pool_box_address_hash {
warn!("Pool box address in R6 register differs to config. Could be due to vote.");
}

let register_reward_token_id = ergo_box
.get_register(NonMandatoryRegisterId::R7.into())
.ok_or(BallotBoxError::NoRewardTokenIdInR7)?
.try_extract_into::<TokenId>()?;

if register_reward_token_id != *reward_token_id {
warn!("Reward token id in R7 register differs to config. Could be due to vote.");
}

if register_reward_token_quantity != *reward_token_quantity {
warn!("Reward token quantity in R8 register differs to config. Could be due to vote.");
let register_reward_token_quantity: u64 = ergo_box
.get_register(NonMandatoryRegisterId::R8.into())
.ok_or(BallotBoxError::NoRewardTokenQuantityInR8)?
.try_extract_into::<i64>()?
as u64;

if register_reward_token_quantity != *reward_token_quantity {
warn!(
"Reward token quantity in R8 register differs to config. Could be due to vote."
);
}
} else if ergo_box.additional_registers.len() > 1 {
// If no vote parameter is provided, then the box must only have R4 (owner public key) defined
return Err(BallotBoxError::ExpectedVoteCast);
}

let contract = BallotContract::from_ergo_tree(ergo_box.ergo_tree.clone(), inputs.into())?;
Expand All @@ -150,6 +151,73 @@ pub struct BallotBoxWrapperInputs<'a> {
pub update_nft_token_id: &'a TokenId,
}

/// A Ballot Box with vote parameters guaranteed to be set
#[derive(Clone, Debug)]
pub struct VoteBallotBoxWrapper {
ergo_box: ErgoBox,
vote_parameters: CastBallotBoxVoteParameters,
contract: BallotContract,
}

impl VoteBallotBoxWrapper {
pub fn new(ergo_box: ErgoBox, inputs: BallotBoxWrapperInputs) -> Result<Self, BallotBoxError> {
let ballot_token_id = &ergo_box
.tokens
.as_ref()
.ok_or(BallotBoxError::NoBallotToken)?
.get(0)
.ok_or(BallotBoxError::NoBallotToken)?
.token_id;
if *ballot_token_id != *inputs.ballot_token_id {
return Err(BallotBoxError::UnknownBallotTokenId);
}

if ergo_box
.get_register(NonMandatoryRegisterId::R4.into())
.ok_or(BallotBoxError::NoGroupElementInR4)?
.try_extract_into::<EcPoint>()
.is_err()
{
return Err(BallotBoxError::NoGroupElementInR4);
}
let update_box_creation_height = ergo_box
.get_register(NonMandatoryRegisterId::R5.into())
.ok_or(BallotBoxError::NoUpdateBoxCreationHeightInR5)?
.try_extract_into::<i32>()?;

let pool_box_address_hash = ergo_box
.get_register(NonMandatoryRegisterId::R6.into())
.ok_or(BallotBoxError::NoPoolBoxAddressInR6)?
.try_extract_into::<Digest32>()?;

let reward_token_id = ergo_box
.get_register(NonMandatoryRegisterId::R7.into())
.ok_or(BallotBoxError::NoRewardTokenIdInR7)?
.try_extract_into::<TokenId>()?;
let reward_token_quantity = ergo_box
.get_register(NonMandatoryRegisterId::R8.into())
.ok_or(BallotBoxError::NoRewardTokenQuantityInR8)?
.try_extract_into::<i64>()? as u64;

let contract = BallotContract::from_ergo_tree(ergo_box.ergo_tree.clone(), inputs.into())?;
let vote_parameters = CastBallotBoxVoteParameters {
pool_box_address_hash,
reward_token_id,
reward_token_quantity,
update_box_creation_height,
};
Ok(Self {
ergo_box,
contract,
vote_parameters,
})
}

pub fn vote_parameters(&self) -> &CastBallotBoxVoteParameters {
&self.vote_parameters
}
}

impl BallotBox for BallotBoxWrapper {
fn contract(&self) -> &BallotContract {
&self.contract
Expand Down Expand Up @@ -183,6 +251,39 @@ impl BallotBox for BallotBoxWrapper {
}
}

impl BallotBox for VoteBallotBoxWrapper {
fn contract(&self) -> &BallotContract {
&self.contract
}

fn ballot_token(&self) -> Token {
self.ergo_box
.tokens
.as_ref()
.unwrap()
.get(0)
.unwrap()
.clone()
}

fn min_storage_rent(&self) -> u64 {
self.contract.min_storage_rent()
}

fn ballot_token_owner(&self) -> ProveDlog {
self.ergo_box
.get_register(NonMandatoryRegisterId::R4.into())
.unwrap()
.try_extract_into::<EcPoint>()
.unwrap()
.into()
}

fn get_box(&self) -> &ErgoBox {
&self.ergo_box
}
}

#[allow(clippy::too_many_arguments)]
pub fn make_local_ballot_box_candidate(
contract: &BallotContract,
Expand Down Expand Up @@ -210,7 +311,7 @@ pub fn make_local_ballot_box_candidate(
);
builder.set_register_value(
NonMandatoryRegisterId::R8,
(*reward_tokens.amount.as_u64() as i32).into(),
(*reward_tokens.amount.as_u64() as i64).into(),
);
builder.add_token(ballot_token);
builder.build()
Expand Down
70 changes: 70 additions & 0 deletions core/src/box_kind/update_box.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use ergo_lib::ergotree_ir::chain::ergo_box::ErgoBox;
use ergo_lib::ergotree_ir::chain::token::Token;
use ergo_lib::ergotree_ir::chain::token::TokenId;
use ergo_lib::ergotree_ir::ergo_tree::ErgoTree;
use thiserror::Error;

use crate::contracts::update::UpdateContract;
use crate::contracts::update::UpdateContractError;
use crate::contracts::update::UpdateContractParameters;

#[derive(Debug, Error)]
pub enum UpdateBoxError {
#[error("oracle box: no tokens found")]
NoTokens,
#[error("update contract: {0:?}")]
UpdateContractError(#[from] UpdateContractError),
#[error("update contract: {0:?}")]
IncorrectUpdateTokenId(TokenId),
}

#[derive(Clone)]
pub struct UpdateBoxWrapper(ErgoBox, UpdateContract);

impl UpdateBoxWrapper {
pub fn new(b: ErgoBox, inputs: UpdateBoxWrapperInputs) -> Result<Self, UpdateBoxError> {
let update_token_id = b
.tokens
.as_ref()
.ok_or(UpdateBoxError::NoTokens)?
.get(0)
.ok_or(UpdateBoxError::NoTokens)?
.token_id
.clone();
if update_token_id != *inputs.update_nft_token_id {
return Err(UpdateBoxError::IncorrectUpdateTokenId(update_token_id));
}
let contract = UpdateContract::from_ergo_tree(b.ergo_tree.clone(), inputs.into())?;

Ok(Self(b, contract))
}
pub fn ergo_tree(&self) -> ErgoTree {
self.1.ergo_tree()
}
pub fn update_nft(&self) -> Token {
self.0.tokens.as_ref().unwrap().get(0).unwrap().clone()
}
pub fn ballot_token_id(&self) -> TokenId {
self.1.ballot_token_id().clone()
}
pub fn get_box(&self) -> &ErgoBox {
&self.0
}
pub fn min_votes(&self) -> u32 {
self.1.min_votes() as u32
}
}

#[derive(Debug, Copy, Clone)]
pub struct UpdateBoxWrapperInputs<'a> {
pub contract_parameters: &'a UpdateContractParameters,
pub update_nft_token_id: &'a TokenId,
pub ballot_token_id: &'a TokenId,
pub pool_nft_token_id: &'a TokenId,
}

impl From<UpdateBoxWrapper> for ErgoBox {
fn from(w: UpdateBoxWrapper) -> Self {
w.0.clone()
}
}
3 changes: 3 additions & 0 deletions core/src/cli_commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@ use ergo_lib::ergotree_ir::chain::address::NetworkPrefix;

pub mod bootstrap;
pub mod extract_reward_tokens;
pub mod prepare_update;
pub mod print_reward_tokens;
pub mod transfer_oracle_token;
pub mod update_pool;
pub mod vote_update_pool;

pub(crate) fn ergo_explorer_transaction_link(tx_id_str: String, prefix: NetworkPrefix) -> String {
let prefix_str = match prefix {
NetworkPrefix::Mainnet => "explorer",
NetworkPrefix::Testnet => "testnet",
};
let tx_id_str = tx_id_str.replace('"', ""); // Node interface returns Tx Id as a JSON string "TxId"
format!(
"https://{}.ergoplatform.com/en/transactions/{}",
prefix_str, tx_id_str
Expand Down
Loading