Cosmwasm refactor and preparation for parse price feeds (#895)
* Add more tests for update_fee_amount Restructure code to split parsing and updating logic so that all messages can be parsed without being applied * Fix docker build command for cosmwasm contract * Refactor is_fee_sufficient tests Extract out the chain specific part into separate function Merge test_accumulator_is_fee_sufficient back into is_fee_sufficient * Rename function and simplify process_batch_attestation tests
This commit is contained in:
parent
339b2f6ce0
commit
ef963cdfc6
|
@ -22,8 +22,8 @@ First, build the contracts within [the current directory](./). You must have Doc
|
|||
cd ./tools
|
||||
npm ci
|
||||
|
||||
# if you want to build specifically for injective
|
||||
npm run build-contract -- --injective
|
||||
# if you want to build specifically for one chain
|
||||
npm run build-contract -- --[injective|osmosis]
|
||||
|
||||
# else a generic cosmwasm contract can be build using
|
||||
npm run build-contract -- --cosmwasm
|
||||
|
|
|
@ -60,6 +60,10 @@ use {
|
|||
WasmMsg,
|
||||
WasmQuery,
|
||||
},
|
||||
pyth_sdk::{
|
||||
Identifier,
|
||||
UnixTimestamp,
|
||||
},
|
||||
pyth_sdk_cw::{
|
||||
error::PythContractError,
|
||||
ExecuteMsg,
|
||||
|
@ -146,7 +150,7 @@ pub fn instantiate(
|
|||
/// *Warning* this function does not verify the emitter of the wormhole message; it only checks
|
||||
/// that the wormhole signatures are valid. The caller is responsible for checking that the message
|
||||
/// originates from the expected emitter.
|
||||
pub fn parse_and_verify_vaa(deps: DepsMut, block_time: u64, data: &Binary) -> StdResult<ParsedVAA> {
|
||||
pub fn parse_and_verify_vaa(deps: Deps, block_time: u64, data: &Binary) -> StdResult<ParsedVAA> {
|
||||
let cfg = config_read(deps.storage).load()?;
|
||||
let vaa: ParsedVAA = deps.querier.query(&QueryRequest::Wasm(WasmQuery::Smart {
|
||||
contract_addr: cfg.wormhole_contract.to_string(),
|
||||
|
@ -256,35 +260,11 @@ fn update_price_feeds(
|
|||
info: MessageInfo,
|
||||
data: &[Binary],
|
||||
) -> StdResult<Response<MsgWrapper>> {
|
||||
let state = config_read(deps.storage).load()?;
|
||||
|
||||
if !is_fee_sufficient(&deps.as_ref(), info, data)? {
|
||||
return Err(PythContractError::InsufficientFee)?;
|
||||
}
|
||||
|
||||
let mut num_total_attestations: usize = 0;
|
||||
let mut total_new_feeds: Vec<PriceFeed> = vec![];
|
||||
|
||||
for datum in data {
|
||||
let header = datum.get(0..4);
|
||||
let (num_attestations, new_feeds) =
|
||||
if header == Some(PYTHNET_ACCUMULATOR_UPDATE_MAGIC.as_slice()) {
|
||||
process_accumulator(&mut deps, &env, datum)?
|
||||
} else {
|
||||
let vaa = parse_and_verify_vaa(deps.branch(), env.block.time.seconds(), datum)?;
|
||||
verify_vaa_from_data_source(&state, &vaa)?;
|
||||
|
||||
let data = &vaa.payload;
|
||||
let batch_attestation = BatchPriceAttestation::deserialize(&data[..])
|
||||
.map_err(|_| PythContractError::InvalidUpdatePayload)?;
|
||||
|
||||
process_batch_attestation(&mut deps, &env, &batch_attestation)?
|
||||
};
|
||||
num_total_attestations += num_attestations;
|
||||
for new_feed in new_feeds {
|
||||
total_new_feeds.push(new_feed.to_owned());
|
||||
}
|
||||
}
|
||||
let (num_total_attestations, total_new_feeds) = apply_updates(&mut deps, &env, data)?;
|
||||
|
||||
let num_total_new_attestations = total_new_feeds.len();
|
||||
|
||||
|
@ -313,12 +293,12 @@ fn update_price_feeds(
|
|||
/// The VAA must come from an authorized governance emitter.
|
||||
/// See [GovernanceInstruction] for descriptions of the supported operations.
|
||||
fn execute_governance_instruction(
|
||||
mut deps: DepsMut,
|
||||
deps: DepsMut,
|
||||
env: Env,
|
||||
_info: MessageInfo,
|
||||
data: &Binary,
|
||||
) -> StdResult<Response<MsgWrapper>> {
|
||||
let vaa = parse_and_verify_vaa(deps.branch(), env.block.time.seconds(), data)?;
|
||||
let vaa = parse_and_verify_vaa(deps.as_ref(), env.block.time.seconds(), data)?;
|
||||
let state = config_read(deps.storage).load()?;
|
||||
verify_vaa_from_governance_source(&state, &vaa)?;
|
||||
|
||||
|
@ -358,7 +338,7 @@ fn execute_governance_instruction(
|
|||
}
|
||||
AuthorizeGovernanceDataSourceTransfer { claim_vaa } => {
|
||||
let parsed_claim_vaa =
|
||||
parse_and_verify_vaa(deps.branch(), env.block.time.seconds(), &claim_vaa)?;
|
||||
parse_and_verify_vaa(deps.as_ref(), env.block.time.seconds(), &claim_vaa)?;
|
||||
transfer_governance(&mut updated_config, &state, &parsed_claim_vaa)?
|
||||
}
|
||||
SetDataSources { data_sources } => {
|
||||
|
@ -500,17 +480,43 @@ fn verify_vaa_from_governance_source(state: &ConfigInfo, vaa: &ParsedVAA) -> Std
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn process_accumulator(
|
||||
fn parse_update(deps: &Deps, env: &Env, data: &Binary) -> StdResult<Vec<PriceFeed>> {
|
||||
let header = data.get(0..4);
|
||||
let feeds = if header == Some(PYTHNET_ACCUMULATOR_UPDATE_MAGIC.as_slice()) {
|
||||
parse_accumulator(deps, env, data)?
|
||||
} else {
|
||||
parse_batch_attestation(deps, env, data)?
|
||||
};
|
||||
Ok(feeds)
|
||||
}
|
||||
|
||||
fn apply_updates(
|
||||
deps: &mut DepsMut,
|
||||
env: &Env,
|
||||
data: &[u8],
|
||||
data: &[Binary],
|
||||
) -> StdResult<(usize, Vec<PriceFeed>)> {
|
||||
let mut num_total_attestations: usize = 0;
|
||||
let mut total_new_feeds: Vec<PriceFeed> = vec![];
|
||||
|
||||
for datum in data {
|
||||
let feeds = parse_update(&deps.as_ref(), env, datum)?;
|
||||
num_total_attestations += feeds.len();
|
||||
for feed in feeds {
|
||||
if update_price_feed_if_new(deps, env, feed)? {
|
||||
total_new_feeds.push(feed);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok((num_total_attestations, total_new_feeds))
|
||||
}
|
||||
|
||||
fn parse_accumulator(deps: &Deps, env: &Env, data: &[u8]) -> StdResult<Vec<PriceFeed>> {
|
||||
let update_data = AccumulatorUpdateData::try_from_slice(data)
|
||||
.map_err(|_| PythContractError::InvalidAccumulatorPayload)?;
|
||||
match update_data.proof {
|
||||
Proof::WormholeMerkle { vaa, updates } => {
|
||||
let parsed_vaa = parse_and_verify_vaa(
|
||||
deps.branch(),
|
||||
*deps,
|
||||
env.block.time.seconds(),
|
||||
&Binary::from(Vec::from(vaa)),
|
||||
)?;
|
||||
|
@ -523,8 +529,7 @@ fn process_accumulator(
|
|||
let root: MerkleRoot<Keccak160> = MerkleRoot::new(match msg.payload {
|
||||
WormholePayload::Merkle(merkle_root) => merkle_root.root,
|
||||
});
|
||||
let update_len = updates.len();
|
||||
let mut new_feeds = vec![];
|
||||
let mut feeds = vec![];
|
||||
for update in updates {
|
||||
let message_vec = Vec::from(update.message);
|
||||
if !root.check(update.proof, &message_vec) {
|
||||
|
@ -551,37 +556,33 @@ fn process_accumulator(
|
|||
publish_time: price_feed_message.publish_time,
|
||||
},
|
||||
);
|
||||
|
||||
if update_price_feed_if_new(deps, env, price_feed)? {
|
||||
new_feeds.push(price_feed);
|
||||
}
|
||||
feeds.push(price_feed);
|
||||
}
|
||||
_ => return Err(PythContractError::InvalidAccumulatorMessageType)?,
|
||||
}
|
||||
}
|
||||
Ok((update_len, new_feeds))
|
||||
Ok(feeds)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Update the on-chain storage for any new price updates provided in `batch_attestation`.
|
||||
fn process_batch_attestation(
|
||||
deps: &mut DepsMut,
|
||||
env: &Env,
|
||||
batch_attestation: &BatchPriceAttestation,
|
||||
) -> StdResult<(usize, Vec<PriceFeed>)> {
|
||||
let mut new_feeds = vec![];
|
||||
fn parse_batch_attestation(deps: &Deps, env: &Env, data: &Binary) -> StdResult<Vec<PriceFeed>> {
|
||||
let vaa = parse_and_verify_vaa(*deps, env.block.time.seconds(), data)?;
|
||||
let state = config_read(deps.storage).load()?;
|
||||
verify_vaa_from_data_source(&state, &vaa)?;
|
||||
let data = &vaa.payload;
|
||||
let batch_attestation = BatchPriceAttestation::deserialize(&data[..])
|
||||
.map_err(|_| PythContractError::InvalidUpdatePayload)?;
|
||||
let mut feeds = vec![];
|
||||
|
||||
// Update prices
|
||||
for price_attestation in batch_attestation.price_attestations.iter() {
|
||||
let price_feed = create_price_feed_from_price_attestation(price_attestation);
|
||||
|
||||
if update_price_feed_if_new(deps, env, price_feed)? {
|
||||
new_feeds.push(price_feed);
|
||||
}
|
||||
feeds.push(price_feed);
|
||||
}
|
||||
|
||||
Ok((batch_attestation.price_attestations.len(), new_feeds))
|
||||
Ok(feeds)
|
||||
}
|
||||
|
||||
fn create_price_feed_from_price_attestation(price_attestation: &PriceAttestation) -> PriceFeed {
|
||||
|
@ -667,6 +668,58 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/// This function is not used in the contract yet but mimicks the behavior implemented
|
||||
/// in the EVM contract. We are yet to finalize how the parsed prices should be consumed
|
||||
/// in injective as well as other chains.
|
||||
pub fn parse_price_feed_updates(
|
||||
deps: DepsMut,
|
||||
env: Env,
|
||||
info: MessageInfo,
|
||||
updates: &[Binary],
|
||||
price_feeds: Vec<Identifier>,
|
||||
min_publish_time: UnixTimestamp,
|
||||
max_publish_time: UnixTimestamp,
|
||||
) -> StdResult<Response<MsgWrapper>> {
|
||||
let _config = config_read(deps.storage).load()?;
|
||||
if !is_fee_sufficient(&deps.as_ref(), info, updates)? {
|
||||
return Err(PythContractError::InsufficientFee)?;
|
||||
}
|
||||
let mut found_feeds = 0;
|
||||
let mut results: Vec<(Identifier, Option<PriceFeed>)> =
|
||||
price_feeds.iter().map(|id| (*id, None)).collect();
|
||||
for datum in updates {
|
||||
let feeds = parse_update(&deps.as_ref(), &env, datum)?;
|
||||
for result in results.as_mut_slice() {
|
||||
if result.1.is_some() {
|
||||
continue;
|
||||
}
|
||||
for feed in feeds.as_slice() {
|
||||
if feed.get_price_unchecked().publish_time < min_publish_time
|
||||
|| feed.get_price_unchecked().publish_time > max_publish_time
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if result.0 == feed.id {
|
||||
result.1 = Some(*feed);
|
||||
found_feeds += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if found_feeds != price_feeds.len() {
|
||||
return Err(PythContractError::InvalidUpdatePayload)?;
|
||||
}
|
||||
|
||||
let _unwrapped_feeds = results
|
||||
.into_iter()
|
||||
.map(|(_, feed)| feed.unwrap())
|
||||
.collect::<Vec<PriceFeed>>();
|
||||
let response = Response::new();
|
||||
Ok(response.add_attribute("action", "parse_price_feeds"))
|
||||
}
|
||||
|
||||
/// Get the most recent value of the price feed indicated by `feed_id`.
|
||||
pub fn query_price_feed(deps: &Deps, feed_id: &[u8]) -> StdResult<PriceFeedResponse> {
|
||||
match price_feed_read_bucket(deps.storage).load(feed_id) {
|
||||
|
@ -882,9 +935,13 @@ mod test {
|
|||
}
|
||||
}
|
||||
|
||||
fn create_price_update_msg(emitter_address: &[u8], emitter_chain: u16) -> Binary {
|
||||
fn create_batch_price_update_msg(
|
||||
emitter_address: &[u8],
|
||||
emitter_chain: u16,
|
||||
attestations: Vec<PriceAttestation>,
|
||||
) -> Binary {
|
||||
let batch_attestation = BatchPriceAttestation {
|
||||
price_attestations: vec![PriceAttestation::default()],
|
||||
price_attestations: attestations,
|
||||
};
|
||||
|
||||
let mut vaa = create_zero_vaa();
|
||||
|
@ -895,6 +952,17 @@ mod test {
|
|||
to_binary(&vaa).unwrap()
|
||||
}
|
||||
|
||||
fn create_batch_price_update_msg_from_attestations(
|
||||
attestations: Vec<PriceAttestation>,
|
||||
) -> Binary {
|
||||
create_batch_price_update_msg(
|
||||
default_emitter_addr().as_slice(),
|
||||
EMITTER_CHAIN,
|
||||
attestations,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
fn create_zero_config_info() -> ConfigInfo {
|
||||
ConfigInfo {
|
||||
wormhole_contract: Addr::unchecked(String::default()),
|
||||
|
@ -946,14 +1014,12 @@ mod test {
|
|||
config_info: &ConfigInfo,
|
||||
emitter_address: &[u8],
|
||||
emitter_chain: u16,
|
||||
funds: &[Coin],
|
||||
) -> StdResult<Response<MsgWrapper>> {
|
||||
attestations: Vec<PriceAttestation>,
|
||||
) -> StdResult<(usize, Vec<PriceFeed>)> {
|
||||
let (mut deps, env) = setup_test();
|
||||
config(&mut deps.storage).save(config_info).unwrap();
|
||||
|
||||
let info = mock_info("123", funds);
|
||||
let msg = create_price_update_msg(emitter_address, emitter_chain);
|
||||
update_price_feeds(deps.as_mut(), env, info, &[msg])
|
||||
let msg = create_batch_price_update_msg(emitter_address, emitter_chain, attestations);
|
||||
apply_updates(&mut deps.as_mut(), &env, &[msg])
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1025,71 +1091,32 @@ mod test {
|
|||
assert!(res.is_err());
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "osmosis"))]
|
||||
#[test]
|
||||
fn test_is_fee_sufficient() {
|
||||
let mut config_info = default_config_info();
|
||||
config_info.fee = Coin::new(100, "foo");
|
||||
|
||||
let (mut deps, _env) = setup_test();
|
||||
config(&mut deps.storage).save(&config_info).unwrap();
|
||||
|
||||
let mut info = mock_info("123", coins(100, "foo").as_slice());
|
||||
let data = create_price_update_msg(default_emitter_addr().as_slice(), EMITTER_CHAIN);
|
||||
|
||||
// sufficient fee -> true
|
||||
let result = is_fee_sufficient(&deps.as_ref(), info.clone(), &[data.clone()]);
|
||||
assert_eq!(result, Ok(true));
|
||||
|
||||
// insufficient fee -> false
|
||||
info.funds = coins(50, "foo");
|
||||
let result = is_fee_sufficient(&deps.as_ref(), info.clone(), &[data.clone()]);
|
||||
assert_eq!(result, Ok(false));
|
||||
|
||||
// insufficient fee -> false
|
||||
info.funds = coins(150, "bar");
|
||||
let result = is_fee_sufficient(&deps.as_ref(), info, &[data]);
|
||||
assert_eq!(result, Ok(false));
|
||||
}
|
||||
|
||||
#[cfg(feature = "osmosis")]
|
||||
#[test]
|
||||
fn test_is_fee_sufficient() {
|
||||
// setup config with base fee
|
||||
let base_denom = "foo";
|
||||
let base_amount = 100;
|
||||
let mut config_info = default_config_info();
|
||||
config_info.fee = Coin::new(base_amount, base_denom);
|
||||
let (mut deps, _env) = setup_test();
|
||||
config(&mut deps.storage).save(&config_info).unwrap();
|
||||
|
||||
// a dummy price data
|
||||
let data = create_price_update_msg(default_emitter_addr().as_slice(), EMITTER_CHAIN);
|
||||
|
||||
// sufficient fee in base denom -> true
|
||||
let info = mock_info("123", coins(base_amount, base_denom).as_slice());
|
||||
let result = is_fee_sufficient(&deps.as_ref(), info.clone(), &[data.clone()]);
|
||||
fn check_sufficient_fee(deps: &Deps, data: &[Binary]) {
|
||||
let mut info = mock_info("123", coins(100, "foo").as_slice());
|
||||
let result = is_fee_sufficient(&deps, info.clone(), &data);
|
||||
assert_eq!(result, Ok(true));
|
||||
|
||||
// insufficient fee in base denom -> false
|
||||
let info = mock_info("123", coins(50, base_denom).as_slice());
|
||||
let result = is_fee_sufficient(&deps.as_ref(), info, &[data.clone()]);
|
||||
info.funds = coins(50, "foo");
|
||||
let result = is_fee_sufficient(&deps, info.clone(), &data);
|
||||
assert_eq!(result, Ok(false));
|
||||
|
||||
// valid denoms are 'uion' or 'ibc/FF3065989E34457F342D4EFB8692406D49D4E2B5C70F725F127862E22CE6BDCD'
|
||||
// a valid denom other than base denom with sufficient fee
|
||||
let info = mock_info("123", coins(100, "uion").as_slice());
|
||||
let result = is_fee_sufficient(&deps.as_ref(), info, &[data.clone()]);
|
||||
info.funds = coins(100, "uion");
|
||||
let result = is_fee_sufficient(&deps, info.clone(), &data);
|
||||
assert_eq!(result, Ok(true));
|
||||
|
||||
// insufficient fee in valid denom -> false
|
||||
let info = mock_info("123", coins(50, "uion").as_slice());
|
||||
let result = is_fee_sufficient(&deps.as_ref(), info, &[data.clone()]);
|
||||
info.funds = coins(50, "uion");
|
||||
let result = is_fee_sufficient(&deps, info.clone(), &data);
|
||||
assert_eq!(result, Ok(false));
|
||||
|
||||
// an invalid denom -> Err invalid fee denom
|
||||
let info = mock_info("123", coins(100, "invalid_denom").as_slice());
|
||||
let result = is_fee_sufficient(&deps.as_ref(), info, &[data.clone()]);
|
||||
info.funds = coins(100, "invalid_denom");
|
||||
let result = is_fee_sufficient(&deps, info, &data);
|
||||
assert_eq!(
|
||||
result,
|
||||
Err(PythContractError::InvalidFeeDenom {
|
||||
|
@ -1099,14 +1126,57 @@ mod test {
|
|||
);
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "osmosis"))]
|
||||
fn check_sufficient_fee(deps: &Deps, data: &[Binary]) {
|
||||
let mut info = mock_info("123", coins(100, "foo").as_slice());
|
||||
|
||||
// sufficient fee -> true
|
||||
let result = is_fee_sufficient(deps, info.clone(), data);
|
||||
assert_eq!(result, Ok(true));
|
||||
|
||||
// insufficient fee -> false
|
||||
info.funds = coins(50, "foo");
|
||||
let result = is_fee_sufficient(deps, info.clone(), data);
|
||||
assert_eq!(result, Ok(false));
|
||||
|
||||
// insufficient fee -> false
|
||||
info.funds = coins(150, "bar");
|
||||
let result = is_fee_sufficient(deps, info, data);
|
||||
assert_eq!(result, Ok(false));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_process_batch_attestation_empty_array() {
|
||||
let (mut deps, env) = setup_test();
|
||||
let attestations = BatchPriceAttestation {
|
||||
price_attestations: vec![],
|
||||
};
|
||||
let (num_attestations, new_attestations) =
|
||||
process_batch_attestation(&mut deps.as_mut(), &env, &attestations).unwrap();
|
||||
fn test_is_fee_sufficient() {
|
||||
let mut config_info = default_config_info();
|
||||
config_info.fee = Coin::new(100, "foo");
|
||||
|
||||
let (mut deps, _env) = setup_test();
|
||||
config(&mut deps.storage).save(&config_info).unwrap();
|
||||
let data = [create_batch_price_update_msg_from_attestations(vec![
|
||||
PriceAttestation::default(),
|
||||
])];
|
||||
check_sufficient_fee(&deps.as_ref(), &data);
|
||||
|
||||
let feed1 = create_dummy_price_feed_message(100);
|
||||
let feed2 = create_dummy_price_feed_message(200);
|
||||
let feed3 = create_dummy_price_feed_message(300);
|
||||
let data = [create_accumulator_message(
|
||||
&[feed1, feed2, feed3],
|
||||
&[feed1],
|
||||
false,
|
||||
)];
|
||||
check_sufficient_fee(&deps.as_ref(), &data)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_batch_attestation_empty_array() {
|
||||
let (num_attestations, new_attestations) = apply_price_update(
|
||||
&default_config_info(),
|
||||
default_emitter_addr().as_slice(),
|
||||
EMITTER_CHAIN,
|
||||
vec![],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(num_attestations, 0);
|
||||
assert_eq!(new_attestations.len(), 0);
|
||||
|
@ -1252,36 +1322,6 @@ mod test {
|
|||
test_accumulator_wrong_source(default_emitter_addr(), EMITTER_CHAIN + 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_accumulator_is_fee_sufficient() {
|
||||
let mut config_info = default_config_info();
|
||||
config_info.fee = Coin::new(100, "foo");
|
||||
|
||||
let (mut deps, _env) = setup_test();
|
||||
config(&mut deps.storage).save(&config_info).unwrap();
|
||||
|
||||
|
||||
let feed1 = create_dummy_price_feed_message(100);
|
||||
let feed2 = create_dummy_price_feed_message(200);
|
||||
let feed3 = create_dummy_price_feed_message(300);
|
||||
let msg = create_accumulator_message(&[feed1, feed2, feed3], &[feed1, feed3], false);
|
||||
let data = &[msg];
|
||||
let mut info = mock_info("123", coins(200, "foo").as_slice());
|
||||
// sufficient fee -> true
|
||||
let result = is_fee_sufficient(&deps.as_ref(), info.clone(), data);
|
||||
assert_eq!(result, Ok(true));
|
||||
|
||||
// insufficient fee -> false
|
||||
info.funds = coins(100, "foo");
|
||||
let result = is_fee_sufficient(&deps.as_ref(), info.clone(), data);
|
||||
assert_eq!(result, Ok(false));
|
||||
|
||||
// insufficient fee -> false
|
||||
info.funds = coins(300, "bar");
|
||||
let result = is_fee_sufficient(&deps.as_ref(), info, data);
|
||||
assert_eq!(result, Ok(false));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_accumulator_get_update_fee_amount() {
|
||||
let mut config_info = default_config_info();
|
||||
|
@ -1307,6 +1347,14 @@ mod test {
|
|||
false,
|
||||
);
|
||||
assert_eq!(get_update_fee_amount(&deps.as_ref(), &[msg]).unwrap(), 500);
|
||||
|
||||
let batch_msg =
|
||||
create_batch_price_update_msg_from_attestations(vec![PriceAttestation::default()]);
|
||||
let msg = create_accumulator_message(&[feed1, feed2, feed3], &[feed1, feed2, feed3], false);
|
||||
assert_eq!(
|
||||
get_update_fee_amount(&deps.as_ref(), &[msg, batch_msg]).unwrap(),
|
||||
400
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1643,11 +1691,8 @@ mod test {
|
|||
assert_eq!(ema_price.publish_time, 99);
|
||||
}
|
||||
|
||||
// this is testing the function process_batch_attestation
|
||||
// process_batch_attestation is calling update_price_feed_if_new
|
||||
// changes to update_price_feed_if_new might cause this test
|
||||
#[test]
|
||||
fn test_process_batch_attestation_status_not_trading() {
|
||||
fn test_parse_batch_attestation_status_not_trading() {
|
||||
let (mut deps, env) = setup_test();
|
||||
|
||||
let price_attestation = PriceAttestation {
|
||||
|
@ -1666,20 +1711,14 @@ mod test {
|
|||
..Default::default()
|
||||
};
|
||||
|
||||
let attestations = BatchPriceAttestation {
|
||||
price_attestations: vec![price_attestation],
|
||||
};
|
||||
let (num_attestations, new_attestations) =
|
||||
process_batch_attestation(&mut deps.as_mut(), &env, &attestations).unwrap();
|
||||
|
||||
let stored_price_feed = price_feed_read_bucket(&deps.storage)
|
||||
.load(&[0u8; 32])
|
||||
config(&mut deps.storage)
|
||||
.save(&default_config_info())
|
||||
.unwrap();
|
||||
let price = stored_price_feed.get_price_unchecked();
|
||||
let ema_price = stored_price_feed.get_ema_price_unchecked();
|
||||
|
||||
assert_eq!(num_attestations, 1);
|
||||
assert_eq!(new_attestations.len(), 1);
|
||||
let msg = create_batch_price_update_msg_from_attestations(vec![price_attestation]);
|
||||
let feeds = parse_batch_attestation(&deps.as_ref(), &env, &msg).unwrap();
|
||||
assert_eq!(feeds.len(), 1);
|
||||
let price = feeds[0].get_price_unchecked();
|
||||
let ema_price = feeds[0].get_ema_price_unchecked();
|
||||
|
||||
// for price
|
||||
assert_eq!(price.price, 99);
|
||||
|
@ -1694,11 +1733,8 @@ mod test {
|
|||
assert_eq!(ema_price.publish_time, 99);
|
||||
}
|
||||
|
||||
// this is testing the function process_batch_attestation
|
||||
// process_batch_attestation is calling update_price_feed_if_new
|
||||
// changes to update_price_feed_if_new might affect this test
|
||||
#[test]
|
||||
fn test_process_batch_attestation_status_trading() {
|
||||
fn test_parse_batch_attestation_status_trading() {
|
||||
let (mut deps, env) = setup_test();
|
||||
|
||||
let price_attestation = PriceAttestation {
|
||||
|
@ -1717,20 +1753,14 @@ mod test {
|
|||
..Default::default()
|
||||
};
|
||||
|
||||
let attestations = BatchPriceAttestation {
|
||||
price_attestations: vec![price_attestation],
|
||||
};
|
||||
let (num_attestations, new_attestations) =
|
||||
process_batch_attestation(&mut deps.as_mut(), &env, &attestations).unwrap();
|
||||
|
||||
let stored_price_feed = price_feed_read_bucket(&deps.storage)
|
||||
.load(&[0u8; 32])
|
||||
config(&mut deps.storage)
|
||||
.save(&default_config_info())
|
||||
.unwrap();
|
||||
let price = stored_price_feed.get_price_unchecked();
|
||||
let ema_price = stored_price_feed.get_ema_price_unchecked();
|
||||
|
||||
assert_eq!(num_attestations, 1);
|
||||
assert_eq!(new_attestations.len(), 1);
|
||||
let msg = create_batch_price_update_msg_from_attestations(vec![price_attestation]);
|
||||
let feeds = parse_batch_attestation(&deps.as_ref(), &env, &msg).unwrap();
|
||||
assert_eq!(feeds.len(), 1);
|
||||
let price = feeds[0].get_price_unchecked();
|
||||
let ema_price = feeds[0].get_ema_price_unchecked();
|
||||
|
||||
// for price
|
||||
assert_eq!(price.price, 100);
|
||||
|
@ -1751,7 +1781,7 @@ mod test {
|
|||
&default_config_info(),
|
||||
default_emitter_addr().as_slice(),
|
||||
EMITTER_CHAIN,
|
||||
&[],
|
||||
vec![PriceAttestation::default()],
|
||||
);
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
|
@ -1763,7 +1793,7 @@ mod test {
|
|||
&default_config_info(),
|
||||
emitter_address.as_slice(),
|
||||
EMITTER_CHAIN,
|
||||
&[],
|
||||
vec![PriceAttestation::default()],
|
||||
);
|
||||
assert_eq!(result, Err(PythContractError::InvalidUpdateEmitter.into()));
|
||||
}
|
||||
|
@ -1774,7 +1804,7 @@ mod test {
|
|||
&default_config_info(),
|
||||
default_emitter_addr().as_slice(),
|
||||
EMITTER_CHAIN + 1,
|
||||
&[],
|
||||
vec![PriceAttestation::default()],
|
||||
);
|
||||
assert_eq!(result, Err(PythContractError::InvalidUpdateEmitter.into()));
|
||||
}
|
||||
|
|
|
@ -80,6 +80,7 @@ function build() {
|
|||
|
||||
const buildCommand = `
|
||||
docker run --rm -v "$(cd ..; pwd)":/code \
|
||||
-v "$(cd ../../../pythnet; pwd)":/pythnet \
|
||||
-v "$(cd ../../../wormhole_attester; pwd)":/wormhole_attester \
|
||||
--mount type=volume,source="$(basename "$(cd ..; pwd)")_cache",target=/code/target \
|
||||
--mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \
|
||||
|
|
Loading…
Reference in New Issue