mirror of
https://github.com/zkemail/zk-email-verify.git
synced 2026-01-07 20:54:05 -05:00
refactor: extract command related utilities
This commit is contained in:
@@ -2,8 +2,6 @@
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import { Bytes } from "@openzeppelin/contracts/utils/Bytes.sol";
|
||||
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
|
||||
import { CommandUtils } from "@zk-email/email-tx-builder/src/libraries/CommandUtils.sol";
|
||||
|
||||
/**
|
||||
* @title CircuitUtils
|
||||
@@ -13,7 +11,6 @@ import { CommandUtils } from "@zk-email/email-tx-builder/src/libraries/CommandUt
|
||||
*/
|
||||
library CircuitUtils {
|
||||
using Bytes for bytes;
|
||||
using Strings for string;
|
||||
|
||||
/**
|
||||
* @notice Error thrown when the public signals array length is not exactly 60
|
||||
@@ -210,9 +207,10 @@ library CircuitUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Flattens multiple arrays of field elements into a single array of length 60
|
||||
* @notice Flattens multiple arrays of field elements into a single array
|
||||
* @param inputs The arrays of field elements to flatten
|
||||
* @return out The flattened array of length 60
|
||||
* @param outLength The length of the flattened array
|
||||
* @return out The flattened array
|
||||
*/
|
||||
function flattenFields(uint256[][] memory inputs, uint256 outLength) internal pure returns (uint256[] memory out) {
|
||||
out = new uint256[](outLength);
|
||||
@@ -227,98 +225,4 @@ library CircuitUtils {
|
||||
if (k != outLength) revert InvalidPubSignalsLength();
|
||||
return out;
|
||||
}
|
||||
|
||||
/// @notice Extracts a parameter from a command string based on the template and parameter index.
|
||||
/// @param template The command template as an array of strings.
|
||||
/// @param command The command string to extract from.
|
||||
/// @param paramIndex The zero-based index of the parameter to extract.
|
||||
/// @return The extracted parameter as a string, or an empty string if not found.
|
||||
function extractCommandParamByIndex(
|
||||
string[] memory template,
|
||||
string memory command,
|
||||
uint256 paramIndex
|
||||
)
|
||||
internal
|
||||
pure
|
||||
returns (string memory)
|
||||
{
|
||||
uint256 wordIndex = _getParamWordIndex(template, paramIndex);
|
||||
if (wordIndex == type(uint256).max) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return _splitString(command, " ")[wordIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Checks if the given template string is a matcher (parameter placeholder).
|
||||
* @param templateString The template string to check.
|
||||
* @return True if the string is a matcher, false otherwise.
|
||||
*/
|
||||
function _isMatcher(string memory templateString) private pure returns (bool) {
|
||||
return Strings.equal(templateString, CommandUtils.STRING_MATCHER)
|
||||
|| Strings.equal(templateString, CommandUtils.UINT_MATCHER)
|
||||
|| Strings.equal(templateString, CommandUtils.INT_MATCHER)
|
||||
|| Strings.equal(templateString, CommandUtils.DECIMALS_MATCHER)
|
||||
|| Strings.equal(templateString, CommandUtils.ETH_ADDR_MATCHER);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Finds the index in the template corresponding to the Nth matcher (zero-based).
|
||||
* @param template The command template as an array of strings.
|
||||
* @param paramIndex The zero-based index of the parameter to find.
|
||||
* @return paramTemplateIndex The zero-based index in the template array, or uint256 max if not found.
|
||||
*/
|
||||
function _getParamWordIndex(
|
||||
string[] memory template,
|
||||
uint256 paramIndex
|
||||
)
|
||||
private
|
||||
pure
|
||||
returns (uint256 paramTemplateIndex)
|
||||
{
|
||||
paramTemplateIndex = 0;
|
||||
for (uint256 i = 0; i < template.length; i++) {
|
||||
if (_isMatcher(template[i])) {
|
||||
if (paramTemplateIndex == paramIndex) {
|
||||
return i;
|
||||
}
|
||||
paramTemplateIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
// return uint max if param not found
|
||||
return type(uint256).max;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Splits a string by a delimiter into an array of strings
|
||||
* @param str The string to split
|
||||
* @param delimiter The delimiter to split by
|
||||
* @return The array of split strings
|
||||
*/
|
||||
function _splitString(string memory str, bytes1 delimiter) private pure returns (string[] memory) {
|
||||
bytes memory strBytes = bytes(str);
|
||||
uint256 count = 1;
|
||||
for (uint256 i = 0; i < strBytes.length; i++) {
|
||||
if (strBytes[i] == delimiter) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
string[] memory parts = new string[](count);
|
||||
uint256 lastIndex = 0;
|
||||
uint256 partIndex = 0;
|
||||
for (uint256 i = 0; i < strBytes.length; i++) {
|
||||
if (strBytes[i] == delimiter) {
|
||||
bytes memory partBytes = strBytes.slice(lastIndex, i);
|
||||
parts[partIndex] = string(partBytes);
|
||||
lastIndex = i + 1;
|
||||
partIndex++;
|
||||
}
|
||||
}
|
||||
bytes memory lastPartBytes = strBytes.slice(lastIndex, strBytes.length);
|
||||
parts[partIndex] = string(lastPartBytes);
|
||||
return parts;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
"dependencies": {
|
||||
"@openzeppelin/contracts": "5.3.0",
|
||||
"@openzeppelin/contracts-upgradeable": "5.3.0",
|
||||
"@zk-email/email-tx-builder": "https://github.com/zkemail/email-tx-builder#9620b7bbec4a2e15704f01ccc2635ec66bedbf7b",
|
||||
"dotenv": "^16.3.1"
|
||||
},
|
||||
"files": [
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.30;
|
||||
|
||||
import { Test } from "forge-std/Test.sol";
|
||||
import { CommandUtils } from "@zk-email/email-tx-builder/src/libraries/CommandUtils.sol";
|
||||
import { CircuitUtilsHelper } from "./_CircuitUtilsHelper.sol";
|
||||
|
||||
contract ExtractCommandParamByIndexTest is Test {
|
||||
CircuitUtilsHelper private _helper;
|
||||
|
||||
function setUp() public {
|
||||
_helper = new CircuitUtilsHelper();
|
||||
}
|
||||
|
||||
function test_simpleStringParameter() public view {
|
||||
string[] memory template = new string[](2);
|
||||
template[0] = "String:";
|
||||
template[1] = CommandUtils.STRING_MATCHER;
|
||||
|
||||
string memory command = "String: username";
|
||||
string memory result = _helper.callExtractCommandParamByIndex(template, command, 0);
|
||||
assertEq(result, "username");
|
||||
}
|
||||
|
||||
function test_ethAddressParameter() public view {
|
||||
string[] memory template = new string[](4);
|
||||
template[0] = "Address:";
|
||||
template[1] = CommandUtils.ETH_ADDR_MATCHER;
|
||||
|
||||
string memory command = "Address: 0xafBD210c60dD651892a61804A989eEF7bD63CBA0";
|
||||
string memory result = _helper.callExtractCommandParamByIndex(template, command, 0);
|
||||
assertEq(result, "0xafBD210c60dD651892a61804A989eEF7bD63CBA0");
|
||||
}
|
||||
|
||||
function test_multipleParameters() public view {
|
||||
string[] memory template = new string[](4);
|
||||
template[0] = "Address1:";
|
||||
template[1] = CommandUtils.ETH_ADDR_MATCHER;
|
||||
template[2] = "Address2:";
|
||||
template[3] = CommandUtils.ETH_ADDR_MATCHER;
|
||||
|
||||
string memory command =
|
||||
"Address1: 0x0000000000000000000000000000000000000000 Address2: 0x1111111111111111111111111111111111111111";
|
||||
string memory result1 = _helper.callExtractCommandParamByIndex(template, command, 0);
|
||||
string memory result2 = _helper.callExtractCommandParamByIndex(template, command, 1);
|
||||
assertEq(result1, "0x0000000000000000000000000000000000000000");
|
||||
assertEq(result2, "0x1111111111111111111111111111111111111111");
|
||||
}
|
||||
|
||||
function test_parameterIndexOutOfBounds() public view {
|
||||
string[] memory template = new string[](2);
|
||||
template[0] = "Address:";
|
||||
template[1] = CommandUtils.ETH_ADDR_MATCHER;
|
||||
|
||||
string memory command = "Address: 0xafBD210c60dD651892a61804A989eEF7bD63CBA0";
|
||||
string memory result = _helper.callExtractCommandParamByIndex(template, command, 2);
|
||||
assertEq(result, "");
|
||||
}
|
||||
|
||||
function test_noParameters() public view {
|
||||
string[] memory template = new string[](2);
|
||||
template[0] = "PING";
|
||||
template[1] = "PONG";
|
||||
|
||||
string memory command = "PING PONG";
|
||||
string memory result = _helper.callExtractCommandParamByIndex(template, command, 0);
|
||||
assertEq(result, "");
|
||||
}
|
||||
|
||||
function test_parameterAtStart() public view {
|
||||
string[] memory template = new string[](2);
|
||||
template[0] = CommandUtils.STRING_MATCHER;
|
||||
template[1] = "!";
|
||||
|
||||
string memory command = "username !";
|
||||
string memory result = _helper.callExtractCommandParamByIndex(template, command, 0);
|
||||
assertEq(result, "username");
|
||||
}
|
||||
|
||||
function test_consecutiveParameters() public view {
|
||||
string[] memory template = new string[](4);
|
||||
template[0] = CommandUtils.STRING_MATCHER;
|
||||
template[1] = CommandUtils.UINT_MATCHER;
|
||||
template[2] = CommandUtils.STRING_MATCHER;
|
||||
template[3] = "!";
|
||||
|
||||
string memory command = "user 123 token !";
|
||||
string memory result1 = _helper.callExtractCommandParamByIndex(template, command, 0);
|
||||
string memory result2 = _helper.callExtractCommandParamByIndex(template, command, 1);
|
||||
string memory result3 = _helper.callExtractCommandParamByIndex(template, command, 2);
|
||||
|
||||
assertEq(result1, "user");
|
||||
assertEq(result2, "123");
|
||||
assertEq(result3, "token");
|
||||
}
|
||||
|
||||
function test_realEnsClaimCommand() public view {
|
||||
string[] memory template = new string[](9);
|
||||
template[0] = "Claim";
|
||||
template[1] = "ENS";
|
||||
template[2] = "name";
|
||||
template[3] = "for";
|
||||
template[4] = "address";
|
||||
template[5] = CommandUtils.ETH_ADDR_MATCHER;
|
||||
template[6] = "with";
|
||||
template[7] = "resolver";
|
||||
template[8] = CommandUtils.STRING_MATCHER;
|
||||
|
||||
string memory command =
|
||||
"Claim ENS name for address 0xafBD210c60dD651892a61804A989eEF7bD63CBA0 with resolver resolver.eth";
|
||||
string memory result1 = _helper.callExtractCommandParamByIndex(template, command, 0);
|
||||
string memory result2 = _helper.callExtractCommandParamByIndex(template, command, 1);
|
||||
|
||||
assertEq(result1, "0xafBD210c60dD651892a61804A989eEF7bD63CBA0");
|
||||
assertEq(result2, "resolver.eth");
|
||||
}
|
||||
|
||||
function test_simpleEnsClaimCommand() public view {
|
||||
string[] memory template = new string[](6);
|
||||
template[0] = "Claim";
|
||||
template[1] = "ENS";
|
||||
template[2] = "name";
|
||||
template[3] = "for";
|
||||
template[4] = "address";
|
||||
template[5] = CommandUtils.ETH_ADDR_MATCHER;
|
||||
|
||||
string memory command = "Claim ENS name for address 0xafBD210c60dD651892a61804A989eEF7bD63CBA0";
|
||||
string memory result = _helper.callExtractCommandParamByIndex(template, command, 0);
|
||||
assertEq(result, "0xafBD210c60dD651892a61804A989eEF7bD63CBA0");
|
||||
}
|
||||
}
|
||||
@@ -4,18 +4,6 @@ pragma solidity ^0.8.30;
|
||||
import { CircuitUtils } from "../../CircuitUtils.sol";
|
||||
|
||||
contract CircuitUtilsHelper {
|
||||
function callExtractCommandParamByIndex(
|
||||
string[] memory template,
|
||||
string memory command,
|
||||
uint256 index
|
||||
)
|
||||
external
|
||||
pure
|
||||
returns (string memory)
|
||||
{
|
||||
return CircuitUtils.extractCommandParamByIndex(template, command, index);
|
||||
}
|
||||
|
||||
function callFlattenFields(uint256[][] memory inputs, uint256 outLength) external pure returns (uint256[] memory) {
|
||||
return CircuitUtils.flattenFields(inputs, outLength);
|
||||
}
|
||||
|
||||
@@ -2734,19 +2734,11 @@ __metadata:
|
||||
dependencies:
|
||||
"@openzeppelin/contracts": 5.3.0
|
||||
"@openzeppelin/contracts-upgradeable": 5.3.0
|
||||
"@zk-email/email-tx-builder": "https://github.com/zkemail/email-tx-builder#9620b7bbec4a2e15704f01ccc2635ec66bedbf7b"
|
||||
dotenv: ^16.3.1
|
||||
forge-std: "https://github.com/foundry-rs/forge-std#v1.10.0"
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@zk-email/email-tx-builder@https://github.com/zkemail/email-tx-builder#9620b7bbec4a2e15704f01ccc2635ec66bedbf7b":
|
||||
version: 1.0.0
|
||||
resolution: "@zk-email/email-tx-builder@https://github.com/zkemail/email-tx-builder.git#commit=9620b7bbec4a2e15704f01ccc2635ec66bedbf7b"
|
||||
checksum: da3d79f0299202794f161b0019a2d32f56530e28ae248b5ef3b0388e90546377767f28d7ae2690d259c878126d3d2f3e48f45a4e62081a7bb25371bcfe5bf517
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@zk-email/helpers@workspace:packages/helpers":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@zk-email/helpers@workspace:packages/helpers"
|
||||
|
||||
Reference in New Issue
Block a user