Skip to content

Commit 2d26617

Browse files
authored
Merge pull request #80 from SethDusek/updatepool
Update Pool Box
2 parents 3dac8f9 + a59227f commit 2d26617

File tree

19 files changed

+1740
-85
lines changed

19 files changed

+1740
-85
lines changed

core/src/box_kind.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ mod ballot_box;
22
mod oracle_box;
33
mod pool_box;
44
mod refresh_box;
5+
mod update_box;
56

67
pub use ballot_box::*;
78
pub use oracle_box::*;
89
pub use pool_box::*;
910
pub use refresh_box::*;
11+
pub use update_box::*;

core/src/box_kind/ballot_box.rs

Lines changed: 145 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use std::convert::TryInto;
2-
31
use crate::{
42
contracts::ballot::{BallotContract, BallotContractError},
53
oracle_config::{BallotBoxWrapperParameters, CastBallotBoxVoteParameters},
@@ -59,23 +57,14 @@ pub trait BallotBox {
5957
fn get_box(&self) -> &ErgoBox;
6058
}
6159

62-
#[derive(Clone)]
60+
#[derive(Clone, Debug)]
6361
pub struct BallotBoxWrapper {
6462
ergo_box: ErgoBox,
6563
contract: BallotContract,
6664
}
6765

6866
impl BallotBoxWrapper {
6967
pub fn new(ergo_box: ErgoBox, inputs: BallotBoxWrapperInputs) -> Result<Self, BallotBoxError> {
70-
let CastBallotBoxVoteParameters {
71-
reward_token_id,
72-
reward_token_quantity,
73-
pool_box_address_hash,
74-
} = inputs
75-
.parameters
76-
.vote_parameters
77-
.as_ref()
78-
.ok_or(BallotBoxError::ExpectedVoteCast)?;
7968
let ballot_token_id = &ergo_box
8069
.tokens
8170
.as_ref()
@@ -98,42 +87,54 @@ impl BallotBoxWrapper {
9887
return Err(BallotBoxError::UnexpectedGroupElementInR4);
9988
}
10089

101-
if ergo_box
102-
.get_register(NonMandatoryRegisterId::R5.into())
103-
.ok_or(BallotBoxError::NoUpdateBoxCreationHeightInR5)?
104-
.try_extract_into::<i32>()
105-
.is_err()
90+
if let Some(CastBallotBoxVoteParameters {
91+
reward_token_id,
92+
reward_token_quantity,
93+
pool_box_address_hash,
94+
update_box_creation_height,
95+
}) = inputs.parameters.vote_parameters.as_ref()
10696
{
107-
return Err(BallotBoxError::NoUpdateBoxCreationHeightInR5);
108-
}
97+
let register_update_box_creation_height = ergo_box
98+
.get_register(NonMandatoryRegisterId::R5.into())
99+
.ok_or(BallotBoxError::NoUpdateBoxCreationHeightInR5)?
100+
.try_extract_into::<i32>()?;
109101

110-
let register_pool_box_address_hash = ergo_box
111-
.get_register(NonMandatoryRegisterId::R6.into())
112-
.ok_or(BallotBoxError::NoPoolBoxAddressInR6)?
113-
.try_extract_into::<Digest32>()?;
114-
let pb: Digest32 = base16::decode(pool_box_address_hash)
115-
.unwrap()
116-
.try_into()
117-
.unwrap();
118-
if pb != register_pool_box_address_hash {
119-
warn!("Pool box address in R6 register differs to config. Could be due to vote.");
120-
}
102+
if register_update_box_creation_height != *update_box_creation_height {
103+
warn!("Update box creation height in R5 register differs to config. Could be due to vote.");
104+
}
121105

122-
let register_reward_token_id = ergo_box
123-
.get_register(NonMandatoryRegisterId::R7.into())
124-
.ok_or(BallotBoxError::NoRewardTokenIdInR7)?
125-
.try_extract_into::<TokenId>()?;
126-
if register_reward_token_id != *reward_token_id {
127-
warn!("Reward token id in R7 register differs to config. Could be due to vote.");
128-
}
106+
let register_pool_box_address_hash = ergo_box
107+
.get_register(NonMandatoryRegisterId::R6.into())
108+
.ok_or(BallotBoxError::NoPoolBoxAddressInR6)?
109+
.try_extract_into::<Digest32>()?;
129110

130-
let register_reward_token_quantity = ergo_box
131-
.get_register(NonMandatoryRegisterId::R8.into())
132-
.ok_or(BallotBoxError::NoRewardTokenQuantityInR8)?
133-
.try_extract_into::<i32>()? as u32;
111+
if *pool_box_address_hash != register_pool_box_address_hash {
112+
warn!("Pool box address in R6 register differs to config. Could be due to vote.");
113+
}
114+
115+
let register_reward_token_id = ergo_box
116+
.get_register(NonMandatoryRegisterId::R7.into())
117+
.ok_or(BallotBoxError::NoRewardTokenIdInR7)?
118+
.try_extract_into::<TokenId>()?;
119+
120+
if register_reward_token_id != *reward_token_id {
121+
warn!("Reward token id in R7 register differs to config. Could be due to vote.");
122+
}
134123

135-
if register_reward_token_quantity != *reward_token_quantity {
136-
warn!("Reward token quantity in R8 register differs to config. Could be due to vote.");
124+
let register_reward_token_quantity: u64 = ergo_box
125+
.get_register(NonMandatoryRegisterId::R8.into())
126+
.ok_or(BallotBoxError::NoRewardTokenQuantityInR8)?
127+
.try_extract_into::<i64>()?
128+
as u64;
129+
130+
if register_reward_token_quantity != *reward_token_quantity {
131+
warn!(
132+
"Reward token quantity in R8 register differs to config. Could be due to vote."
133+
);
134+
}
135+
} else if ergo_box.additional_registers.len() > 1 {
136+
// If no vote parameter is provided, then the box must only have R4 (owner public key) defined
137+
return Err(BallotBoxError::ExpectedVoteCast);
137138
}
138139

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

154+
/// A Ballot Box with vote parameters guaranteed to be set
155+
#[derive(Clone, Debug)]
156+
pub struct VoteBallotBoxWrapper {
157+
ergo_box: ErgoBox,
158+
vote_parameters: CastBallotBoxVoteParameters,
159+
contract: BallotContract,
160+
}
161+
162+
impl VoteBallotBoxWrapper {
163+
pub fn new(ergo_box: ErgoBox, inputs: BallotBoxWrapperInputs) -> Result<Self, BallotBoxError> {
164+
let ballot_token_id = &ergo_box
165+
.tokens
166+
.as_ref()
167+
.ok_or(BallotBoxError::NoBallotToken)?
168+
.get(0)
169+
.ok_or(BallotBoxError::NoBallotToken)?
170+
.token_id;
171+
if *ballot_token_id != *inputs.ballot_token_id {
172+
return Err(BallotBoxError::UnknownBallotTokenId);
173+
}
174+
175+
if ergo_box
176+
.get_register(NonMandatoryRegisterId::R4.into())
177+
.ok_or(BallotBoxError::NoGroupElementInR4)?
178+
.try_extract_into::<EcPoint>()
179+
.is_err()
180+
{
181+
return Err(BallotBoxError::NoGroupElementInR4);
182+
}
183+
let update_box_creation_height = ergo_box
184+
.get_register(NonMandatoryRegisterId::R5.into())
185+
.ok_or(BallotBoxError::NoUpdateBoxCreationHeightInR5)?
186+
.try_extract_into::<i32>()?;
187+
188+
let pool_box_address_hash = ergo_box
189+
.get_register(NonMandatoryRegisterId::R6.into())
190+
.ok_or(BallotBoxError::NoPoolBoxAddressInR6)?
191+
.try_extract_into::<Digest32>()?;
192+
193+
let reward_token_id = ergo_box
194+
.get_register(NonMandatoryRegisterId::R7.into())
195+
.ok_or(BallotBoxError::NoRewardTokenIdInR7)?
196+
.try_extract_into::<TokenId>()?;
197+
let reward_token_quantity = ergo_box
198+
.get_register(NonMandatoryRegisterId::R8.into())
199+
.ok_or(BallotBoxError::NoRewardTokenQuantityInR8)?
200+
.try_extract_into::<i64>()? as u64;
201+
202+
let contract = BallotContract::from_ergo_tree(ergo_box.ergo_tree.clone(), inputs.into())?;
203+
let vote_parameters = CastBallotBoxVoteParameters {
204+
pool_box_address_hash,
205+
reward_token_id,
206+
reward_token_quantity,
207+
update_box_creation_height,
208+
};
209+
Ok(Self {
210+
ergo_box,
211+
contract,
212+
vote_parameters,
213+
})
214+
}
215+
216+
pub fn vote_parameters(&self) -> &CastBallotBoxVoteParameters {
217+
&self.vote_parameters
218+
}
219+
}
220+
153221
impl BallotBox for BallotBoxWrapper {
154222
fn contract(&self) -> &BallotContract {
155223
&self.contract
@@ -183,6 +251,39 @@ impl BallotBox for BallotBoxWrapper {
183251
}
184252
}
185253

254+
impl BallotBox for VoteBallotBoxWrapper {
255+
fn contract(&self) -> &BallotContract {
256+
&self.contract
257+
}
258+
259+
fn ballot_token(&self) -> Token {
260+
self.ergo_box
261+
.tokens
262+
.as_ref()
263+
.unwrap()
264+
.get(0)
265+
.unwrap()
266+
.clone()
267+
}
268+
269+
fn min_storage_rent(&self) -> u64 {
270+
self.contract.min_storage_rent()
271+
}
272+
273+
fn ballot_token_owner(&self) -> ProveDlog {
274+
self.ergo_box
275+
.get_register(NonMandatoryRegisterId::R4.into())
276+
.unwrap()
277+
.try_extract_into::<EcPoint>()
278+
.unwrap()
279+
.into()
280+
}
281+
282+
fn get_box(&self) -> &ErgoBox {
283+
&self.ergo_box
284+
}
285+
}
286+
186287
#[allow(clippy::too_many_arguments)]
187288
pub fn make_local_ballot_box_candidate(
188289
contract: &BallotContract,
@@ -210,7 +311,7 @@ pub fn make_local_ballot_box_candidate(
210311
);
211312
builder.set_register_value(
212313
NonMandatoryRegisterId::R8,
213-
(*reward_tokens.amount.as_u64() as i32).into(),
314+
(*reward_tokens.amount.as_u64() as i64).into(),
214315
);
215316
builder.add_token(ballot_token);
216317
builder.build()

core/src/box_kind/update_box.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
use ergo_lib::ergotree_ir::chain::ergo_box::ErgoBox;
2+
use ergo_lib::ergotree_ir::chain::token::Token;
3+
use ergo_lib::ergotree_ir::chain::token::TokenId;
4+
use ergo_lib::ergotree_ir::ergo_tree::ErgoTree;
5+
use thiserror::Error;
6+
7+
use crate::contracts::update::UpdateContract;
8+
use crate::contracts::update::UpdateContractError;
9+
use crate::contracts::update::UpdateContractParameters;
10+
11+
#[derive(Debug, Error)]
12+
pub enum UpdateBoxError {
13+
#[error("oracle box: no tokens found")]
14+
NoTokens,
15+
#[error("update contract: {0:?}")]
16+
UpdateContractError(#[from] UpdateContractError),
17+
#[error("update contract: {0:?}")]
18+
IncorrectUpdateTokenId(TokenId),
19+
}
20+
21+
#[derive(Clone)]
22+
pub struct UpdateBoxWrapper(ErgoBox, UpdateContract);
23+
24+
impl UpdateBoxWrapper {
25+
pub fn new(b: ErgoBox, inputs: UpdateBoxWrapperInputs) -> Result<Self, UpdateBoxError> {
26+
let update_token_id = b
27+
.tokens
28+
.as_ref()
29+
.ok_or(UpdateBoxError::NoTokens)?
30+
.get(0)
31+
.ok_or(UpdateBoxError::NoTokens)?
32+
.token_id
33+
.clone();
34+
if update_token_id != *inputs.update_nft_token_id {
35+
return Err(UpdateBoxError::IncorrectUpdateTokenId(update_token_id));
36+
}
37+
let contract = UpdateContract::from_ergo_tree(b.ergo_tree.clone(), inputs.into())?;
38+
39+
Ok(Self(b, contract))
40+
}
41+
pub fn ergo_tree(&self) -> ErgoTree {
42+
self.1.ergo_tree()
43+
}
44+
pub fn update_nft(&self) -> Token {
45+
self.0.tokens.as_ref().unwrap().get(0).unwrap().clone()
46+
}
47+
pub fn ballot_token_id(&self) -> TokenId {
48+
self.1.ballot_token_id().clone()
49+
}
50+
pub fn get_box(&self) -> &ErgoBox {
51+
&self.0
52+
}
53+
pub fn min_votes(&self) -> u32 {
54+
self.1.min_votes() as u32
55+
}
56+
}
57+
58+
#[derive(Debug, Copy, Clone)]
59+
pub struct UpdateBoxWrapperInputs<'a> {
60+
pub contract_parameters: &'a UpdateContractParameters,
61+
pub update_nft_token_id: &'a TokenId,
62+
pub ballot_token_id: &'a TokenId,
63+
pub pool_nft_token_id: &'a TokenId,
64+
}
65+
66+
impl From<UpdateBoxWrapper> for ErgoBox {
67+
fn from(w: UpdateBoxWrapper) -> Self {
68+
w.0.clone()
69+
}
70+
}

core/src/cli_commands.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,18 @@ use ergo_lib::ergotree_ir::chain::address::NetworkPrefix;
22

33
pub mod bootstrap;
44
pub mod extract_reward_tokens;
5+
pub mod prepare_update;
56
pub mod print_reward_tokens;
67
pub mod transfer_oracle_token;
8+
pub mod update_pool;
79
pub mod vote_update_pool;
810

911
pub(crate) fn ergo_explorer_transaction_link(tx_id_str: String, prefix: NetworkPrefix) -> String {
1012
let prefix_str = match prefix {
1113
NetworkPrefix::Mainnet => "explorer",
1214
NetworkPrefix::Testnet => "testnet",
1315
};
16+
let tx_id_str = tx_id_str.replace('"', ""); // Node interface returns Tx Id as a JSON string "TxId"
1417
format!(
1518
"https://{}.ergoplatform.com/en/transactions/{}",
1619
prefix_str, tx_id_str

0 commit comments

Comments
 (0)