From 6c6d2bc04ff1b340aeb75653068228bd3d7d4543 Mon Sep 17 00:00:00 2001
From: Kunal Arora <55632507+aroralanuk@users.noreply.github.com>
Date: Mon, 13 Jan 2025 22:03:40 +0530
Subject: [PATCH] fix(e2e): reenable gas enforcement check in e2e
 (non-cosmwasm) (#5105)

### Description

- Move to valid 'gaspaymentenforcement' for e2e, which was earlier
shortcircuiting to none (the default value for enforcement policy). This
meant we were not checking if the relayer was enforcing a non-zero gas
payment for either sealevel or EVM gas payments.
- The igpHook set as part of the default hook for Kathy was not
configured properly, hence was giving a quote of 0. Now, Kathy does set
the IGP config (oracle and overhead). (Note: Kathy is soon to be
deprecated, so this is more of a quick patch for e2e coverage).
- Added a check for deserilization of 'gaspaymentenforcement' and panic
if invalid to prevent this bug in the future.



### Drive-by changes

<!--
Are there any minor or drive-by changes also included?
-->

### Related issues

<!--
- Fixes #[issue number here]
-->

### Backward compatibility

<!--
Are these changes backward compatible? Are there any infrastructure
implications, e.g. changes that would prohibit deploying older commits
using this infra tooling?

Yes/No
-->

### Testing

<!--
What kind of testing have these changes undergone?

None/Manual/Unit Tests
-->
---
 rust/main/agents/relayer/src/settings/mod.rs  | 44 ++++++++--
 rust/main/utils/run-locally/src/main.rs       |  2 +-
 .../infra/scripts/send-test-messages.ts       | 81 +++++++++++++++++--
 3 files changed, 113 insertions(+), 14 deletions(-)

diff --git a/rust/main/agents/relayer/src/settings/mod.rs b/rust/main/agents/relayer/src/settings/mod.rs
index dc4c1e543e..df28d03dee 100644
--- a/rust/main/agents/relayer/src/settings/mod.rs
+++ b/rust/main/agents/relayer/src/settings/mod.rs
@@ -125,16 +125,50 @@ impl FromRawConf<RawRelayerSettings> for RelayerSettings {
             .parse_from_str("Expected database path")
             .unwrap_or_else(|| std::env::current_dir().unwrap().join("hyperlane_db"));
 
-        let (raw_gas_payment_enforcement_path, raw_gas_payment_enforcement) = p
-            .get_opt_key("gasPaymentEnforcement")
-            .take_config_err_flat(&mut err)
-            .and_then(parse_json_array)
-            .unwrap_or_else(|| (&p.cwp + "gas_payment_enforcement", Value::Array(vec![])));
+        // is_gas_payment_enforcement_set determines if we should be checking if the correct gas payment enforcement policy has been provided with "gasPaymentEnforcement" key
+        let (
+            raw_gas_payment_enforcement_path,
+            raw_gas_payment_enforcement,
+            is_gas_payment_enforcement_set,
+        ) = {
+            match p.get_opt_key("gasPaymentEnforcement") {
+                Ok(Some(parser)) => match parse_json_array(parser) {
+                    Some((path, value)) => (path, value, true),
+                    None => (
+                        &p.cwp + "gas_payment_enforcement",
+                        Value::Array(vec![]),
+                        true,
+                    ),
+                },
+                Ok(None) => (
+                    &p.cwp + "gas_payment_enforcement",
+                    Value::Array(vec![]),
+                    false,
+                ),
+                Err(_) => (
+                    &p.cwp + "gas_payment_enforcement",
+                    Value::Array(vec![]),
+                    false,
+                ),
+            }
+        };
 
         let gas_payment_enforcement_parser = ValueParser::new(
             raw_gas_payment_enforcement_path,
             &raw_gas_payment_enforcement,
         );
+
+        if is_gas_payment_enforcement_set
+            && gas_payment_enforcement_parser
+                .val
+                .as_array()
+                .unwrap()
+                .is_empty()
+        {
+            Err::<(), eyre::Report>(eyre!("GASPAYMENTENFORCEMENT policy cannot be parsed"))
+                .take_err(&mut err, || cwp + "gas_payment_enforcement");
+        }
+
         let mut gas_payment_enforcement = gas_payment_enforcement_parser.into_array_iter().map(|itr| {
             itr.filter_map(|policy| {
                 let policy_type = policy.chain(&mut err).get_opt_key("type").parse_string().end();
diff --git a/rust/main/utils/run-locally/src/main.rs b/rust/main/utils/run-locally/src/main.rs
index 4686c15446..a7e03b4094 100644
--- a/rust/main/utils/run-locally/src/main.rs
+++ b/rust/main/utils/run-locally/src/main.rs
@@ -227,7 +227,7 @@ fn main() -> ExitCode {
             "GASPAYMENTENFORCEMENT",
             r#"[{
                 "type": "minimum",
-                "payment": "1",
+                "payment": "1"
             }]"#,
         )
         .arg(
diff --git a/typescript/infra/scripts/send-test-messages.ts b/typescript/infra/scripts/send-test-messages.ts
index d028263982..6775ac5534 100644
--- a/typescript/infra/scripts/send-test-messages.ts
+++ b/typescript/infra/scripts/send-test-messages.ts
@@ -1,9 +1,16 @@
 import { Provider } from '@ethersproject/providers';
-import { Wallet } from 'ethers';
+import { BigNumber, Wallet } from 'ethers';
 import fs from 'fs';
 import yargs from 'yargs';
 
-import { Mailbox, TestSendReceiver__factory } from '@hyperlane-xyz/core';
+import {
+  InterchainGasPaymaster,
+  InterchainGasPaymaster__factory,
+  Mailbox,
+  StorageGasOracle,
+  StorageGasOracle__factory,
+  TestSendReceiver__factory,
+} from '@hyperlane-xyz/core';
 import {
   ChainName,
   HookType,
@@ -11,7 +18,7 @@ import {
   MultiProvider,
   TestChainName,
 } from '@hyperlane-xyz/sdk';
-import { addressToBytes32, sleep } from '@hyperlane-xyz/utils';
+import { addressToBytes32, formatMessage, sleep } from '@hyperlane-xyz/utils';
 
 const ANVIL_KEY =
   '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80';
@@ -47,6 +54,44 @@ async function setMailboxHook(
   console.log(`set the ${mailboxHookType} hook on ${local} to ${hook}`);
 }
 
+async function setIgpConfig(
+  remoteId: number,
+  signer: Wallet,
+  provider: Provider,
+  mailbox: Mailbox,
+  addresses: any,
+  local: ChainName,
+) {
+  const storageGasOracleF = new StorageGasOracle__factory(
+    signer.connect(provider),
+  );
+  const storageGasOracle = await storageGasOracleF.deploy();
+  await storageGasOracle.deployTransaction.wait();
+
+  const oracleConfigs: Array<StorageGasOracle.RemoteGasDataConfigStruct> = [];
+  oracleConfigs.push({
+    remoteDomain: remoteId,
+    tokenExchangeRate: '10000000000',
+    gasPrice: '1000000000',
+  });
+  await storageGasOracle.setRemoteGasDataConfigs(oracleConfigs);
+
+  const gasParamsToSet: InterchainGasPaymaster.GasParamStruct[] = [];
+  gasParamsToSet.push({
+    remoteDomain: remoteId,
+    config: {
+      gasOracle: storageGasOracle.address,
+      gasOverhead: 1000000,
+    },
+  });
+
+  const igpHook = InterchainGasPaymaster__factory.connect(
+    addresses[local].interchainGasPaymaster,
+    signer.connect(provider),
+  );
+  await igpHook.setDestinationGasConfigs(gasParamsToSet);
+}
+
 const chainSummary = async (core: HyperlaneCore, chain: ChainName) => {
   const coreContracts = core.getContracts(chain);
   const mailbox = coreContracts.mailbox;
@@ -157,15 +202,33 @@ async function main() {
       MailboxHookType.REQUIRED,
       requiredHook,
     );
+
+    if (
+      defaultHook === HookType.AGGREGATION ||
+      defaultHook === HookType.INTERCHAIN_GAS_PAYMASTER
+    ) {
+      console.log('Setting IGP config for message ...');
+      await setIgpConfig(remoteId, signer, provider, mailbox, addresses, local);
+    }
+
+    const message = formatMessage(
+      1,
+      0,
+      multiProvider.getDomainId(local),
+      recipient.address,
+      multiProvider.getDomainId(remote),
+      recipient.address,
+      '0x1234',
+    );
     const quote = await mailbox['quoteDispatch(uint32,bytes32,bytes)'](
       remoteId,
       addressToBytes32(recipient.address),
-      '0x1234',
+      message,
     );
-    await recipient['dispatchToSelf(address,uint32,bytes)'](
-      mailbox.address,
+    await mailbox['dispatch(uint32,bytes32,bytes)'](
       remoteId,
-      '0x1234',
+      addressToBytes32(recipient.address),
+      message,
       {
         value: quote,
       },
@@ -173,7 +236,9 @@ async function main() {
     console.log(
       `send to ${recipient.address} on ${remote} via mailbox ${
         mailbox.address
-      } on ${local} with nonce ${(await mailbox.nonce()) - 1}`,
+      } on ${local} with nonce ${
+        (await mailbox.nonce()) - 1
+      } and quote ${quote.toString()}`,
     );
     console.log(await chainSummary(core, local));
     console.log(await chainSummary(core, remote));