Skip to content

Commit 16ac585

Browse files
author
Dev Kalra
authored
[pyth-cosmwasm] sec review update (#649)
* remove owner * address sec review feedback * update storage for pricefeeds * deprecate owner * remove owner field
1 parent bbc140f commit 16ac585

File tree

2 files changed

+71
-119
lines changed

2 files changed

+71
-119
lines changed

target_chains/cosmwasm/contracts/pyth/src/contract.rs

Lines changed: 66 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,9 @@ use {
1919
state::{
2020
config,
2121
config_read,
22-
price_info,
23-
price_info_read,
22+
price_feed_bucket,
23+
price_feed_read_bucket,
2424
ConfigInfo,
25-
PriceInfo,
2625
PythDataSource,
2726
},
2827
},
@@ -44,7 +43,6 @@ use {
4443
QueryRequest,
4544
Response,
4645
StdResult,
47-
Timestamp,
4846
WasmMsg,
4947
WasmQuery,
5048
},
@@ -93,12 +91,11 @@ pub fn migrate(_deps: DepsMut, _env: Env, _msg: MigrateMsg) -> StdResult<Respons
9391
pub fn instantiate(
9492
deps: DepsMut,
9593
_env: Env,
96-
info: MessageInfo,
94+
_info: MessageInfo,
9795
msg: InstantiateMsg,
9896
) -> StdResult<Response> {
9997
// Save general wormhole and pyth info
10098
let state = ConfigInfo {
101-
owner: info.sender,
10299
wormhole_contract: deps.api.addr_validate(msg.wormhole_contract.as_ref())?,
103100
data_sources: msg.data_sources.iter().cloned().collect(),
104101
chain_id: msg.chain_id,
@@ -385,9 +382,7 @@ fn process_batch_attestation(
385382
for price_attestation in batch_attestation.price_attestations.iter() {
386383
let price_feed = create_price_feed_from_price_attestation(price_attestation);
387384

388-
let attestation_time = Timestamp::from_seconds(price_attestation.attestation_time as u64);
389-
390-
if update_price_feed_if_new(deps, env, price_feed, attestation_time)? {
385+
if update_price_feed_if_new(deps, env, price_feed)? {
391386
new_attestations_cnt += 1;
392387
}
393388
}
@@ -440,37 +435,28 @@ fn create_price_feed_from_price_attestation(price_attestation: &PriceAttestation
440435
/// in the bucket won't be parsed.
441436
fn update_price_feed_if_new(
442437
deps: &mut DepsMut,
443-
env: &Env,
444-
price_feed: PriceFeed,
445-
attestation_time: Timestamp,
438+
_env: &Env,
439+
new_price_feed: PriceFeed,
446440
) -> StdResult<bool> {
447441
let mut is_new_price = true;
448-
price_info(deps.storage).update(
449-
price_feed.id.as_ref(),
450-
|maybe_price_info| -> StdResult<PriceInfo> {
451-
match maybe_price_info {
452-
Some(price_info) => {
442+
price_feed_bucket(deps.storage).update(
443+
new_price_feed.id.as_ref(),
444+
|maybe_price_feed| -> StdResult<PriceFeed> {
445+
match maybe_price_feed {
446+
Some(price_feed) => {
453447
// This check ensures that a price won't be updated with the same or older
454-
// message. Attestation_time is guaranteed increasing in
448+
// message. Publish_TIme is guaranteed increasing in
455449
// solana
456-
if price_info.attestation_time < attestation_time {
457-
Ok(PriceInfo {
458-
arrival_time: env.block.time,
459-
arrival_block: env.block.height,
460-
price_feed,
461-
attestation_time,
462-
})
450+
if price_feed.get_price_unchecked().publish_time
451+
< new_price_feed.get_price_unchecked().publish_time
452+
{
453+
Ok(new_price_feed)
463454
} else {
464455
is_new_price = false;
465-
Ok(price_info)
456+
Ok(price_feed)
466457
}
467458
}
468-
None => Ok(PriceInfo {
469-
arrival_time: env.block.time,
470-
arrival_block: env.block.height,
471-
price_feed,
472-
attestation_time,
473-
}),
459+
None => Ok(new_price_feed),
474460
}
475461
},
476462
)?;
@@ -488,10 +474,8 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
488474

489475
/// Get the most recent value of the price feed indicated by `feed_id`.
490476
pub fn query_price_feed(deps: &Deps, feed_id: &[u8]) -> StdResult<PriceFeedResponse> {
491-
match price_info_read(deps.storage).load(feed_id) {
492-
Ok(price_info) => Ok(PriceFeedResponse {
493-
price_feed: price_info.price_feed,
494-
}),
477+
match price_feed_read_bucket(deps.storage).load(feed_id) {
478+
Ok(price_feed) => Ok(PriceFeedResponse { price_feed }),
495479
Err(_) => Err(PythContractError::PriceFeedNotFound)?,
496480
}
497481
}
@@ -547,6 +531,7 @@ mod test {
547531
SystemResult,
548532
Uint128,
549533
},
534+
pyth_sdk::UnixTimestamp,
550535
pyth_sdk_cw::PriceIdentifier,
551536
pyth_wormhole_attester_sdk::PriceAttestation,
552537
std::time::Duration,
@@ -656,7 +641,6 @@ mod test {
656641

657642
fn create_zero_config_info() -> ConfigInfo {
658643
ConfigInfo {
659-
owner: Addr::unchecked(String::default()),
660644
wormhole_contract: Addr::unchecked(String::default()),
661645
data_sources: HashSet::default(),
662646
governance_source: PythDataSource {
@@ -671,11 +655,12 @@ mod test {
671655
}
672656
}
673657

674-
fn create_price_feed(expo: i32) -> PriceFeed {
658+
fn create_price_feed(expo: i32, publish_time: UnixTimestamp) -> PriceFeed {
675659
PriceFeed::new(
676660
PriceIdentifier::new([0u8; 32]),
677661
Price {
678662
expo,
663+
publish_time,
679664
..Default::default()
680665
},
681666
Price {
@@ -695,21 +680,10 @@ mod test {
695680
}])
696681
}
697682

698-
/// Updates the price feed with the given attestation time stamp and
683+
/// Updates the price feed with the given publish time stamp and
699684
/// returns the update status (true means updated, false means ignored)
700-
fn do_update_price_feed(
701-
deps: &mut DepsMut,
702-
env: &Env,
703-
price_feed: PriceFeed,
704-
attestation_time_seconds: u64,
705-
) -> bool {
706-
update_price_feed_if_new(
707-
deps,
708-
env,
709-
price_feed,
710-
Timestamp::from_seconds(attestation_time_seconds),
711-
)
712-
.unwrap()
685+
fn do_update_price_feed(deps: &mut DepsMut, env: &Env, price_feed: PriceFeed) -> bool {
686+
update_price_feed_if_new(deps, env, price_feed).unwrap()
713687
}
714688

715689
fn apply_price_update(
@@ -854,10 +828,9 @@ mod test {
854828
process_batch_attestation(&mut deps.as_mut(), &env, &attestations).unwrap();
855829

856830

857-
let stored_price_feed = price_info_read(&deps.storage)
831+
let stored_price_feed = price_feed_read_bucket(&deps.storage)
858832
.load(&[0u8; 32])
859-
.unwrap()
860-
.price_feed;
833+
.unwrap();
861834
let price = stored_price_feed.get_price_unchecked();
862835
let ema_price = stored_price_feed.get_ema_price_unchecked();
863836

@@ -907,10 +880,9 @@ mod test {
907880
process_batch_attestation(&mut deps.as_mut(), &env, &attestations).unwrap();
908881

909882

910-
let stored_price_feed = price_info_read(&deps.storage)
883+
let stored_price_feed = price_feed_read_bucket(&deps.storage)
911884
.load(&[0u8; 32])
912-
.unwrap()
913-
.price_feed;
885+
.unwrap();
914886
let price = stored_price_feed.get_price_unchecked();
915887
let ema_price = stored_price_feed.get_ema_price_unchecked();
916888

@@ -1005,74 +977,69 @@ mod test {
1005977
#[test]
1006978
fn test_update_price_feed_if_new_first_price_ok() {
1007979
let (mut deps, env) = setup_test();
1008-
let price_feed = create_price_feed(3);
980+
let price_feed = create_price_feed(3, 100);
1009981

1010-
let changed = do_update_price_feed(&mut deps.as_mut(), &env, price_feed, 100);
982+
let changed = do_update_price_feed(&mut deps.as_mut(), &env, price_feed);
1011983
assert!(changed);
1012984

1013-
let stored_price_feed = price_info(&mut deps.storage)
985+
let stored_price_feed = price_feed_bucket(&mut deps.storage)
1014986
.load(price_feed.id.as_ref())
1015-
.unwrap()
1016-
.price_feed;
987+
.unwrap();
1017988

1018989
assert_eq!(stored_price_feed, price_feed);
1019990
}
1020991

1021992
#[test]
1022993
fn test_update_price_feed_if_new_ignore_duplicate_time() {
1023994
let (mut deps, env) = setup_test();
1024-
let time = 100;
1025995

1026-
let first_price_feed = create_price_feed(3);
1027-
let changed = do_update_price_feed(&mut deps.as_mut(), &env, first_price_feed, time);
996+
let first_price_feed = create_price_feed(3, 100);
997+
let changed = do_update_price_feed(&mut deps.as_mut(), &env, first_price_feed);
1028998
assert!(changed);
1029999

1030-
let second_price_feed = create_price_feed(4);
1031-
let changed = do_update_price_feed(&mut deps.as_mut(), &env, second_price_feed, time);
1000+
let second_price_feed = create_price_feed(4, 100);
1001+
let changed = do_update_price_feed(&mut deps.as_mut(), &env, second_price_feed);
10321002
assert!(!changed);
10331003

1034-
let stored_price_feed = price_info(&mut deps.storage)
1004+
let stored_price_feed = price_feed_bucket(&mut deps.storage)
10351005
.load(first_price_feed.id.as_ref())
1036-
.unwrap()
1037-
.price_feed;
1006+
.unwrap();
10381007
assert_eq!(stored_price_feed, first_price_feed);
10391008
}
10401009

10411010
#[test]
10421011
fn test_update_price_feed_if_new_ignore_older() {
10431012
let (mut deps, env) = setup_test();
10441013

1045-
let first_price_feed = create_price_feed(3);
1046-
let changed = do_update_price_feed(&mut deps.as_mut(), &env, first_price_feed, 100);
1014+
let first_price_feed = create_price_feed(3, 100);
1015+
let changed = do_update_price_feed(&mut deps.as_mut(), &env, first_price_feed);
10471016
assert!(changed);
10481017

1049-
let second_price_feed = create_price_feed(4);
1050-
let changed = do_update_price_feed(&mut deps.as_mut(), &env, second_price_feed, 90);
1018+
let second_price_feed = create_price_feed(4, 90);
1019+
let changed = do_update_price_feed(&mut deps.as_mut(), &env, second_price_feed);
10511020
assert!(!changed);
10521021

1053-
let stored_price_feed = price_info(&mut deps.storage)
1022+
let stored_price_feed = price_feed_bucket(&mut deps.storage)
10541023
.load(first_price_feed.id.as_ref())
1055-
.unwrap()
1056-
.price_feed;
1024+
.unwrap();
10571025
assert_eq!(stored_price_feed, first_price_feed);
10581026
}
10591027

10601028
#[test]
10611029
fn test_update_price_feed_if_new_accept_newer() {
10621030
let (mut deps, env) = setup_test();
10631031

1064-
let first_price_feed = create_price_feed(3);
1065-
let changed = do_update_price_feed(&mut deps.as_mut(), &env, first_price_feed, 100);
1032+
let first_price_feed = create_price_feed(3, 100);
1033+
let changed = do_update_price_feed(&mut deps.as_mut(), &env, first_price_feed);
10661034
assert!(changed);
10671035

1068-
let second_price_feed = create_price_feed(4);
1069-
let changed = do_update_price_feed(&mut deps.as_mut(), &env, second_price_feed, 110);
1036+
let second_price_feed = create_price_feed(4, 110);
1037+
let changed = do_update_price_feed(&mut deps.as_mut(), &env, second_price_feed);
10701038
assert!(changed);
10711039

1072-
let stored_price_feed = price_info(&mut deps.storage)
1040+
let stored_price_feed = price_feed_bucket(&mut deps.storage)
10731041
.load(first_price_feed.id.as_ref())
1074-
.unwrap()
1075-
.price_feed;
1042+
.unwrap();
10761043
assert_eq!(stored_price_feed, second_price_feed);
10771044
}
10781045

@@ -1082,24 +1049,20 @@ mod test {
10821049

10831050
let address = b"123".as_ref();
10841051

1085-
let dummy_price_info = PriceInfo {
1086-
price_feed: PriceFeed::new(
1087-
PriceIdentifier::new([0u8; 32]),
1088-
Price {
1089-
price: 300,
1090-
conf: 301,
1091-
expo: 302,
1092-
publish_time: 303,
1093-
},
1094-
Price {
1095-
..Default::default()
1096-
},
1097-
),
1098-
..Default::default()
1099-
};
1100-
1101-
price_info(&mut deps.storage)
1102-
.save(address, &dummy_price_info)
1052+
let dummy_price_feed = PriceFeed::new(
1053+
PriceIdentifier::new([0u8; 32]),
1054+
Price {
1055+
price: 300,
1056+
conf: 301,
1057+
expo: 302,
1058+
publish_time: 303,
1059+
},
1060+
Price {
1061+
..Default::default()
1062+
},
1063+
);
1064+
price_feed_bucket(&mut deps.storage)
1065+
.save(address, &dummy_price_feed)
11031066
.unwrap();
11041067

11051068
let price_feed = query_price_feed(&deps.as_ref(), address)

target_chains/cosmwasm/contracts/pyth/src/state.rs

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use {
44
Binary,
55
Coin,
66
Storage,
7-
Timestamp,
87
},
98
cosmwasm_storage::{
109
bucket,
@@ -29,7 +28,7 @@ use {
2928
};
3029

3130
pub static CONFIG_KEY: &[u8] = b"config";
32-
pub static PRICE_INFO_KEY: &[u8] = b"price_info_v4";
31+
pub static PRICE_FEED_KEY: &[u8] = b"price_feed";
3332

3433
/// A `PythDataSource` identifies a specific contract (given by its Wormhole `emitter`) on
3534
/// a specific blockchain (given by `chain_id`).
@@ -41,7 +40,6 @@ pub struct PythDataSource {
4140

4241
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
4342
pub struct ConfigInfo {
44-
pub owner: Addr,
4543
pub wormhole_contract: Addr,
4644
pub data_sources: HashSet<PythDataSource>,
4745
pub governance_source: PythDataSource,
@@ -65,15 +63,6 @@ pub struct ConfigInfo {
6563
pub fee: Coin,
6664
}
6765

68-
#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq, Eq, JsonSchema)]
69-
#[serde(rename_all = "snake_case")]
70-
pub struct PriceInfo {
71-
pub arrival_time: Timestamp,
72-
pub arrival_block: u64,
73-
pub attestation_time: Timestamp,
74-
pub price_feed: PriceFeed,
75-
}
76-
7766
pub fn config(storage: &mut dyn Storage) -> Singleton<ConfigInfo> {
7867
singleton(storage, CONFIG_KEY)
7968
}
@@ -82,10 +71,10 @@ pub fn config_read(storage: &dyn Storage) -> ReadonlySingleton<ConfigInfo> {
8271
singleton_read(storage, CONFIG_KEY)
8372
}
8473

85-
pub fn price_info(storage: &mut dyn Storage) -> Bucket<PriceInfo> {
86-
bucket(storage, PRICE_INFO_KEY)
74+
pub fn price_feed_bucket(storage: &mut dyn Storage) -> Bucket<PriceFeed> {
75+
bucket(storage, PRICE_FEED_KEY)
8776
}
8877

89-
pub fn price_info_read(storage: &dyn Storage) -> ReadonlyBucket<PriceInfo> {
90-
bucket_read(storage, PRICE_INFO_KEY)
78+
pub fn price_feed_read_bucket(storage: &dyn Storage) -> ReadonlyBucket<PriceFeed> {
79+
bucket_read(storage, PRICE_FEED_KEY)
9180
}

0 commit comments

Comments
 (0)