Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 38 additions & 8 deletions examples/hello/README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,45 @@
# ZetaChain Contracts Template
# Hello Example

## Getting Started
```
yarn deploy
```

## EVM

Successful call:

```
npx hardhat echo-call --contract 0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690 --receiver 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --network localhost --types '["string"]' hello
```

Failed call:

```
npx hardhat echo-call --contract 0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690 --receiver 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --network localhost --types '["uint256"]' 42
```

Install dependencies:
Failed call with handled revert:

```
yarn
npx hardhat echo-call --contract 0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690 --receiver 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --network localhost --revert-address 0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690 --revert-message 0x --call-on-revert --types '["uint256"]' 42
```

## Next Steps
## ZetaChain

Ready to dive in? Follow our [**🚀 smart contract
tutorials**](https://www.zetachain.com/docs/developers/tutorials/intro/) to
start building universal app contracts.
Successful call:

```
npx hardhat hello-call --contract 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --receiver 0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690 --zrc20 0x2ca7d64A7EFE2D62A725E2B35Cf7230D6677FfEe --function "hello(string)" --network localhost --types '["string"]' hello
```

Failed call:

```
npx hardhat hello-call --contract 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --receiver 0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690 --zrc20 0x2ca7d64A7EFE2D62A725E2B35Cf7230D6677FfEe --function "hello(string)" --network localhost --types '["uint256"]' 42
```

Failed call with handled revert:

```
npx hardhat hello-call --contract 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --receiver 0xc3e53F4d16Ae77Db1c982e75a937B9f60FE63690 --zrc20 0x2ca7d64A7EFE2D62A725E2B35Cf7230D6677FfEe --function "hello(string)" --network localhost --revert-address 0xE6E340D132b5f46d1e472DebcD681B2aBc16e57E --revert-message 0x --call-on-revert --types '["uint256"]' 42
```
36 changes: 36 additions & 0 deletions examples/hello/contracts/Echo.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

import {RevertContext} from "@zetachain/protocol-contracts/contracts/Revert.sol";
import "@zetachain/protocol-contracts/contracts/evm/GatewayEVM.sol";

contract Echo {
GatewayEVM public immutable gateway;

event RevertEvent(string, RevertContext);
event HelloEvent(string, string);

constructor(address payable gatewayAddress) {
gateway = GatewayEVM(gatewayAddress);
}

function hello(string memory message) external payable {
emit HelloEvent("Hello on EVM", message);
}
Comment on lines +17 to +19
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Consider the implications of the payable hello function.

The hello function is marked as payable but doesn't use the sent Ether. This could lead to locked Ether in the contract.

Consider one of the following options:

  1. Remove the payable keyword if Ether is not needed.
  2. Implement a withdrawal mechanism for the received Ether.
  3. Document the intended use of the received Ether if it's by design.


function onRevert(RevertContext calldata revertContext) external {
emit RevertEvent("Revert on EVM", revertContext);
}

function call(
address receiver,
bytes calldata message,
RevertOptions memory revertOptions
) external {
gateway.call(receiver, message, revertOptions);
}
Comment on lines +25 to +31
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

The call function allows external calls to the gateway.

This function correctly forwards the call to the gateway. However, consider adding access control to prevent unauthorized usage.

Consider implementing the Ownable pattern from OpenZeppelin and adding the onlyOwner modifier to this function:

import "@openzeppelin/contracts/access/Ownable.sol";

contract Echo is Ownable {
    // ...

    function call(
        address receiver,
        bytes calldata message,
        RevertOptions memory revertOptions
    ) external onlyOwner {
        gateway.call(receiver, message, revertOptions);
    }

    // ...
}


receive() external payable {}

fallback() external payable {}
Comment on lines +33 to +35
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Implement withdrawal mechanism for received Ether.

The receive() and fallback() functions allow the contract to receive Ether, but there's no mechanism to withdraw it. This could lead to permanently locked Ether in the contract.

Consider implementing a withdrawal function:

function withdraw() external onlyOwner {
    uint256 balance = address(this).balance;
    payable(owner()).transfer(balance);
}

Also, document the intended use of received Ether in the contract.

}
Comment on lines +7 to +36

Check warning

Code scanning / Slither

Contracts that lock Ether Medium

Contract locking ether found:
Contract Echo has payable functions:
- Echo.hello(string)
- Echo.receive()
- Echo.fallback()
But does not have a function to withdraw the ether
41 changes: 39 additions & 2 deletions examples/hello/contracts/Hello.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@
import "@zetachain/protocol-contracts/contracts/zevm/GatewayZEVM.sol";

contract Hello is UniversalContract {
GatewayZEVM public gateway;
GatewayZEVM public immutable gateway;

event HelloEvent(string, string);
event RevertEvent(string, RevertContext);
error TransferFailed();

constructor(address payable gatewayAddress) {
gateway = GatewayZEVM(gatewayAddress);
Expand All @@ -30,15 +31,51 @@
emit RevertEvent("Revert on ZetaChain", revertContext);
}

function gatewayCall(
function call(
bytes memory receiver,
address zrc20,
bytes calldata message,
uint256 gasLimit,
RevertOptions memory revertOptions
) external {
(, uint256 gasFee) = IZRC20(zrc20).withdrawGasFeeWithGasLimit(gasLimit);
if (!IZRC20(zrc20).transferFrom(msg.sender, address(this), gasFee))
revert TransferFailed();
IZRC20(zrc20).approve(address(gateway), gasFee);
gateway.call(receiver, zrc20, message, gasLimit, revertOptions);
}

Check warning

Code scanning / Slither

Unused return Medium

Check warning

Code scanning / Slither

Unused return Medium

Comment on lines +34 to 46
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Approval with suggestion: Improved call function with transfer check.

The renaming of gatewayCall to call and the addition of a transfer success check are commendable improvements. The use of the custom TransferFailed error enhances gas efficiency and error reporting.

However, there's an opportunity for further improvement:

The return value of the approve function call is not checked. Consider handling the approval result to ensure the operation's success.

Apply this diff to address the issue:

- IZRC20(zrc20).approve(address(gateway), gasFee);
+ if (!IZRC20(zrc20).approve(address(gateway), gasFee))
+     revert TransferFailed();

This change ensures that the approval operation is successful before proceeding with the gateway call.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function call(
bytes memory receiver,
address zrc20,
bytes calldata message,
uint256 gasLimit,
RevertOptions memory revertOptions
) external {
(, uint256 gasFee) = IZRC20(zrc20).withdrawGasFeeWithGasLimit(gasLimit);
if (!IZRC20(zrc20).transferFrom(msg.sender, address(this), gasFee))
revert TransferFailed();
IZRC20(zrc20).approve(address(gateway), gasFee);
gateway.call(receiver, zrc20, message, gasLimit, revertOptions);
}
function call(
bytes memory receiver,
address zrc20,
bytes calldata message,
uint256 gasLimit,
RevertOptions memory revertOptions
) external {
(, uint256 gasFee) = IZRC20(zrc20).withdrawGasFeeWithGasLimit(gasLimit);
if (!IZRC20(zrc20).transferFrom(msg.sender, address(this), gasFee))
revert TransferFailed();
if (!IZRC20(zrc20).approve(address(gateway), gasFee))
revert TransferFailed();
gateway.call(receiver, zrc20, message, gasLimit, revertOptions);
}
🧰 Tools
🪛 GitHub Check: Slither

[warning] 34-46: Unused return
Hello.call(bytes,address,bytes,uint256,RevertOptions) (contracts/Hello.sol#34-46) ignores return value by IZRC20(zrc20).approve(address(gateway),gasFee) (contracts/Hello.sol#44)


[warning] 34-46: Unused return
Hello.call(bytes,address,bytes,uint256,RevertOptions) (contracts/Hello.sol#34-46) ignores return value by (None,gasFee) = IZRC20(zrc20).withdrawGasFeeWithGasLimit(gasLimit) (contracts/Hello.sol#41)


function withdrawAndCall(
bytes memory receiver,
uint256 amount,
address zrc20,
bytes calldata message,
uint256 gasLimit,
RevertOptions memory revertOptions
) external {
(address gasZRC20, uint256 gasFee) = IZRC20(zrc20)
.withdrawGasFeeWithGasLimit(gasLimit);
uint256 target = zrc20 == gasZRC20 ? amount + gasFee : amount;
if (!IZRC20(zrc20).transferFrom(msg.sender, address(this), target))
revert TransferFailed();
IZRC20(zrc20).approve(address(gateway), target);
if (zrc20 != gasZRC20) {
if (
!IZRC20(gasZRC20).transferFrom(
msg.sender,
address(this),
gasFee
)
) revert TransferFailed();
IZRC20(gasZRC20).approve(address(gateway), gasFee);
}
gateway.withdrawAndCall(
receiver,
amount,
zrc20,
message,
gasLimit,
revertOptions
);
}
Comment on lines +48 to +80
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

⚠️ Potential issue

Approval with suggestions: New withdrawAndCall function.

The addition of the withdrawAndCall function is a valuable enhancement, providing a convenient way to perform withdrawals and calls in a single transaction. The implementation includes proper checks for transfer success and handles different ZRC20 scenarios effectively.

However, there are opportunities for further improvement:

  1. The return values of the approve function calls are not checked. Consider handling the approval results to ensure the operations' success.

Apply these diffs to address the issues:

- IZRC20(zrc20).approve(address(gateway), target);
+ if (!IZRC20(zrc20).approve(address(gateway), target))
+     revert TransferFailed();

- IZRC20(gasZRC20).approve(address(gateway), gasFee);
+ if (!IZRC20(gasZRC20).approve(address(gateway), gasFee))
+     revert TransferFailed();

These changes ensure that all approval operations are successful before proceeding with the gateway call.

  1. Consider extracting the common logic for transferring and approving into a separate internal function to reduce code duplication and improve maintainability.
function _transferAndApprove(address token, address from, uint256 amount) internal {
    if (!IZRC20(token).transferFrom(from, address(this), amount))
        revert TransferFailed();
    if (!IZRC20(token).approve(address(gateway), amount))
        revert TransferFailed();
}

This refactored function can then be used in both call and withdrawAndCall, reducing duplication and improving the contract's overall structure.

🧰 Tools
🪛 GitHub Check: Slither

[warning] 48-80: Unused return
Hello.withdrawAndCall(bytes,uint256,address,bytes,uint256,RevertOptions) (contracts/Hello.sol#48-80) ignores return value by IZRC20(gasZRC20).approve(address(gateway),gasFee) (contracts/Hello.sol#70)


[warning] 48-80: Unused return
Hello.withdrawAndCall(bytes,uint256,address,bytes,uint256,RevertOptions) (contracts/Hello.sol#48-80) ignores return value by IZRC20(zrc20).approve(address(gateway),target) (contracts/Hello.sol#61)

}
21 changes: 0 additions & 21 deletions examples/hello/contracts/Revert.sol

This file was deleted.

5 changes: 3 additions & 2 deletions examples/hello/hardhat.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import "./tasks/deploy";
import "./tasks/deployRevert";
import "./tasks/gatewayCall";
import "./tasks/helloCall";
import "./tasks/echoCall";
import "./tasks/helloWithdrawAndCall";
import "@zetachain/localnet/tasks";
import "@nomicfoundation/hardhat-toolbox";
import "@zetachain/toolkit/tasks";
Expand Down
6 changes: 3 additions & 3 deletions examples/hello/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"test": "echo \"Error: no test specified\" && exit 1",
"lint:fix": "npx eslint . --ext .js,.ts --fix",
"lint": "npx eslint . --ext .js,.ts",
"deploy": "npx hardhat compile --force && npx hardhat deploy --network localhost && npx hardhat deploy-revert --network localhost"
"deploy": "npx hardhat compile --force && npx hardhat deploy --network localhost && npx hardhat deploy --name Echo --network localhost --gateway 0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0"
},
"keywords": [],
"author": "",
Expand All @@ -28,8 +28,8 @@
"@types/node": ">=12.0.0",
"@typescript-eslint/eslint-plugin": "^5.59.9",
"@typescript-eslint/parser": "^5.59.9",
"@zetachain/localnet": "^3.0.4",
"@zetachain/toolkit": "13.0.0-rc2",
"@zetachain/localnet": "^3.3.0",
"@zetachain/toolkit": "13.0.0-rc4",
"axios": "^1.3.6",
"chai": "^4.2.0",
"dotenv": "^16.0.3",
Expand Down
6 changes: 3 additions & 3 deletions examples/hello/tasks/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => {
}

const factory = await hre.ethers.getContractFactory(args.name);
const contract = await (factory as any).deploy(args.gatewayZetaChain);
const contract = await (factory as any).deploy(args.gateway);
await contract.deployed();

if (args.json) {
Expand All @@ -30,7 +30,7 @@ task("deploy", "Deploy the contract", main)
.addFlag("json", "Output in JSON")
.addOptionalParam("name", "Contract to deploy", "Hello")
.addOptionalParam(
"gatewayZetaChain",
"Gateway address",
"gateway",
"Gateway address (default: ZetaChain Gateway)",
"0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0"
);
31 changes: 0 additions & 31 deletions examples/hello/tasks/deployRevert.ts

This file was deleted.

99 changes: 99 additions & 0 deletions examples/hello/tasks/echoCall.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { task, types } from "hardhat/config";
import type { HardhatRuntimeEnvironment } from "hardhat/types";

const main = async (args: any, hre: HardhatRuntimeEnvironment) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Specify the type for args instead of using any.

Using the any type for args reduces type safety and may lead to runtime errors. Defining a specific type or interface for args enhances code reliability and leverages TypeScript's type-checking capabilities.

Apply this change to define a type for args:

-interface EchoCallArgs {
+interface EchoCallArgs {
+  contract: string;
+  txOptionsGasPrice?: number;
+  txOptionsGasLimit?: number;
+  callOnRevert: boolean;
+  revertAddress: string;
+  revertMessage: string;
+  receiver: string;
+  onRevertGasLimit?: number;
+  name: string;
+  types: string;
+  values: string[];
+}

-const main = async (args: any, hre: HardhatRuntimeEnvironment) => {
+const main = async (args: EchoCallArgs, hre: HardhatRuntimeEnvironment) => {

Committable suggestion was skipped due to low confidence.

const { ethers } = hre;
const [signer] = await ethers.getSigners();

const txOptions = {
gasPrice: args.txOptionsGasPrice,
gasLimit: args.txOptionsGasLimit,
};

const revertOptions = {
abortAddress: "0x0000000000000000000000000000000000000000", // not used
callOnRevert: args.callOnRevert,
onRevertGasLimit: args.onRevertGasLimit,
revertAddress: args.revertAddress,
revertMessage: ethers.utils.hexlify(
ethers.utils.toUtf8Bytes(args.revertMessage)
),
};

const types = JSON.parse(args.types);

if (types.length !== args.values.length) {
throw new Error(
`The number of types (${types.length}) does not match the number of values (${args.values.length}).`
);
}
Comment on lines +23 to +29
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Handle potential JSON parsing errors for args.types.

Parsing args.types with JSON.parse can throw an error if the input is invalid. Adding error handling prevents the application from crashing due to malformed input.

Implement error handling as follows:

-const types = JSON.parse(args.types);
+let types: string[];
+try {
+  types = JSON.parse(args.types);
+} catch (error) {
+  throw new Error(`Invalid JSON format for types: ${error.message}`);
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const types = JSON.parse(args.types);
if (types.length !== args.values.length) {
throw new Error(
`The number of types (${types.length}) does not match the number of values (${args.values.length}).`
);
}
let types: string[];
try {
types = JSON.parse(args.types);
} catch (error) {
throw new Error(`Invalid JSON format for types: ${error.message}`);
}
if (types.length !== args.values.length) {
throw new Error(
`The number of types (${types.length}) does not match the number of values (${args.values.length}).`
);
}


const valuesArray = args.values.map((value: any, index: number) => {
const type = types[index];

if (type === "bool") {
try {
return JSON.parse(value.toLowerCase());
} catch (e) {
throw new Error(`Invalid boolean value: ${value}`);
}
} else if (type.startsWith("uint") || type.startsWith("int")) {
return ethers.BigNumber.from(value);
} else {
return value;
}
});
Comment on lines +31 to +45
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Improve value parsing logic for parameter types.

Using JSON.parse to parse boolean values is unreliable for string inputs like "true" or "false". Additionally, consider validating numeric inputs to ensure they are valid numbers.

Refactor the value parsing logic:

 const valuesArray = args.values.map((value: string, index: number) => {
   const type = types[index];

-  if (type === "bool") {
-    try {
-      return JSON.parse(value.toLowerCase());
-    } catch (e) {
-      throw new Error(`Invalid boolean value: ${value}`);
-    }
-  } else if (type.startsWith("uint") || type.startsWith("int")) {
+  if (type === "bool") {
+    if (value.toLowerCase() === "true") {
+      return true;
+    } else if (value.toLowerCase() === "false") {
+      return false;
+    } else {
+      throw new Error(`Invalid boolean value: ${value}`);
+    }
+  } else if (/^u?int(\d+)?$/.test(type)) {
     return ethers.BigNumber.from(value);
   } else {
     return value;
   }
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const valuesArray = args.values.map((value: any, index: number) => {
const type = types[index];
if (type === "bool") {
try {
return JSON.parse(value.toLowerCase());
} catch (e) {
throw new Error(`Invalid boolean value: ${value}`);
}
} else if (type.startsWith("uint") || type.startsWith("int")) {
return ethers.BigNumber.from(value);
} else {
return value;
}
});
const valuesArray = args.values.map((value: string, index: number) => {
const type = types[index];
if (type === "bool") {
if (value.toLowerCase() === "true") {
return true;
} else if (value.toLowerCase() === "false") {
return false;
} else {
throw new Error(`Invalid boolean value: ${value}`);
}
} else if (/^u?int(\d+)?$/.test(type)) {
return ethers.BigNumber.from(value);
} else {
return value;
}
});

const encodedParameters = ethers.utils.defaultAbiCoder.encode(
types,
valuesArray
);

const factory = (await hre.ethers.getContractFactory(args.name)) as any;
const contract = factory.attach(args.contract).connect(signer);
Comment on lines +51 to +52
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Avoid casting to any when obtaining the contract factory.

Casting to any bypasses TypeScript's type checking. Instead, use the appropriate contract type to maintain type safety.

Specify the contract type:

-const factory = (await hre.ethers.getContractFactory(args.name)) as any;
+const factory = await hre.ethers.getContractFactory(args.name);
+const contract = factory.attach(args.contract).connect(signer);

Committable suggestion was skipped due to low confidence.


const tx = await contract.call(
args.receiver,
encodedParameters,
revertOptions,
txOptions
);
Comment on lines +54 to +59
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Implement error handling for the contract call.

If the contract call fails, the error should be caught and handled appropriately to prevent unhandled promise rejections.

Add a try-catch block around the contract call:

-let tx = await contract.call(
-  args.receiver,
-  encodedParameters,
-  revertOptions,
-  txOptions
-);
+let tx;
+try {
+  tx = await contract.call(
+    args.receiver,
+    encodedParameters,
+    revertOptions,
+    txOptions
+  );
+} catch (error) {
+  throw new Error(`Contract call failed: ${error.message}`);
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const tx = await contract.call(
args.receiver,
encodedParameters,
revertOptions,
txOptions
);
let tx;
try {
tx = await contract.call(
args.receiver,
encodedParameters,
revertOptions,
txOptions
);
} catch (error) {
throw new Error(`Contract call failed: ${error.message}`);
}


console.log(`Transaction hash: ${tx.hash}`);
await tx.wait();
console.log("gatewayCall executed successfully");
};

task("echo-call", "Calls the gateway on a contract on EVM", main)
.addParam("contract", "The address of the deployed contract")
.addOptionalParam(
"txOptionsGasPrice",
"The gas price for the transaction",
10000000000,
types.int
)
.addOptionalParam(
"txOptionsGasLimit",
"The gas limit for the transaction",
7000000,
types.int
)
.addFlag("callOnRevert", "Whether to call on revert")
.addOptionalParam(
"revertAddress",
"Revert address",
"0x0000000000000000000000000000000000000000"
)
.addOptionalParam("revertMessage", "Revert message", "0x")
.addParam(
"receiver",
"The address of the receiver contract on a connected chain"
)
.addOptionalParam(
"onRevertGasLimit",
"The gas limit for the revert transaction",
7000000,
types.int
)
.addParam("name", "The name of the contract", "Echo")
.addParam("types", `The types of the parameters (example: '["string"]')`)
.addVariadicPositionalParam("values", "The values of the parameters");
Comment on lines +66 to +99
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Task Parameters Lack Proper Validation

The task parameters defined in examples/hello/tasks/echoCall.ts (lines 66-99) do not have corresponding validation logic implemented. It is crucial to incorporate validation checks for each parameter to ensure input correctness and enhance user experience by providing clear error messages for invalid inputs.

  • Implement validation checks for each parameter within the main function or appropriate sections of the codebase to enforce type safety and input integrity.
🔗 Analysis chain

Validate task parameters and provide user feedback.

Ensure all task parameters have appropriate validations and default values. This improves user experience by providing clear error messages for invalid inputs.

Review the parameter definitions using the following script:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: List all task parameters and verify their configurations.

# Expected Output: Parameter definitions with their types and default values.

grep -E '\.add(Param|OptionalParam|Flag)' examples/hello/tasks/echoCall.ts -A 4

Length of output: 1042


Script:

#!/bin/bash
# Description: Verify that each task parameter has appropriate validation in the main function.

# List of parameters to validate
PARAMETERS=(
  "contract"
  "txOptionsGasPrice"
  "txOptionsGasLimit"
  "callOnRevert"
  "revertAddress"
  "revertMessage"
  "receiver"
  "onRevertGasLimit"
  "name"
  "types"
  "values"
)

# Iterate over each parameter and search for validation statements
for param in "${PARAMETERS[@]}"; do
  echo "Validations for parameter: $param"
  rg -n "$param" examples/hello/tasks/echoCall.ts | grep -i 'validate\|ensure\|check'
  echo ""
done

Length of output: 2591

Loading
Loading