diff --git a/README.md b/README.md index d5bc3282..0043f8e7 100644 --- a/README.md +++ b/README.md @@ -154,19 +154,20 @@ The output shows the new pool box contract hash and reward tokens amounts for th Run ```console -oracle-core vote-update-pool +oracle-core vote-update-pool ``` Where: - - base16-encoded blake2b hash of the serialized pool box contract for the new pool box -- - base16-encoded reward token id in the new pool box (use existing if unchanged) -- - reward token amount in the pool box at the time of update transaction is committed - - The creation height of the existing update box. -and are printed in the output of the `prepare-update` command. +are required parameters, with optinal (in case of minting a new reward token): + +- - base16-encoded reward token id in the new pool box (use existing if unchanged) +- - reward token amount in the pool box at the time of update transaction is committed -Keep in mind the REWARD_TOKEN_AMOUNT depends on when(in which epoch) the final `update-pool` command will be run. +They are printed in the output of the `prepare-update` command. ### Update the pool box contract with `update-pool` command @@ -174,24 +175,26 @@ Make sure the `pool_config_updated.yaml` config file generated during the `prepa Run ```console -oracle-core update-pool +oracle-core update-pool ``` -to see the diff for the tokens. +With optional(only if minted) parameters: + - base16-encoded reward token id in the new pool box (only if minted) + - reward token amount in the pool box at the time of update transaction is committed (only if minted) + +This will submit an update tx. +After the update tx is confirmed, remove `scanIds.json` and use `pool_config_updated.yaml` to run the oracle (i.e., rename it to `pool_config.yaml` and restart the oracle). +Distribute the `pool_config.yaml` file to all the oracles. Be sure they delete `scanIds.json` before restart. + +### Import update pool config with `import-pool-update` command +Make sure the `pool_config_updated.yaml` config file generated during the `prepare-update` command is at hand. Run ```console -oracle-core update-pool +oracle-core update-pool pool_config_updated.yaml ``` -Where: - - base16-encoded blake2b hash of the serialized pool box contract for the new pool box - - base16-encoded reward token id in the new pool box (use existing if unchanged) - - reward token amount in the pool box at the time of update transaction is committed - -This will submit an update tx. -After the update tx is confirmed, remove `scanIds.json` and use `pool_config_updated.yaml` to run the oracle (i.e., rename it to `pool_config.yaml` and restart the oracle). -Distribute the `pool_config.yaml` file to all the oracles. Be sure they delete `scanIds.json` before restart. +This will update the pool_config.yaml, removes `scanIds.json`. Restart the oracle afterwards. ## How to run as systemd daemon diff --git a/core/src/box_kind/ballot_box.rs b/core/src/box_kind/ballot_box.rs index 217c7a75..54a5b8b3 100644 --- a/core/src/box_kind/ballot_box.rs +++ b/core/src/box_kind/ballot_box.rs @@ -3,8 +3,7 @@ use crate::{ BallotContract, BallotContractError, BallotContractInputs, BallotContractParameters, }, oracle_types::BlockHeight, - pool_config::CastBallotBoxVoteParameters, - spec_token::{BallotTokenId, SpecToken, TokenIdKind, UpdateTokenId}, + spec_token::{BallotTokenId, RewardTokenId, SpecToken, TokenIdKind, UpdateTokenId}, }; use ergo_lib::{ chain::ergo_box::box_builder::{ErgoBoxCandidateBuilder, ErgoBoxCandidateBuilderError}, @@ -13,7 +12,7 @@ use ergo_lib::{ chain::{ address::{Address, AddressEncoderError}, ergo_box::{box_value::BoxValue, ErgoBox, ErgoBoxCandidate, NonMandatoryRegisterId}, - token::{Token, TokenId}, + token::TokenId, }, mir::constant::{TryExtractFromError, TryExtractInto}, serialization::SigmaSerializationError, @@ -28,10 +27,6 @@ pub enum BallotBoxError { NoBallotToken, #[error("ballot box: unknown ballot token id in `TOKENS(0)`")] UnknownBallotTokenId, - #[error("ballot box: no reward token id in R7 register")] - NoRewardTokenIdInR7, - #[error("ballot box: no reward token quantity in R8 register")] - NoRewardTokenQuantityInR8, #[error("ballot box: no group element in R4 register")] NoGroupElementInR4, #[error("ballot box: unexpected group element in R4 register")] @@ -48,6 +43,8 @@ pub enum BallotBoxError { TryExtractFrom(#[from] TryExtractFromError), #[error("ballot box: SigmaSerializationError {0:?}")] SigmaSerialization(#[from] SigmaSerializationError), + #[error("invalid reward token: {0:?}")] + InvalidRewardToken(String), } pub trait BallotBox { @@ -130,6 +127,13 @@ impl BallotBoxWrapperInputs { } } +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct CastBallotBoxVoteParameters { + pub pool_box_address_hash: Digest32, + pub reward_token_opt: Option>, + pub update_box_creation_height: i32, +} + /// A Ballot Box with vote parameters guaranteed to be set #[derive(Clone, Debug)] pub struct VoteBallotBoxWrapper { @@ -169,21 +173,31 @@ impl VoteBallotBoxWrapper { .ok_or(BallotBoxError::NoPoolBoxAddressInR6)? .try_extract_into::()?; - let reward_token_id = ergo_box + let reward_token_id_opt = ergo_box .get_register(NonMandatoryRegisterId::R7.into()) - .ok_or(BallotBoxError::NoRewardTokenIdInR7)? - .try_extract_into::()?; - let reward_token_quantity = ergo_box + .map(|c| c.try_extract_into::()); + let reward_token_quantity_opt = ergo_box .get_register(NonMandatoryRegisterId::R8.into()) - .ok_or(BallotBoxError::NoRewardTokenQuantityInR8)? - .try_extract_into::()? as u64; + .map(|c| c.try_extract_into::()); + let reward_token_opt = match (reward_token_id_opt, reward_token_quantity_opt) { + (Some(Ok(reward_token_id)), Some(Ok(reward_token_quantity))) => Some(SpecToken { + token_id: RewardTokenId::from_token_id_unchecked(reward_token_id), + amount: (reward_token_quantity as u64).try_into().unwrap(), + }), + (None, None) => None, + (id, amt) => { + return Err(BallotBoxError::InvalidRewardToken(format!( + "Reward token id {:?} amount {:?}", + id, amt + ))) + } + }; let contract = BallotContract::from_ergo_tree(ergo_box.ergo_tree.clone(), &inputs.contract_inputs)?; let vote_parameters = CastBallotBoxVoteParameters { pool_box_address_hash, - reward_token_id, - reward_token_quantity, + reward_token_opt, update_box_creation_height, }; Ok(Self { @@ -269,7 +283,7 @@ pub fn make_local_ballot_box_candidate( update_box_creation_height: BlockHeight, ballot_token: SpecToken, pool_box_address_hash: Digest32, - reward_tokens: Token, + reward_token_opt: Option>, value: BoxValue, creation_height: BlockHeight, ) -> Result { @@ -283,11 +297,16 @@ pub fn make_local_ballot_box_candidate( (update_box_creation_height.0 as i32).into(), ); builder.set_register_value(NonMandatoryRegisterId::R6, pool_box_address_hash.into()); - builder.set_register_value(NonMandatoryRegisterId::R7, reward_tokens.token_id.into()); - builder.set_register_value( - NonMandatoryRegisterId::R8, - (*reward_tokens.amount.as_u64() as i64).into(), - ); + if let Some(reward_tokens) = reward_token_opt { + builder.set_register_value( + NonMandatoryRegisterId::R7, + reward_tokens.token_id.token_id().into(), + ); + builder.set_register_value( + NonMandatoryRegisterId::R8, + (*reward_tokens.amount.as_u64() as i64).into(), + ); + } builder.add_token(ballot_token.into()); builder.build() } diff --git a/core/src/box_kind/pool_box.rs b/core/src/box_kind/pool_box.rs index a828d838..155a609a 100644 --- a/core/src/box_kind/pool_box.rs +++ b/core/src/box_kind/pool_box.rs @@ -4,7 +4,6 @@ use ergo_lib::ergotree_ir::chain::ergo_box::box_value::BoxValue; use ergo_lib::ergotree_ir::chain::ergo_box::ErgoBox; use ergo_lib::ergotree_ir::chain::ergo_box::ErgoBoxCandidate; use ergo_lib::ergotree_ir::chain::ergo_box::NonMandatoryRegisterId; -use ergo_lib::ergotree_ir::chain::token::Token; use ergo_lib::ergotree_ir::mir::constant::TryExtractInto; use thiserror::Error; @@ -229,7 +228,7 @@ pub fn make_pool_box_candidate_unchecked( datapoint: i64, epoch_counter: EpochCounter, pool_nft_token: SpecToken, - reward_token: Token, + reward_token: SpecToken, value: BoxValue, creation_height: BlockHeight, ) -> Result { @@ -237,6 +236,6 @@ pub fn make_pool_box_candidate_unchecked( builder.set_register_value(NonMandatoryRegisterId::R4, datapoint.into()); builder.set_register_value(NonMandatoryRegisterId::R5, (epoch_counter.0 as i32).into()); builder.add_token(pool_nft_token.into()); - builder.add_token(reward_token); + builder.add_token(reward_token.into()); builder.build() } diff --git a/core/src/cli_commands.rs b/core/src/cli_commands.rs index eb23e6d6..7bba8e8c 100644 --- a/core/src/cli_commands.rs +++ b/core/src/cli_commands.rs @@ -1,6 +1,3 @@ -use ergo_lib::chain::transaction::TxId; -use ergo_lib::ergotree_ir::chain::address::NetworkPrefix; - pub mod bootstrap; pub mod extract_reward_tokens; pub mod import_pool_update; @@ -9,15 +6,3 @@ 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: TxId, prefix: NetworkPrefix) -> String { - let prefix_str = match prefix { - NetworkPrefix::Mainnet => "explorer", - NetworkPrefix::Testnet => "testnet", - }; - let tx_id_str = String::from(tx_id); - format!( - "https://{}.ergoplatform.com/en/transactions/{}", - prefix_str, tx_id_str - ) -} diff --git a/core/src/cli_commands/bootstrap.rs b/core/src/cli_commands/bootstrap.rs index 53d75e39..9b1266d6 100644 --- a/core/src/cli_commands/bootstrap.rs +++ b/core/src/cli_commands/bootstrap.rs @@ -669,7 +669,6 @@ pub(crate) mod tests { ergotree_ir::chain::{ address::{AddressEncoder, NetworkAddress, NetworkPrefix}, ergo_box::{ErgoBox, NonMandatoryRegisters}, - token::TokenId, }, wallet::Wallet, }; @@ -781,12 +780,6 @@ pub(crate) mod tests { let s = serde_yaml::to_string(&oracle_config).unwrap(); println!("{}", s); - // Quickly check an encoding - let bytes: Vec = token_ids.ballot_token_id.token_id().into(); - let encoded = base64::encode(bytes); - let ballot_id = TokenId::from_base64(&encoded).unwrap(); - assert_eq!(token_ids.ballot_token_id.token_id(), ballot_id); - // Check that refresh contract is updated assert_ne!( oracle_config diff --git a/core/src/cli_commands/extract_reward_tokens.rs b/core/src/cli_commands/extract_reward_tokens.rs index d991d428..3921490b 100644 --- a/core/src/cli_commands/extract_reward_tokens.rs +++ b/core/src/cli_commands/extract_reward_tokens.rs @@ -26,7 +26,7 @@ use crate::{ box_kind::{ make_collected_oracle_box_candidate, make_oracle_box_candidate, OracleBox, OracleBoxWrapper, }, - cli_commands::ergo_explorer_transaction_link, + explorer_api::ergo_explorer_transaction_link, node_interface::{SignTransaction, SubmitTransaction}, oracle_config::BASE_FEE, oracle_state::{LocalDatapointBoxSource, StageError}, @@ -226,7 +226,7 @@ mod tests { let wallet = Wallet::from_secrets(vec![secret.clone().into()]); let oracle_pub_key = secret.public_image().h; - let num_reward_tokens_in_box = 100_u64; + let num_reward_tokens_in_box = 2; let parameters = OracleContractParameters::default(); let oracle_box_wrapper_inputs = @@ -239,6 +239,7 @@ mod tests { &token_ids, BASE_FEE.checked_mul_u32(100).unwrap(), BlockHeight(height.0), + num_reward_tokens_in_box, ), &oracle_box_wrapper_inputs, ) diff --git a/core/src/cli_commands/prepare_update.rs b/core/src/cli_commands/prepare_update.rs index cbd55657..ea37032e 100644 --- a/core/src/cli_commands/prepare_update.rs +++ b/core/src/cli_commands/prepare_update.rs @@ -111,8 +111,6 @@ pub fn prepare_update( let prepare = PrepareUpdate::new(update_bootstrap_input, &POOL_CONFIG, &ORACLE_CONFIG)?; let (new_config, submitted_tx_ids) = prepare.execute(config)?; - wait_for_txs_confirmation(submitted_tx_ids); - // let new_config = perform_update_chained_transaction(update_bootstrap_input)?; let blake2b_pool_ergo_tree: String = blake2b256_hash( new_config .pool_box_wrapper_inputs @@ -134,11 +132,12 @@ pub fn prepare_update( "Base16-encoded blake2b hash of the serialized new pool box contract(ErgoTree): {}", blake2b_pool_ergo_tree ); - print_hints_for_voting(height.0)?; + print_hints_for_voting(height)?; + wait_for_txs_confirmation(submitted_tx_ids); Ok(()) } -fn print_hints_for_voting(height: u32) -> Result<(), PrepareUpdateError> { +fn print_hints_for_voting(height: BlockHeight) -> Result<(), PrepareUpdateError> { let epoch_length = POOL_CONFIG .refresh_box_wrapper_inputs .contract_inputs @@ -150,15 +149,16 @@ fn print_hints_for_voting(height: u32) -> Result<(), PrepareUpdateError> { let min_oracle_box_height = height - epoch_length; let active_oracle_count = oracle_boxes .into_iter() - .filter(|b| b.creation_height >= min_oracle_box_height) + .filter(|b| b.creation_height >= min_oracle_box_height.0) .count() as u32; let pool_box = op.get_pool_box_source().get_pool_box().unwrap(); let pool_box_height = pool_box.get_box().creation_height; - let next_epoch_height = max(pool_box_height + epoch_length, height); + let next_epoch_height = max(pool_box_height + epoch_length, height.0); let reward_tokens_left = *pool_box.reward_token().amount.as_u64(); let update_box = op.get_update_box_source().get_update_box().unwrap(); let update_box_height = update_box.get_box().creation_height; info!("Update box height: {}", update_box_height); + info!( "Reward token id in the pool box: {}", String::from(pool_box.reward_token().token_id.token_id()) diff --git a/core/src/cli_commands/transfer_oracle_token.rs b/core/src/cli_commands/transfer_oracle_token.rs index 6b144528..9f1c9a55 100644 --- a/core/src/cli_commands/transfer_oracle_token.rs +++ b/core/src/cli_commands/transfer_oracle_token.rs @@ -23,7 +23,7 @@ use crate::{ box_kind::{ make_collected_oracle_box_candidate, make_oracle_box_candidate, OracleBox, OracleBoxWrapper, }, - cli_commands::ergo_explorer_transaction_link, + explorer_api::ergo_explorer_transaction_link, node_interface::{SignTransaction, SubmitTransaction}, oracle_config::BASE_FEE, oracle_state::{LocalDatapointBoxSource, StageError}, @@ -113,7 +113,7 @@ fn build_transfer_oracle_token_tx( .get_local_oracle_datapoint_box()? .ok_or(TransferOracleTokenActionError::NoLocalDatapointBox)?; let num_reward_tokens = *in_oracle_box.reward_token().amount.as_u64(); - if num_reward_tokens <= 1 { + if num_reward_tokens != 1 { return Err( TransferOracleTokenActionError::IncorrectNumberOfRewardTokensInOracleBox( num_reward_tokens as usize, @@ -215,6 +215,7 @@ mod tests { &token_ids, BASE_FEE.checked_mul_u32(100).unwrap(), BlockHeight(height.0) - 9, + 1, ), &oracle_box_wrapper_inputs, ) diff --git a/core/src/cli_commands/update_pool.rs b/core/src/cli_commands/update_pool.rs index b1ef83c0..3b3af677 100644 --- a/core/src/cli_commands/update_pool.rs +++ b/core/src/cli_commands/update_pool.rs @@ -9,7 +9,6 @@ use ergo_lib::{ ergotree_ir::chain::{ address::Address, ergo_box::{ErgoBox, NonMandatoryRegisterId}, - token::Token, }, ergotree_ir::serialization::SigmaSerializable, wallet::{ @@ -24,16 +23,17 @@ use std::convert::TryInto; use crate::{ box_kind::{ - make_pool_box_candidate_unchecked, BallotBox, PoolBox, PoolBoxWrapper, VoteBallotBoxWrapper, + make_pool_box_candidate_unchecked, BallotBox, CastBallotBoxVoteParameters, PoolBox, + PoolBoxWrapper, VoteBallotBoxWrapper, }, - cli_commands::ergo_explorer_transaction_link, contracts::pool::PoolContract, + explorer_api::ergo_explorer_transaction_link, node_interface::{SignTransaction, SubmitTransaction}, oracle_config::BASE_FEE, oracle_state::{OraclePool, PoolBoxSource, StageError, UpdateBoxSource, VoteBallotBoxesSource}, oracle_types::BlockHeight, - pool_config::{CastBallotBoxVoteParameters, PoolConfig, POOL_CONFIG}, - spec_token::TokenIdKind, + pool_config::{PoolConfig, POOL_CONFIG}, + spec_token::{RewardTokenId, SpecToken, TokenIdKind}, wallet::{WalletDataError, WalletDataSource}, }; use derive_more::From; @@ -76,8 +76,7 @@ pub fn update_pool( wallet: &dyn WalletDataSource, tx_signer: &dyn SignTransaction, tx_submit: &dyn SubmitTransaction, - new_pool_box_hash_str: Option, - new_reward_tokens: Option, + new_reward_tokens: Option>, height: BlockHeight, ) -> Result<(), UpdatePoolError> { info!("Opening pool_config_updated.yaml"); @@ -104,32 +103,46 @@ pub fn update_pool( new_reward_tokens.clone(), ); - if new_pool_box_hash_str.is_none() { - println!( - "Run ./oracle-core --new_pool_box_hash {} to update pool", - String::from(new_pool_box_hash) - ); - return Ok(()); - } - let tx = build_update_pool_box_tx( op.get_pool_box_source(), op.get_ballot_boxes_source(), wallet, op.get_update_box_source(), new_pool_contract, - new_reward_tokens, + new_reward_tokens.clone(), height, change_address, )?; + log::debug!("Signing update pool box tx: {:#?}", tx); let signed_tx = tx_signer.sign_transaction(&tx.spending_tx)?; - let tx_id_str = tx_submit.submit_transaction(&signed_tx)?; - crate::explorer_api::wait_for_tx_confirmation(signed_tx.id()); + println!( - "Update pool box transaction submitted: view here, {}", - ergo_explorer_transaction_link(tx_id_str, network_prefix) + "YOU WILL BE SUBMITTING AN UPDATE TO THE POOL CONTRACT:\ + - Hash of new pool box contract: {}", + String::from(new_pool_box_hash), ); + if let Some(reward_token) = new_reward_tokens { + println!( + " - Reward token Id: {}\ + - Reward token amount: {}", + String::from(reward_token.token_id.token_id()), + reward_token.amount.as_u64(), + ); + } + println!("TYPE 'YES' TO SUBMIT THE TRANSACTION."); + let mut input = String::new(); + std::io::stdin().read_line(&mut input)?; + if input.trim_end() == "YES" { + let tx_id_str = tx_submit.submit_transaction(&signed_tx)?; + crate::explorer_api::wait_for_tx_confirmation(signed_tx.id()); + println!( + "Update pool box transaction submitted: view here, {}", + ergo_explorer_transaction_link(tx_id_str, network_prefix) + ); + } else { + println!("Aborting the transaction.") + } Ok(()) } @@ -137,9 +150,9 @@ fn display_update_diff( old_pool_config: &PoolConfig, new_pool_config: &PoolConfig, old_pool_box: PoolBoxWrapper, - new_reward_tokens: Option, + new_reward_tokens: Option>, ) { - let new_tokens = new_reward_tokens.unwrap_or_else(|| old_pool_box.reward_token().into()); + let new_tokens = new_reward_tokens.unwrap_or_else(|| old_pool_box.reward_token()); let new_pool_contract = PoolContract::checked_load(&new_pool_config.pool_box_wrapper_inputs.contract_inputs) .unwrap(); @@ -189,7 +202,7 @@ fn build_update_pool_box_tx( wallet: &dyn WalletDataSource, update_box: &dyn UpdateBoxSource, new_pool_contract: PoolContract, - new_reward_tokens: Option, + new_reward_tokens: Option>, height: BlockHeight, change_address: Address, ) -> Result, UpdatePoolError> { @@ -202,13 +215,12 @@ fn build_update_pool_box_tx( .sigma_serialize_bytes() .unwrap(), ); - let reward_tokens = new_reward_tokens.unwrap_or_else(|| old_pool_box.reward_token().into()); let vote_parameters = CastBallotBoxVoteParameters { pool_box_address_hash: pool_box_hash, - reward_token_id: reward_tokens.token_id, - reward_token_quantity: *reward_tokens.amount.as_u64(), + reward_token_opt: new_reward_tokens.clone(), update_box_creation_height: update_box.get_box().creation_height as i32, }; + let reward_tokens = new_reward_tokens.unwrap_or_else(|| old_pool_box.reward_token()); // Find ballot boxes that are voting for the new pool hash let mut sorted_ballot_boxes = ballot_boxes.get_ballot_boxes()?; // Sort in descending order of ballot token amounts. If two boxes have the same amount of ballot tokens, also compare box value, in case some boxes were incorrectly created below minStorageRent @@ -278,11 +290,12 @@ fn build_update_pool_box_tx( } let target_balance = *BASE_FEE; - let target_tokens = if reward_tokens.token_id != old_pool_box.reward_token().token_id() { - vec![reward_tokens.clone()] - } else { - vec![] - }; + let target_tokens = + if reward_tokens.token_id.token_id() != old_pool_box.reward_token().token_id() { + vec![reward_tokens.clone().into()] + } else { + vec![] + }; let box_selector = SimpleBoxSelector::new(); let selection = box_selector.select(unspent_boxes, target_balance, &target_tokens)?; let mut input_boxes = vec![old_pool_box.get_box().clone(), update_box.get_box().clone()]; @@ -321,7 +334,7 @@ fn build_update_pool_box_tx( change_address, ); - if reward_tokens.token_id != old_pool_box.reward_token().token_id() { + if reward_tokens.token_id.token_id() != old_pool_box.reward_token().token_id() { tx_builder.set_token_burn_permit(vec![old_pool_box.reward_token().into()]); } @@ -379,7 +392,7 @@ mod tests { generate_token_ids, make_wallet_unspent_box, BallotBoxesMock, PoolBoxMock, UpdateBoxMock, WalletDataMock, }, - spec_token::{RefreshTokenId, SpecToken, TokenIdKind}, + spec_token::{RefreshTokenId, RewardTokenId, SpecToken, TokenIdKind}, }; use super::build_update_pool_box_tx; @@ -405,8 +418,8 @@ mod tests { token_id: token_ids.reward_token_id.clone(), amount: 1500.try_into().unwrap(), }; - let new_reward_tokens = Token { - token_id: force_any_tokenid(), + let new_reward_tokens = SpecToken { + token_id: RewardTokenId::from_token_id_unchecked(force_any_tokenid()), amount: force_any_val(), }; dbg!(&new_reward_tokens); @@ -498,7 +511,7 @@ mod tests { amount: 1.try_into().unwrap(), }, pool_box_hash, - new_reward_tokens.clone(), + Some(new_reward_tokens.clone()), ballot_contract.min_storage_rent(), height, ) @@ -524,7 +537,7 @@ mod tests { // create a wallet box with new reward tokens secret.public_image(), BASE_FEE.checked_mul_u32(4_000_000_000).unwrap(), - Some(vec![new_reward_tokens.clone()].try_into().unwrap()), + Some(vec![new_reward_tokens.clone().into()].try_into().unwrap()), ); let change_address = AddressEncoder::unchecked_parse_network_address_from_str( "9iHyKxXs2ZNLMp9N9gbUT9V8gTbsV7HED1C1VhttMfBUMPDyF7r", diff --git a/core/src/cli_commands/vote_update_pool.rs b/core/src/cli_commands/vote_update_pool.rs index f7132b32..278e56be 100644 --- a/core/src/cli_commands/vote_update_pool.rs +++ b/core/src/cli_commands/vote_update_pool.rs @@ -7,10 +7,7 @@ use ergo_lib::{ }, ergo_chain_types::{Digest32, DigestNError}, ergotree_interpreter::sigma_protocol::prover::ContextExtension, - ergotree_ir::chain::{ - address::Address, - token::{Token, TokenAmount, TokenId}, - }, + ergotree_ir::chain::address::Address, wallet::{ box_selector::{BoxSelection, BoxSelector, BoxSelectorError, SimpleBoxSelector}, tx_builder::{TxBuilder, TxBuilderError}, @@ -20,16 +17,16 @@ use ergo_node_interface::node_interface::NodeError; use crate::{ box_kind::{make_local_ballot_box_candidate, BallotBox, BallotBoxWrapper}, - cli_commands::ergo_explorer_transaction_link, contracts::ballot::{ BallotContract, BallotContractError, BallotContractInputs, BallotContractParameters, }, + explorer_api::ergo_explorer_transaction_link, node_interface::{SignTransaction, SubmitTransaction}, oracle_config::{BASE_FEE, ORACLE_CONFIG}, oracle_state::{LocalBallotBoxSource, StageError}, oracle_types::BlockHeight, pool_config::{TokenIds, POOL_CONFIG}, - spec_token::SpecToken, + spec_token::{RewardTokenId, SpecToken, TokenIdKind}, wallet::{WalletDataError, WalletDataSource}, }; use derive_more::From; @@ -68,15 +65,13 @@ pub fn vote_update_pool( tx_submit: &dyn SubmitTransaction, local_ballot_box_source: &dyn LocalBallotBoxSource, new_pool_box_address_hash_str: String, - reward_token_id_str: String, - reward_token_amount: u32, + reward_token_opt: Option>, update_box_creation_height: BlockHeight, height: BlockHeight, ) -> Result<(), VoteUpdatePoolError> { let change_network_address = wallet.get_change_address()?; let network_prefix = change_network_address.network(); let new_pool_box_address_hash = Digest32::try_from(new_pool_box_address_hash_str)?; - let reward_token_id: TokenId = Digest32::try_from(reward_token_id_str)?.into(); let unsigned_tx = if let Some(local_ballot_box) = local_ballot_box_source.get_ballot_box()? { // Note: the ballot box contains the ballot token, but the box is guarded by the contract, // which stipulates that the address in R4 is the 'owner' of the token @@ -84,8 +79,7 @@ pub fn vote_update_pool( local_ballot_box, wallet, new_pool_box_address_hash, - reward_token_id, - reward_token_amount, + reward_token_opt.clone(), update_box_creation_height, height, change_network_address.address(), @@ -95,8 +89,7 @@ pub fn vote_update_pool( build_tx_for_first_ballot_box( wallet, new_pool_box_address_hash, - reward_token_id, - reward_token_amount, + reward_token_opt.clone(), update_box_creation_height, ORACLE_CONFIG.oracle_address.address(), POOL_CONFIG @@ -110,15 +103,18 @@ pub fn vote_update_pool( }; println!( "YOU WILL BE CASTING A VOTE FOR THE FOLLOWING ITEMS:\ - - Hash of new pool box address: {}\ - - Reward token Id: {}\ - - Reward token amount: {}\n - TYPE 'YES' TO INITIATE THE TRANSACTION. - ", + - Hash of new pool box contract: {}", String::from(new_pool_box_address_hash), - String::from(reward_token_id), - reward_token_amount, ); + if let Some(reward_token) = reward_token_opt { + println!( + " - Reward token Id: {}\ + - Reward token amount: {}", + String::from(reward_token.token_id.token_id()), + reward_token.amount.as_u64(), + ); + } + println!("TYPE 'YES' TO INITIATE THE TRANSACTION."); let mut input = String::new(); std::io::stdin().read_line(&mut input)?; if input.trim_end() == "YES" { @@ -140,24 +136,19 @@ fn build_tx_with_existing_ballot_box( in_ballot_box: BallotBoxWrapper, wallet: &dyn WalletDataSource, new_pool_box_address_hash: Digest32, - reward_token_id: TokenId, - reward_token_amount: u32, + reward_token_opt: Option>, update_box_creation_height: BlockHeight, height: BlockHeight, change_address: Address, ) -> Result { let unspent_boxes = wallet.get_unspent_wallet_boxes()?; - let reward_token = Token { - token_id: reward_token_id, - amount: TokenAmount::try_from(reward_token_amount as u64).unwrap(), - }; let ballot_box_candidate = make_local_ballot_box_candidate( in_ballot_box.contract(), in_ballot_box.ballot_token_owner(), update_box_creation_height, in_ballot_box.ballot_token(), new_pool_box_address_hash, - reward_token, + reward_token_opt, in_ballot_box.get_box().value, height, )?; @@ -189,8 +180,7 @@ fn build_tx_with_existing_ballot_box( fn build_tx_for_first_ballot_box( wallet: &dyn WalletDataSource, new_pool_box_address_hash: Digest32, - reward_token_id: TokenId, - reward_token_amount: u32, + reward_token_opt: Option>, update_box_creation_height: BlockHeight, ballot_token_owner_address: Address, ballot_contract_parameters: &BallotContractParameters, @@ -200,10 +190,6 @@ fn build_tx_for_first_ballot_box( ) -> Result { let unspent_boxes = wallet.get_unspent_wallet_boxes()?; let out_ballot_box_value = ballot_contract_parameters.min_storage_rent(); - let reward_token = Token { - token_id: reward_token_id, - amount: TokenAmount::try_from(reward_token_amount as u64).unwrap(), - }; let inputs = BallotContractInputs::build_with( ballot_contract_parameters.clone(), token_ids.update_nft_token_id.clone(), @@ -220,7 +206,7 @@ fn build_tx_for_first_ballot_box( update_box_creation_height, ballot_token.clone(), new_pool_box_address_hash, - reward_token, + reward_token_opt, out_ballot_box_value, height, )?; @@ -279,7 +265,7 @@ mod tests { pool_commands::test_utils::{ find_input_boxes, generate_token_ids, make_wallet_unspent_box, WalletDataMock, }, - spec_token::{SpecToken, TokenIdKind}, + spec_token::{RewardTokenId, SpecToken, TokenIdKind}, wallet::WalletDataSource, }; @@ -319,12 +305,14 @@ mod tests { change_address: change_address.clone(), }; - let new_reward_token_id = force_any_val::(); + let new_reward_token = SpecToken { + token_id: RewardTokenId::from_token_id_unchecked(force_any_val::()), + amount: 100_000.try_into().unwrap(), + }; let unsigned_tx = build_tx_for_first_ballot_box( &wallet_mock, new_pool_box_address_hash, - new_reward_token_id, - 100_000, + Some(new_reward_token), BlockHeight(height.0) - 3, change_address.address(), ballot_contract_inputs.contract_parameters(), @@ -378,10 +366,10 @@ mod tests { height - EpochLength(2), ballot_token, new_pool_box_address_hash, - Token { - token_id: token_ids.reward_token_id.token_id(), + Some(SpecToken { + token_id: token_ids.reward_token_id.clone(), amount: 100_000.try_into().unwrap(), - }, + }), BoxValue::new(10_000_000).unwrap(), height - EpochLength(2), ) @@ -409,8 +397,10 @@ mod tests { ballot_box, &wallet_mock, new_pool_box_address_hash, - token_ids.reward_token_id.token_id(), - 100_000, + Some(SpecToken { + token_id: token_ids.reward_token_id, + amount: 100_000.try_into().unwrap(), + }), height - EpochLength(3), height, change_address.address(), diff --git a/core/src/contracts/ballot.rs b/core/src/contracts/ballot.rs index 77bd17d1..6aa2ca5e 100644 --- a/core/src/contracts/ballot.rs +++ b/core/src/contracts/ballot.rs @@ -98,16 +98,18 @@ impl BallotContract { fn build_with(inputs: &BallotContractInputs) -> Result { let parameters = inputs.contract_parameters.clone(); - let ergo_tree = - ErgoTree::sigma_parse_bytes(inputs.contract_parameters.ergo_tree_bytes.as_slice())? - .with_constant( - parameters.min_storage_rent_index, - parameters.min_storage_rent.into(), - )? - .with_constant( - parameters.update_nft_index, - inputs.update_nft_token_id.token_id().into(), - )?; + let ergo_tree_orig = + ErgoTree::sigma_parse_bytes(inputs.contract_parameters.ergo_tree_bytes.as_slice())?; + log::debug!("ballot contract ergo_tree_orig: {:#?}", ergo_tree_orig); + let ergo_tree = ergo_tree_orig + .with_constant( + parameters.min_storage_rent_index, + parameters.min_storage_rent.into(), + )? + .with_constant( + parameters.update_nft_index, + inputs.update_nft_token_id.token_id().into(), + )?; let contract = Self::from_ergo_tree(ergo_tree, inputs)?; Ok(contract) } diff --git a/core/src/contracts/oracle.rs b/core/src/contracts/oracle.rs index 31bcd360..edd8a813 100644 --- a/core/src/contracts/oracle.rs +++ b/core/src/contracts/oracle.rs @@ -254,8 +254,10 @@ impl OracleContractParameters { min_storage_rent_index: usize, min_storage_rent: BoxValue, ) -> Result { - let ergo_tree = ErgoTree::sigma_parse_bytes(ergo_tree_bytes.as_slice())? - .with_constant(min_storage_rent_index, min_storage_rent.into())?; + let ergo_tree_orig = ErgoTree::sigma_parse_bytes(ergo_tree_bytes.as_slice())?; + log::debug!("oracle contract ergo_tree_orig: {:#?}", ergo_tree_orig); + let ergo_tree = + ergo_tree_orig.with_constant(min_storage_rent_index, min_storage_rent.into())?; let _pool_nft = ergo_tree .get_constant(pool_nft_index) diff --git a/core/src/contracts/pool.rs b/core/src/contracts/pool.rs index d57c0227..d06df724 100644 --- a/core/src/contracts/pool.rs +++ b/core/src/contracts/pool.rs @@ -99,16 +99,18 @@ impl PoolContract { } pub fn build_with(inputs: &PoolContractInputs) -> Result { - let ergo_tree = - ErgoTree::sigma_parse_bytes(inputs.contract_parameters.ergo_tree_bytes.as_slice())? - .with_constant( - inputs.contract_parameters.refresh_nft_index, - inputs.refresh_nft_token_id.token_id().into(), - )? - .with_constant( - inputs.contract_parameters.update_nft_index, - inputs.update_nft_token_id.token_id().into(), - )?; + let ergo_tree_orig = + ErgoTree::sigma_parse_bytes(inputs.contract_parameters.ergo_tree_bytes.as_slice())?; + log::debug!("pool contract ergo_tree_orig: {:#?}", ergo_tree_orig); + let ergo_tree = ergo_tree_orig + .with_constant( + inputs.contract_parameters.refresh_nft_index, + inputs.refresh_nft_token_id.token_id().into(), + )? + .with_constant( + inputs.contract_parameters.update_nft_index, + inputs.update_nft_token_id.token_id().into(), + )?; let contract = Self::from_ergo_tree(ergo_tree, inputs)?; Ok(contract) } diff --git a/core/src/contracts/refresh.rs b/core/src/contracts/refresh.rs index cdba886d..0e2abf48 100644 --- a/core/src/contracts/refresh.rs +++ b/core/src/contracts/refresh.rs @@ -443,7 +443,9 @@ impl RefreshContractParameters { pub fn build_with( inputs: RefreshContractParametersInputs, ) -> Result { - let ergo_tree = ErgoTree::sigma_parse_bytes(inputs.ergo_tree_bytes.as_slice())? + let ergo_tree_orig = ErgoTree::sigma_parse_bytes(inputs.ergo_tree_bytes.as_slice())?; + log::debug!("refresh contract ergo_tree_orig: {:#?}", ergo_tree_orig); + let ergo_tree = ergo_tree_orig .with_constant( inputs.min_data_points_index, inputs.min_data_points.0.into(), diff --git a/core/src/contracts/update.rs b/core/src/contracts/update.rs index 8ab14a21..0af5ef73 100644 --- a/core/src/contracts/update.rs +++ b/core/src/contracts/update.rs @@ -260,7 +260,9 @@ impl UpdateContractParameters { min_votes_index: usize, min_votes: u64, ) -> Result { - let ergo_tree = ErgoTree::sigma_parse_bytes(ergo_tree_bytes.as_slice())? + let ergo_tree_orig = ErgoTree::sigma_parse_bytes(ergo_tree_bytes.as_slice())?; + log::debug!("update contract ergo_tree_orig: {:#?}", ergo_tree_orig); + let ergo_tree = ergo_tree_orig .with_constant(min_votes_index, (min_votes as i32).into()) .map_err(UpdateContractParametersError::ErgoTreeConstant)?; let _pool_nft = ergo_tree diff --git a/core/src/default_parameters.rs b/core/src/default_parameters.rs index 4729e576..28f57a17 100644 --- a/core/src/default_parameters.rs +++ b/core/src/default_parameters.rs @@ -91,11 +91,11 @@ impl Default for RefreshContractParameters { impl Default for UpdateContractParameters { fn default() -> Self { // compiled via - // https://scastie.scala-lang.org/BxJFCRDcSCeiwf9ZgKdymQ - let ergo_tree_bytes = base16::decode("100e040004000400040204020e20472b4b6250655368566d597133743677397a24432646294a404d635166546a570400040004000e203f4428472d4b6150645367566b5970337336763979244226452948404d625165010005000400040cd806d601b2a4730000d602b2db63087201730100d603b2a5730200d604db63087203d605b2a5730300d606b27204730400d1ededed938c7202017305edededed937202b2720473060093c17201c1720393c672010405c67203040593c672010504c672030504efe6c672030661edededed93db63087205db6308a793c27205c2a792c17205c1a7918cc77205018cc7a701efe6c67205046192b0b5a4d9010763d801d609db630872079591b172097307edededed938cb2720973080001730993e4c6720705048cc7a70193e4c67207060ecbc2720393e4c67207070e8c72060193e4c6720708058c720602730a730bd9010741639a8c7207018cb2db63088c720702730c00027e730d05").unwrap(); - let pool_nft_index = 5; - let ballot_token_index = 9; - let min_votes_index = 13; + // https://scastie.scala-lang.org/LjGBkqExRc2vCjmDKGLxWg + let ergo_tree_bytes = base16::decode("100f0400040004000402040204020e20472b4b6250655368566d597133743677397a24432646294a404d635166546a570400040004000e203f4428472d4b6150645367566b5970337336763979244226452948404d625165010005000400040cd80ad601b2a4730000d602db63087201d603b27202730100d604b2a5730200d605db63087204d606b2a5730300d607b27205730400d6088c720701d6098c720702d60ab27202730500d1ededed938c7203017306edededed937203b2720573070093c17201c1720493c672010405c67204040593c672010504c672040504efe6c672040661edededed93db63087206db6308a793c27206c2a792c17206c1a7918cc77206018cc7a701efe6c67206046192b0b5a4d9010b63d801d60ddb6308720b9591b1720d7308d801d60ec6720b070eededed938cb2720d73090001730a93e4c6720b05048cc7a70193e4c6720b060ecbc2720495ede6720ee6c6720b0805ed93e4720e720893e4c6720b08057209ed938c720a017208938c720a027209730b730cd9010b41639a8c720b018cb2db63088c720b02730d00027e730e05").unwrap(); + let pool_nft_index = 6; + let ballot_token_index = 10; + let min_votes_index = 14; let min_votes = 6; UpdateContractParameters::checked_load( ergo_tree_bytes, @@ -161,7 +161,7 @@ mod tests { let expected_refresh_encoding = "cs5c5QEirstI4ZlTyrbTjlPwWYHRW+QsedtpyOSBnH4="; let expected_oracle_encoding = "fhOYLO3s+NJCqTQDWUz0E+ffy2T1VG7ZnhSFs0RP948="; let expected_ballot_encoding = "2DnK+72bh+TxviNk8XfuYzLKtuF5jnqUJOzimt30NvI="; - let expected_update_encoding = "3aIVTP5tRgCZHxaT3ZFw3XubRV5DJi0rKeo9bKVHlVw="; + let expected_update_encoding = "pQ7Dgjq1pUyISroP+RWEDf+kVNYAWjeFHzW+cpImhsQ="; println!("BASE 64 ENCODING OF BLAKE2B HASH OF CONTRACT ERGO-TREE BYTES"); println!("------------------------------------------------------------\n"); diff --git a/core/src/explorer_api.rs b/core/src/explorer_api.rs index d7cffc46..acf56e3a 100644 --- a/core/src/explorer_api.rs +++ b/core/src/explorer_api.rs @@ -7,11 +7,17 @@ use ergo_lib::ergotree_ir::chain::address::NetworkPrefix; use reqwest::blocking::RequestBuilder; use reqwest::blocking::Response; use reqwest::header::CONTENT_TYPE; +use reqwest::Url; use thiserror::Error; use url::ParseError; use crate::oracle_config::ORACLE_CONFIG; +use self::explorer_url::default_explorer_api_url; +use self::explorer_url::default_explorer_url; + +pub mod explorer_url; + #[derive(Debug, From, Error)] pub enum ExplorerApiError { #[error("reqwest error: {0}")] @@ -27,10 +33,8 @@ pub struct ExplorerApi { } impl ExplorerApi { - pub fn new(url: &str) -> Result { - Ok(Self { - url: url::Url::parse(url)?, - }) + pub fn new(url: Url) -> Self { + Self { url } } /// Sets required headers for a request @@ -63,6 +67,19 @@ impl ExplorerApi { } } +pub(crate) fn ergo_explorer_transaction_link(tx_id: TxId, prefix: NetworkPrefix) -> String { + let url = ORACLE_CONFIG + .explorer_url + .clone() + .unwrap_or_else(|| default_explorer_url(prefix)); + let tx_id_str = String::from(tx_id); + url.join("en/transactions/") + .unwrap() + .join(&tx_id_str) + .unwrap(); + url.to_string() +} + pub fn wait_for_tx_confirmation(tx_id: TxId) { wait_for_txs_confirmation(vec![tx_id]); } @@ -70,12 +87,11 @@ pub fn wait_for_tx_confirmation(tx_id: TxId) { pub fn wait_for_txs_confirmation(tx_ids: Vec) { let network = ORACLE_CONFIG.oracle_address.network(); let timeout = Duration::from_secs(1200); - let explorer_api = match network { - NetworkPrefix::Mainnet => ExplorerApi::new("https://api.ergoplatform.com/").unwrap(), - NetworkPrefix::Testnet => { - ExplorerApi::new("https://api-testnet.ergoplatform.com/").unwrap() - } - }; + let explorer_url = ORACLE_CONFIG + .explorer_url + .clone() + .unwrap_or_else(|| default_explorer_api_url(network)); + let explorer_api = ExplorerApi::new(explorer_url); let start_time = std::time::Instant::now(); println!("Waiting for block confirmation from ExplorerApi for tx ids: {tx_ids:?} ..."); let mut remaining_txs = tx_ids.clone(); diff --git a/core/src/explorer_api/explorer_url.rs b/core/src/explorer_api/explorer_url.rs new file mode 100644 index 00000000..0126e953 --- /dev/null +++ b/core/src/explorer_api/explorer_url.rs @@ -0,0 +1,24 @@ +use ergo_lib::ergotree_ir::chain::address::NetworkPrefix; +use reqwest::Url; + +pub const MAINNET_EXPLORER_API_URL: &str = "https://api.ergoplatform.com/"; +pub const TESTNET_EXPLORER_API_URL: &str = "https://api-testnet.ergoplatform.com/"; + +pub const MAINNET_EXPLORER_URL: &str = "https://explorer.ergoplatform.com/"; +pub const TESTNET_EXPLORER_URL: &str = "https://testnet.ergoplatform.com/"; + +pub fn default_explorer_api_url(network_prefix: NetworkPrefix) -> Url { + let url_str = match network_prefix { + NetworkPrefix::Mainnet => MAINNET_EXPLORER_API_URL, + NetworkPrefix::Testnet => TESTNET_EXPLORER_API_URL, + }; + Url::parse(url_str).unwrap() +} + +pub fn default_explorer_url(network_prefix: NetworkPrefix) -> Url { + let url_str = match network_prefix { + NetworkPrefix::Mainnet => MAINNET_EXPLORER_URL, + NetworkPrefix::Testnet => TESTNET_EXPLORER_URL, + }; + Url::parse(url_str).unwrap() +} diff --git a/core/src/main.rs b/core/src/main.rs index fcd5f31b..0fdd3d76 100644 --- a/core/src/main.rs +++ b/core/src/main.rs @@ -51,7 +51,7 @@ use ergo_lib::ergo_chain_types::Digest32; use ergo_lib::ergotree_ir::chain::address::Address; use ergo_lib::ergotree_ir::chain::address::NetworkAddress; use ergo_lib::ergotree_ir::chain::address::NetworkPrefix; -use ergo_lib::ergotree_ir::chain::token::Token; +use ergo_lib::ergotree_ir::chain::token::TokenAmount; use ergo_lib::ergotree_ir::chain::token::TokenId; use log::error; use log::LevelFilter; @@ -68,10 +68,12 @@ use pool_commands::PoolCommandError; use pool_config::DEFAULT_POOL_CONFIG_FILE_NAME; use pool_config::POOL_CONFIG; use scans::get_scans_file_path; +use spec_token::RewardTokenId; +use spec_token::SpecToken; +use spec_token::TokenIdKind; use state::process; use state::PoolState; use std::convert::TryFrom; -use std::convert::TryInto; use std::env; use std::path::Path; use std::path::PathBuf; @@ -161,22 +163,20 @@ enum Command { VoteUpdatePool { /// The base16-encoded blake2b hash of the serialized pool box contract for the new pool box. new_pool_box_address_hash_str: String, - /// The base16-encoded reward token id of the new pool box (use existing if unchanged) - reward_token_id_str: String, - /// The reward token amount in the pool box at the time of update transaction is committed. - reward_token_amount: u32, /// The creation height of the existing update box. update_box_creation_height: u32, + /// The base16-encoded reward token id of the new pool box (if minted) + reward_token_id_str: Option, + /// The reward token amount in the pool box at the time of update transaction is committed (if minted). + reward_token_amount: Option, }, /// Initiate the Update Pool transaction. - /// Run with no arguments to show diff between oracle_config.yaml and oracle_config_updated.yaml - /// Updated config file must be created using --prepare-update command first + /// Updated config file `pool_config_updated.yaml` is expected to be in the current directory + /// and must be created using --prepare-update command first UpdatePool { - /// New pool box hash. Must match hash of updated pool contract - new_pool_box_hash: Option, - /// New reward token id (optional, base64) + /// New reward token id (only if minted) reward_token_id: Option, - /// New reward token amount, required if new token id was voted for + /// New reward token amount (only if minted) reward_token_amount: Option, }, /// Prepare updating oracle pool with new contracts/parameters. @@ -382,14 +382,14 @@ fn handle_pool_command( reward_token_amount, update_box_creation_height, } => { + let reward_token_opt = check_reward_token_opt(reward_token_id_str, reward_token_amount); if let Err(e) = cli_commands::vote_update_pool::vote_update_pool( &node_api, &node_api.node, &node_api.node, op.get_local_ballot_box_source(), new_pool_box_address_hash_str, - reward_token_id_str, - reward_token_amount, + reward_token_opt, BlockHeight(update_box_creation_height), height, ) { @@ -398,24 +398,16 @@ fn handle_pool_command( } } Command::UpdatePool { - new_pool_box_hash, reward_token_id, reward_token_amount, } => { - let new_reward_tokens = - reward_token_id - .zip(reward_token_amount) - .map(|(token_id, amount)| Token { - token_id: TokenId::from(Digest32::try_from(token_id).unwrap()), - amount: amount.try_into().unwrap(), - }); + let reward_token_opt = check_reward_token_opt(reward_token_id, reward_token_amount); if let Err(e) = cli_commands::update_pool::update_pool( &op, &node_api, &node_api.node, &node_api.node, - new_pool_box_hash, - new_reward_tokens, + reward_token_opt, height, ) { error!("Fatal update-pool error: {}", e); @@ -533,3 +525,26 @@ fn log_on_launch() { log::info!("Oracle address: {}", config.oracle_address.to_base58()); } } + +fn check_reward_token_opt( + reward_token_id_str: Option, + reward_token_amount: Option, +) -> Option> { + let reward_token_opt = match (reward_token_id_str, reward_token_amount) { + (None, None) => None, + (None, Some(_)) => { + panic!("reward_token_amount is set, but reward_token_id is not set") + } + (Some(_), None) => { + panic!("reward_token_id is set, but reward_token_amount is not set") + } + (Some(reward_token_id_str), Some(reward_token_amount)) => Some({ + let reward_token_id: TokenId = Digest32::try_from(reward_token_id_str).unwrap().into(); + SpecToken { + token_id: RewardTokenId::from_token_id_unchecked(reward_token_id), + amount: TokenAmount::try_from(reward_token_amount).unwrap(), + } + }), + }; + reward_token_opt +} diff --git a/core/src/oracle_config.rs b/core/src/oracle_config.rs index c410c06b..c72f3efd 100644 --- a/core/src/oracle_config.rs +++ b/core/src/oracle_config.rs @@ -15,6 +15,8 @@ use reqwest::Url; use serde::{Deserialize, Serialize}; use thiserror::Error; +use crate::explorer_api::explorer_url::default_explorer_api_url; + pub const DEFAULT_ORACLE_CONFIG_FILE_NAME: &str = "oracle_config.yaml"; #[derive(Debug, Clone, Deserialize, Serialize)] @@ -26,6 +28,7 @@ pub struct OracleConfig { pub core_api_port: u16, pub oracle_address: NetworkAddress, pub data_point_source_custom_script: Option, + pub explorer_url: Option, } impl OracleConfig { @@ -73,13 +76,14 @@ impl Default for OracleConfig { ) .unwrap(); Self { - oracle_address: address, + oracle_address: address.clone(), node_api_key: "hello".into(), core_api_port: 9010, data_point_source_custom_script: None, base_fee: *tx_builder::SUGGESTED_TX_FEE().as_u64(), log_level: LevelFilter::Info.into(), node_url: Url::parse("http://127.0.0.1:9053").unwrap(), + explorer_url: Some(default_explorer_api_url(address.network())), } } } diff --git a/core/src/pool_commands/publish_datapoint.rs b/core/src/pool_commands/publish_datapoint.rs index 3a8c8ea0..fcc07ea5 100644 --- a/core/src/pool_commands/publish_datapoint.rs +++ b/core/src/pool_commands/publish_datapoint.rs @@ -239,6 +239,7 @@ mod tests { .contract_parameters() .min_storage_rent, height - EpochLength(99), + 100, ), &oracle_box_wrapper_inputs, ) diff --git a/core/src/pool_commands/refresh.rs b/core/src/pool_commands/refresh.rs index 6158add6..6db602d7 100644 --- a/core/src/pool_commands/refresh.rs +++ b/core/src/pool_commands/refresh.rs @@ -427,6 +427,7 @@ mod tests { token_ids, value, creation_height, + 100, ), &oracle_box_wrapper_inputs, ) diff --git a/core/src/pool_commands/test_utils.rs b/core/src/pool_commands/test_utils.rs index e9e0ad53..ac01be81 100644 --- a/core/src/pool_commands/test_utils.rs +++ b/core/src/pool_commands/test_utils.rs @@ -195,6 +195,7 @@ pub(crate) fn make_datapoint_box( token_ids: &TokenIds, value: BoxValue, creation_height: BlockHeight, + reward_token_amount: u64, ) -> ErgoBox { let tokens = vec![ Token::from(( @@ -203,7 +204,7 @@ pub(crate) fn make_datapoint_box( )), Token::from(( token_ids.reward_token_id.token_id(), - 100u64.try_into().unwrap(), + reward_token_amount.try_into().unwrap(), )), ] .try_into() diff --git a/core/src/pool_config.rs b/core/src/pool_config.rs index 9aa7c3c1..b914bacc 100644 --- a/core/src/pool_config.rs +++ b/core/src/pool_config.rs @@ -3,8 +3,6 @@ use std::path::PathBuf; use anyhow::anyhow; use derive_more::From; -use ergo_lib::ergo_chain_types::Digest32; -use ergo_lib::ergotree_ir::chain::token::TokenId; use once_cell::sync; use serde::Deserialize; use serde::Serialize; @@ -51,14 +49,6 @@ pub struct PoolConfig { pub token_ids: TokenIds, } -#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] -pub struct CastBallotBoxVoteParameters { - pub pool_box_address_hash: Digest32, - pub reward_token_id: TokenId, - pub reward_token_quantity: u64, - pub update_box_creation_height: i32, -} - #[derive(serde::Serialize, serde::Deserialize, Debug, Copy, Clone)] #[allow(clippy::enum_variant_names)] pub enum PredefinedDataPointSource { diff --git a/rust-toolchain b/rust-toolchain index 5b6cd6b3..0403bed1 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -1.65 +1.66.1