Ver Fonte

cleanup some stuff

Jayant Krishnamurthy há 2 anos atrás
pai
commit
344f06db0a

+ 58 - 55
cosmwasm/contracts/pyth/src/contract.rs

@@ -84,15 +84,9 @@ pub fn instantiate(
     let state = ConfigInfo {
         owner:                      info.sender,
         wormhole_contract:          deps.api.addr_validate(msg.wormhole_contract.as_ref())?,
-        data_sources:               HashSet::from([PythDataSource {
-            emitter:            msg.pyth_emitter,
-            pyth_emitter_chain: msg.pyth_emitter_chain,
-        }]),
+        data_sources:               msg.data_sources.iter().cloned().collect(),
         chain_id:                   msg.chain_id,
-        governance_source:          PythDataSource {
-            emitter:            msg.governance_emitter,
-            pyth_emitter_chain: msg.governance_emitter_chain,
-        },
+        governance_source:          msg.governance_data_source.clone(),
         governance_source_index:    msg.governance_source_index,
         governance_sequence_number: msg.governance_sequence_number,
         valid_time_period:          Duration::from_secs(msg.valid_time_period_secs as u64),
@@ -130,7 +124,7 @@ fn update_price_feeds(
     mut deps: DepsMut,
     env: Env,
     info: MessageInfo,
-    data: &Binary,
+    data: &[Binary],
 ) -> StdResult<Response> {
     let state = config_read(deps.storage).load()?;
 
@@ -139,14 +133,26 @@ fn update_price_feeds(
         return Err(PythContractError::InsufficientFee.into());
     }
 
-    let vaa = parse_vaa(deps.branch(), env.block.time.seconds(), data)?;
-    verify_vaa_from_data_source(&state, &vaa)?;
+    let mut total_attestations: usize = 0;
+    let mut new_attestations: usize = 0;
+    for datum in data {
+        let vaa = parse_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)?;
+        let data = &vaa.payload;
+        let batch_attestation = BatchPriceAttestation::deserialize(&data[..])
+            .map_err(|_| PythContractError::InvalidUpdatePayload)?;
 
-    process_batch_attestation(deps, env, &batch_attestation)
+        let (num_updates, num_new) =
+            process_batch_attestation(&mut deps, &env, &batch_attestation)?;
+        total_attestations += num_updates;
+        new_attestations += num_new;
+    }
+
+    Ok(Response::new()
+        .add_attribute("action", "update_price_feeds")
+        .add_attribute("num_attestations", format!("{total_attestations}"))
+        .add_attribute("num_updated", format!("{new_attestations}")))
 }
 
 fn execute_governance_instruction(
@@ -203,8 +209,8 @@ fn execute_governance_instruction(
 
                     updated_config.governance_source_index = governance_data_source_index;
                     let new_governance_source = PythDataSource {
-                        emitter:            Binary::from(parsed_claim_vaa.emitter_address.clone()),
-                        pyth_emitter_chain: parsed_claim_vaa.emitter_chain,
+                        emitter:  Binary::from(parsed_claim_vaa.emitter_address.clone()),
+                        chain_id: parsed_claim_vaa.emitter_chain,
                     };
                     updated_config.governance_source = new_governance_source;
                     updated_config.governance_sequence_number = parsed_claim_vaa.sequence;
@@ -274,8 +280,8 @@ fn execute_governance_instruction(
 /// Check that `vaa` is from a valid data source (and hence is a legitimate price update message).
 fn verify_vaa_from_data_source(state: &ConfigInfo, vaa: &ParsedVAA) -> StdResult<()> {
     let vaa_data_source = PythDataSource {
-        emitter:            vaa.emitter_address.clone().into(),
-        pyth_emitter_chain: vaa.emitter_chain,
+        emitter:  vaa.emitter_address.clone().into(),
+        chain_id: vaa.emitter_chain,
     };
     if !state.data_sources.contains(&vaa_data_source) {
         return Err(PythContractError::InvalidUpdateEmitter)?;
@@ -286,8 +292,8 @@ fn verify_vaa_from_data_source(state: &ConfigInfo, vaa: &ParsedVAA) -> StdResult
 /// Check that `vaa` is from a valid governance source (and hence is a legitimate governance instruction).
 fn verify_vaa_from_governance_source(state: &ConfigInfo, vaa: &ParsedVAA) -> StdResult<()> {
     let vaa_data_source = PythDataSource {
-        emitter:            vaa.emitter_address.clone().into(),
-        pyth_emitter_chain: vaa.emitter_chain,
+        emitter:  vaa.emitter_address.clone().into(),
+        chain_id: vaa.emitter_chain,
     };
     if state.governance_source != vaa_data_source {
         return Err(PythContractError::InvalidUpdateEmitter)?;
@@ -296,11 +302,11 @@ fn verify_vaa_from_governance_source(state: &ConfigInfo, vaa: &ParsedVAA) -> Std
 }
 
 fn process_batch_attestation(
-    mut deps: DepsMut,
-    env: Env,
+    deps: &mut DepsMut,
+    env: &Env,
     batch_attestation: &BatchPriceAttestation,
-) -> StdResult<Response> {
-    let mut new_attestations_cnt: u8 = 0;
+) -> StdResult<(usize, usize)> {
+    let mut new_attestations_cnt: usize = 0;
 
     // Update prices
     for price_attestation in batch_attestation.price_attestations.iter() {
@@ -323,18 +329,15 @@ fn process_batch_attestation(
 
         let attestation_time = Timestamp::from_seconds(price_attestation.attestation_time as u64);
 
-        if update_price_feed_if_new(&mut deps, &env, price_feed, attestation_time)? {
+        if update_price_feed_if_new(deps, env, price_feed, attestation_time)? {
             new_attestations_cnt += 1;
         }
     }
 
-    Ok(Response::new()
-        .add_attribute("action", "price_update")
-        .add_attribute(
-            "batch_size",
-            format!("{}", batch_attestation.price_attestations.len()),
-        )
-        .add_attribute("num_updates", format!("{new_attestations_cnt}")))
+    Ok((
+        batch_attestation.price_attestations.len(),
+        new_attestations_cnt,
+    ))
 }
 
 /// Returns true if the price_feed is newer than the stored one.
@@ -579,8 +582,8 @@ mod test {
             wormhole_contract:          Addr::unchecked(String::default()),
             data_sources:               HashSet::default(),
             governance_source:          PythDataSource {
-                emitter:            Binary(vec![]),
-                pyth_emitter_chain: 0,
+                emitter:  Binary(vec![]),
+                chain_id: 0,
             },
             governance_source_index:    0,
             governance_sequence_number: 0,
@@ -602,8 +605,8 @@ mod test {
         pyth_emitter_chain: u16,
     ) -> HashSet<PythDataSource> {
         HashSet::from([PythDataSource {
-            emitter: pyth_emitter.into(),
-            pyth_emitter_chain,
+            emitter:  pyth_emitter.into(),
+            chain_id: pyth_emitter_chain,
         }])
     }
 
@@ -635,7 +638,7 @@ mod test {
 
         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)
+        update_price_feeds(deps.as_mut(), env, info, &[msg])
     }
 
     #[test]
@@ -965,8 +968,8 @@ mod test {
         ConfigInfo {
             wormhole_contract: Addr::unchecked(WORMHOLE_ADDR),
             governance_source: PythDataSource {
-                emitter:            Binary(vec![1u8, 2u8]),
-                pyth_emitter_chain: 3,
+                emitter:  Binary(vec![1u8, 2u8]),
+                chain_id: 3,
             },
             governance_sequence_number: 4,
             chain_id: 5,
@@ -1048,8 +1051,8 @@ mod test {
     #[test]
     fn test_authorize_governance_transfer_success() {
         let source_2 = PythDataSource {
-            emitter:            Binary::from([2u8; 32]),
-            pyth_emitter_chain: 4,
+            emitter:  Binary::from([2u8; 32]),
+            chain_id: 4,
         };
 
         let test_config = governance_test_config();
@@ -1059,7 +1062,7 @@ mod test {
             action:          AuthorizeGovernanceDataSourceTransfer {
                 claim_vaa: to_binary(&ParsedVAA {
                     emitter_address: source_2.emitter.to_vec(),
-                    emitter_chain: source_2.pyth_emitter_chain,
+                    emitter_chain: source_2.chain_id,
                     sequence: 12,
                     payload: GovernanceInstruction {
                         module:          Target,
@@ -1086,8 +1089,8 @@ mod test {
     #[test]
     fn test_authorize_governance_transfer_bad_source_index() {
         let source_2 = PythDataSource {
-            emitter:            Binary::from([2u8; 32]),
-            pyth_emitter_chain: 4,
+            emitter:  Binary::from([2u8; 32]),
+            chain_id: 4,
         };
 
         let mut test_config = governance_test_config();
@@ -1098,7 +1101,7 @@ mod test {
             action:          AuthorizeGovernanceDataSourceTransfer {
                 claim_vaa: to_binary(&ParsedVAA {
                     emitter_address: source_2.emitter.to_vec(),
-                    emitter_chain: source_2.pyth_emitter_chain,
+                    emitter_chain: source_2.chain_id,
                     sequence: 12,
                     payload: GovernanceInstruction {
                         module:          Target,
@@ -1125,8 +1128,8 @@ mod test {
     #[test]
     fn test_authorize_governance_transfer_bad_target_chain() {
         let source_2 = PythDataSource {
-            emitter:            Binary::from([2u8; 32]),
-            pyth_emitter_chain: 4,
+            emitter:  Binary::from([2u8; 32]),
+            chain_id: 4,
         };
 
         let test_config = governance_test_config();
@@ -1136,7 +1139,7 @@ mod test {
             action:          AuthorizeGovernanceDataSourceTransfer {
                 claim_vaa: to_binary(&ParsedVAA {
                     emitter_address: source_2.emitter.to_vec(),
-                    emitter_chain: source_2.pyth_emitter_chain,
+                    emitter_chain: source_2.chain_id,
                     sequence: 12,
                     payload: GovernanceInstruction {
                         module:          Target,
@@ -1163,16 +1166,16 @@ mod test {
     #[test]
     fn test_set_data_sources() {
         let source_1 = PythDataSource {
-            emitter:            Binary::from([1u8; 32]),
-            pyth_emitter_chain: 2,
+            emitter:  Binary::from([1u8; 32]),
+            chain_id: 2,
         };
         let source_2 = PythDataSource {
-            emitter:            Binary::from([2u8; 32]),
-            pyth_emitter_chain: 4,
+            emitter:  Binary::from([2u8; 32]),
+            chain_id: 4,
         };
         let source_3 = PythDataSource {
-            emitter:            Binary::from([3u8; 32]),
-            pyth_emitter_chain: 6,
+            emitter:  Binary::from([3u8; 32]),
+            chain_id: 6,
         };
 
         let mut test_config = governance_test_config();

+ 3 - 3
cosmwasm/contracts/pyth/src/governance.rs

@@ -118,8 +118,8 @@ impl GovernanceInstruction {
                     bytes.read_exact(&mut emitter_address)?;
 
                     data_sources.push(PythDataSource {
-                        emitter:            Binary::from(&emitter_address),
-                        pyth_emitter_chain: chain_id,
+                        emitter: Binary::from(&emitter_address),
+                        chain_id,
                     });
                 }
 
@@ -172,7 +172,7 @@ impl GovernanceInstruction {
                 buf.write_u16::<BigEndian>(self.target_chain_id)?;
                 buf.write_u8(u8::try_from(data_sources.len())?)?;
                 for data_source in data_sources {
-                    buf.write_u16::<BigEndian>(data_source.pyth_emitter_chain)?;
+                    buf.write_u16::<BigEndian>(data_source.chain_id)?;
 
                     // The message format expects emitter addresses to be 32 bytes.
                     // However, we don't maintain this invariant in the rust code (and we violate it in the tests).

+ 9 - 9
cosmwasm/contracts/pyth/src/msg.rs

@@ -1,4 +1,5 @@
 use {
+    crate::state::PythDataSource,
     cosmwasm_std::{
         Binary,
         Uint128,
@@ -19,16 +20,15 @@ type HumanAddr = String;
 #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
 #[serde(rename_all = "snake_case")]
 pub struct InstantiateMsg {
-    pub wormhole_contract:          HumanAddr,
-    // TODO: this should support multiple emitters
-    pub pyth_emitter:               Binary,
-    pub pyth_emitter_chain:         u16,
-    pub governance_emitter:         Binary,
-    pub governance_emitter_chain:   u16,
+    pub wormhole_contract: HumanAddr,
+    pub data_sources:      Vec<PythDataSource>,
+
+    pub governance_data_source:     PythDataSource,
     pub governance_source_index:    u32,
     pub governance_sequence_number: u64,
-    pub chain_id:                   u16,
-    pub valid_time_period_secs:     u16,
+
+    pub chain_id:               u16,
+    pub valid_time_period_secs: u16,
 
     pub fee:       Uint128,
     pub fee_denom: String,
@@ -38,7 +38,7 @@ pub struct InstantiateMsg {
 #[serde(rename_all = "snake_case")]
 pub enum ExecuteMsg {
     // TODO: add UpdatePriceFeeds if necessary
-    UpdatePriceFeeds { data: Binary },
+    UpdatePriceFeeds { data: Vec<Binary> },
     ExecuteGovernanceInstruction { data: Binary },
 }
 

+ 2 - 2
cosmwasm/contracts/pyth/src/state.rs

@@ -33,8 +33,8 @@ pub static PRICE_INFO_KEY: &[u8] = b"price_info_v3";
 
 #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, Hash, JsonSchema)]
 pub struct PythDataSource {
-    pub emitter:            Binary,
-    pub pyth_emitter_chain: u16,
+    pub emitter:  Binary,
+    pub chain_id: u16,
 }
 
 #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]

+ 12 - 7
cosmwasm/tools/deploy.js

@@ -173,13 +173,18 @@ addresses["pyth_cosmwasm.wasm"] = await instantiate(
   "pyth_cosmwasm.wasm",
   {
     wormhole_contract: addresses["wormhole.wasm"],
-    pyth_emitter: Buffer.from(pythEmitterAddress, "hex").toString("base64"),
-    pyth_emitter_chain: pythChain,
-    governance_emitter: Buffer.from(
-      pythGovernanceEmitterAddress,
-      "hex"
-    ).toString("base64"),
-    governance_emitter_chain: pythChain,
+    data_sources: [
+      {
+        emitter: Buffer.from(pythEmitterAddress, "hex").toString("base64"),
+        chain_id: pythChain,
+      },
+    ],
+    governance_source: {
+      emitter: Buffer.from(pythGovernanceEmitterAddress, "hex").toString(
+        "base64"
+      ),
+      chain_id: pythChain,
+    },
     governance_source_index: 0,
     governance_sequence_number: 0,
     chain_id: 3,

+ 16 - 14
third_party/pyth/p2w-relay/src/relay/terra.ts

@@ -3,6 +3,7 @@ import {
   LCDClient,
   LCDClientConfig,
   MnemonicKey,
+  Msg,
   MsgExecuteContract,
 } from "@terra-money/terra.js";
 import axios from "axios";
@@ -68,22 +69,23 @@ export class TerraRelay implements Relay {
       let fee: Coin = await this.getUpdateFee(signedVAAs);
 
       logger.debug("TIME: creating messages");
-      let msgs = new Array<MsgExecuteContract>();
-      for (let idx = 0; idx < signedVAAs.length; ++idx) {
-        const msg = new MsgExecuteContract(
-          wallet.key.accAddress,
-          this.contractAddress,
-          {
-            update_price_feeds: {
-              data: Buffer.from(signedVAAs[idx], "hex").toString("base64"),
-            },
-          },
-          [fee]
-        );
 
-        msgs.push(msg);
+      let base64VAAs = [];
+      for (let idx = 0; idx < signedVAAs.length; ++idx) {
+        base64VAAs.push(Buffer.from(signedVAAs[idx], "hex").toString("base64"));
       }
 
+      let msg = new MsgExecuteContract(
+        wallet.key.accAddress,
+        this.contractAddress,
+        {
+          update_price_feeds: {
+            data: base64VAAs,
+          },
+        },
+        [fee]
+      );
+
       let gasPrices;
       try {
         gasPrices = await axios
@@ -98,7 +100,7 @@ export class TerraRelay implements Relay {
       }
 
       const tx = await wallet.createAndSignTx({
-        msgs: msgs,
+        msgs: [msg],
         memo: "P2T",
         feeDenoms: [this.coinDenom],
         gasPrices,