diff --git a/solidity/TestTokenForZK/README.md b/solidity/TestTokenForZK/README.md new file mode 100644 index 000000000..60781f75e --- /dev/null +++ b/solidity/TestTokenForZK/README.md @@ -0,0 +1,6 @@ +This contract was created on October 17, 2024, at the address 0x8bA6144A8615Ad0fA1f781E631F16C7502fc5283 on the following network instance: + +L2 Explorer: http://108.61.209.124:4001/ +RPC: http://136.244.112.12:8123 +ChainID: 1010 +Symbol: TLOS \ No newline at end of file diff --git a/solidity/TestTokenForZK/TestTokenForZK.sol b/solidity/TestTokenForZK/TestTokenForZK.sol new file mode 100644 index 000000000..aeef85359 --- /dev/null +++ b/solidity/TestTokenForZK/TestTokenForZK.sol @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.18; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/access/Ownable.sol"; + +/** + * @title TestTokenForZK + * @dev ERC20 token called TESTZK with additional functionality for purchasing with ETH, + * transferring the contract's balances to the owner, and managing contract ownership. + */ +contract TestTokenForZK is ERC20, Ownable { + uint256 public constant TOKENS_PER_ETH = 1000; // Exchange rate of 1000 TESTZK per 1 ETH + + /** + * @dev Constructor that initializes the TESTZK token with an initial supply of 0, + * sets the token name as "Test Token ZK" and the symbol as "TESTZK", + * and assigns ownership to the contract deployer. + */ + constructor() ERC20("Test Token ZK", "TESTZK") Ownable() { + // Initial supply is 0, no need for initial minting in the constructor + } + + /** + * @notice Allows users to buy TESTZK tokens by sending ETH to the contract. + * @dev For every ETH sent, the buyer will receive 1000 TESTZK. + * The tokens are minted to the buyer in the transaction. + */ + function buyTokens() external payable { + require(msg.value > 0, "You must send some ETH to buy tokens."); + uint256 amountToMint = msg.value * TOKENS_PER_ETH; + _mint(msg.sender, amountToMint); // Mint the calculated amount of TESTZK tokens to the buyer + } + + /** + * @notice Returns the ETH balance held by the contract. + * @return The ETH balance in wei. + */ + function getContractEthBalance() external view returns (uint256) { + return address(this).balance; + } + + /** + * @notice Returns the TESTZK token balance held by the contract. + * @return The TESTZK token balance in the contract. + */ + function getContractTokenBalance() external view returns (uint256) { + return balanceOf(address(this)); + } + + /** + * @notice Transfers the entire ETH balance from the contract to the owner. + * @dev Can only be executed by the owner of the contract. + */ + function withdrawAllEth() external onlyOwner { + uint256 contractEthBalance = address(this).balance; + require(contractEthBalance > 0, "No ETH to withdraw."); + payable(owner()).transfer(contractEthBalance); + } + + /** + * @notice Transfers the entire TESTZK token balance from the contract to the owner. + * @dev Can only be executed by the owner of the contract. + */ + function withdrawAllTokens() external onlyOwner { + uint256 contractTokenBalance = balanceOf(address(this)); + require(contractTokenBalance > 0, "No TESTZK tokens to withdraw."); + _transfer(address(this), owner(), contractTokenBalance); + } + + /** + * @notice Allows the owner to transfer the contract's ownership to a new address. + * @param newOwner The address of the new owner. + * @dev Can only be executed by the current owner. + */ + function changeOwner(address newOwner) external onlyOwner { + require(newOwner != address(0), "New owner address cannot be the zero address."); + transferOwnership(newOwner); + } +} diff --git a/solidity/TupleInputFunctionsContract/README.md b/solidity/TupleInputFunctionsContract/README.md new file mode 100644 index 000000000..d1198af43 --- /dev/null +++ b/solidity/TupleInputFunctionsContract/README.md @@ -0,0 +1 @@ +Verification successful! perfectly verified at Telos EVM Mainnet:0xc5F13247b1a2547Fd0f6C7696695cDFeB003027c \ No newline at end of file diff --git a/solidity/TupleInputFunctionsContract/TupleInputFunctionsContract.sol b/solidity/TupleInputFunctionsContract/TupleInputFunctionsContract.sol new file mode 100644 index 000000000..bc88c6280 --- /dev/null +++ b/solidity/TupleInputFunctionsContract/TupleInputFunctionsContract.sol @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.18; + +/** + * @title TupleInputFunctionsContract + * @dev This contract demonstrates functions that take various structs (tuples) and complex data types as input parameters. + * It is designed to test the interaction with functions that require both simple and complex tuples, as well as arrays. + */ +contract TupleInputFunctionsContract { + + /// @dev Simple structure with a single uint256 field. + struct SimpleStruct { + uint256 value; + } + + /// @dev Structure with two fields of the same type, uint256. + struct DoubleUintStruct { + uint256 value1; + uint256 value2; + } + + /// @dev Structure with two fields of different types: address and uint256. + struct AddressUintStruct { + address user; + uint256 amount; + } + + /// @dev More complex structure with three fields of different types. + struct ComplexStruct { + uint256 id; + address user; + bool isActive; + } + + /// @dev Structure that contains another structure (nested). + struct NestedStruct { + SimpleStruct simple; + AddressUintStruct userInfo; + bool isVerified; + } + + /// @dev Event emitted when a function is called. + event StructProcessed(string functionName, string message, bytes32 dataHash); + + /** + * @notice Processes a simple tuple with a single uint256 field. + * @param simple Struct with a `value` field. + */ + function process01SimpleStruct(SimpleStruct memory simple) external { + emit StructProcessed("process01SimpleStruct", "Processed simple struct with uint256.", keccak256(abi.encode(simple.value))); + } + + /** + * @notice Processes a tuple with two uint256 fields. + * @param doubleUint Struct with `value1` and `value2` fields. + */ + function process02DoubleUintStruct(DoubleUintStruct memory doubleUint) external { + emit StructProcessed("process02DoubleUintStruct", "Processed struct with two uint256 fields.", keccak256(abi.encode(doubleUint.value1, doubleUint.value2))); + } + + /** + * @notice Processes a tuple with an address and a uint256. + * @param addressUint Struct with an address and a uint256 field. + */ + function process03AddressUintStruct(AddressUintStruct memory addressUint) external { + emit StructProcessed("process03AddressUintStruct", "Processed struct with address and uint256.", keccak256(abi.encode(addressUint.user, addressUint.amount))); + } + + /** + * @notice Processes a more complex tuple with three mixed fields. + * @param complex Struct with `id`, `user`, and `isActive` fields. + */ + function process04ComplexStruct(ComplexStruct memory complex) external { + emit StructProcessed("process04ComplexStruct", "Processed complex struct with uint256, address, and bool.", keccak256(abi.encode(complex.id, complex.user, complex.isActive))); + } + + /** + * @notice Processes a tuple that contains another nested struct. + * @param nested Nested struct containing other structs. + */ + function process05NestedStruct(NestedStruct memory nested) external { + emit StructProcessed("process05NestedStruct", "Processed nested struct with simple and addressUint structs.", keccak256(abi.encode(nested.simple.value, nested.userInfo.user, nested.userInfo.amount, nested.isVerified))); + } + + /** + * @notice Processes a struct with a string field. + * @param value A string field. + */ + function process06String(string memory value) external { + emit StructProcessed("process06String", "Processed struct with string field.", keccak256(abi.encode(value))); + } + + /** + * @notice Processes a struct with a bytes32 field. + * @param value A bytes32 field. + */ + function process07Bytes32(bytes32 value) external { + emit StructProcessed("process07Bytes32", "Processed struct with bytes32 field.", keccak256(abi.encode(value))); + } + + /** + * @notice Processes an array of SimpleStruct. + * @param values An array of SimpleStruct. + */ + function process08ArrayOfStructs(SimpleStruct[] memory values) external { + // Example logic: Process an array of structs. + for (uint i = 0; i < values.length; i++) { + emit StructProcessed("process08ArrayOfStructs", "Processed array of SimpleStruct.", keccak256(abi.encode(values[i].value))); + } + } + + /** + * @notice Processes an array of uint256 values. + * @param values An array of uint256 values. + */ + function process09Uint256Array(uint256[] memory values) external { + // Example logic: Process an array of uint256 values. + emit StructProcessed("process09Uint256Array", "Processed uint256 array.", keccak256(abi.encode(values))); + } + + /** + * @notice Processes an array of string values. + * @param values An array of string values. + */ + function process10StringArray(string[] memory values) external { + // Example logic: Process an array of strings. + for (uint i = 0; i < values.length; i++) { + emit StructProcessed("process10StringArray", "Processed string array.", keccak256(abi.encode(values[i]))); + } + } + + /** + * @notice Processes a fixed-size array of addresses. + * @param addresses A fixed-size array of 3 addresses. + */ + function process11FixedAddressArray(address[3] memory addresses) external { + // Example logic: Process a fixed-size array of addresses. + emit StructProcessed("process11FixedAddressArray", "Processed fixed-size address array.", keccak256(abi.encode(addresses))); + } + + /** + * @notice Processes an array of complex structs. + * @param tuples An array of ComplexStruct. + */ + function process12ArrayOfComplexStructs(ComplexStruct[] memory tuples) external { + // Example logic: Process an array of complex structs. + for (uint i = 0; i < tuples.length; i++) { + emit StructProcessed("process12ArrayOfComplexStructs", "Processed array of ComplexStruct.", keccak256(abi.encode(tuples[i].id, tuples[i].user, tuples[i].isActive))); + } + } + + /** + * @notice Processes a fixed-size array of tuples with mixed fields. + * @param tuples An array of 3 ComplexStruct. + */ + function process13FixedComplexArray(ComplexStruct[3] memory tuples) external { + // Example logic: Process a fixed-size array of complex structs. + for (uint i = 0; i < tuples.length; i++) { + emit StructProcessed("process13FixedComplexArray", "Processed fixed-size array of ComplexStruct.", keccak256(abi.encode(tuples[i].id, tuples[i].user, tuples[i].isActive))); + } + } + + /** + * @notice Processes a fixed-size array of nested structs. + * @param tuples An array of 2 NestedStruct. + */ + function process14FixedNestedArray(NestedStruct[2] memory tuples) external { + // Example logic: Process a fixed-size array of nested structs. + for (uint i = 0; i < tuples.length; i++) { + emit StructProcessed("process14FixedNestedArray", "Processed fixed-size array of NestedStruct.", keccak256(abi.encode(tuples[i].simple.value, tuples[i].userInfo.user, tuples[i].userInfo.amount, tuples[i].isVerified))); + } + } +} diff --git a/solidity/TupleInputFunctionsContract/TupleInputFunctionsContract_metadata.json b/solidity/TupleInputFunctionsContract/TupleInputFunctionsContract_metadata.json new file mode 100644 index 000000000..b68a9f0af --- /dev/null +++ b/solidity/TupleInputFunctionsContract/TupleInputFunctionsContract_metadata.json @@ -0,0 +1,535 @@ +{ + "compiler": { + "version": "0.8.18+commit.87f61d96" + }, + "language": "Solidity", + "output": { + "abi": [ + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "string", + "name": "functionName", + "type": "string" + }, + { + "indexed": false, + "internalType": "string", + "name": "message", + "type": "string" + }, + { + "indexed": false, + "internalType": "bytes32", + "name": "dataHash", + "type": "bytes32" + } + ], + "name": "StructProcessed", + "type": "event" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "internalType": "struct TupleInputFunctionsContract.SimpleStruct", + "name": "simple", + "type": "tuple" + } + ], + "name": "process01SimpleStruct", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "value1", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "value2", + "type": "uint256" + } + ], + "internalType": "struct TupleInputFunctionsContract.DoubleUintStruct", + "name": "doubleUint", + "type": "tuple" + } + ], + "name": "process02DoubleUintStruct", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct TupleInputFunctionsContract.AddressUintStruct", + "name": "addressUint", + "type": "tuple" + } + ], + "name": "process03AddressUintStruct", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "internalType": "bool", + "name": "isActive", + "type": "bool" + } + ], + "internalType": "struct TupleInputFunctionsContract.ComplexStruct", + "name": "complex", + "type": "tuple" + } + ], + "name": "process04ComplexStruct", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "components": [ + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "internalType": "struct TupleInputFunctionsContract.SimpleStruct", + "name": "simple", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct TupleInputFunctionsContract.AddressUintStruct", + "name": "userInfo", + "type": "tuple" + }, + { + "internalType": "bool", + "name": "isVerified", + "type": "bool" + } + ], + "internalType": "struct TupleInputFunctionsContract.NestedStruct", + "name": "nested", + "type": "tuple" + } + ], + "name": "process05NestedStruct", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "value", + "type": "string" + } + ], + "name": "process06String", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "value", + "type": "bytes32" + } + ], + "name": "process07Bytes32", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "internalType": "struct TupleInputFunctionsContract.SimpleStruct[]", + "name": "values", + "type": "tuple[]" + } + ], + "name": "process08ArrayOfStructs", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256[]", + "name": "values", + "type": "uint256[]" + } + ], + "name": "process09Uint256Array", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string[]", + "name": "values", + "type": "string[]" + } + ], + "name": "process10StringArray", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address[3]", + "name": "addresses", + "type": "address[3]" + } + ], + "name": "process11FixedAddressArray", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "internalType": "bool", + "name": "isActive", + "type": "bool" + } + ], + "internalType": "struct TupleInputFunctionsContract.ComplexStruct[]", + "name": "tuples", + "type": "tuple[]" + } + ], + "name": "process12ArrayOfComplexStructs", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "id", + "type": "uint256" + }, + { + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "internalType": "bool", + "name": "isActive", + "type": "bool" + } + ], + "internalType": "struct TupleInputFunctionsContract.ComplexStruct[3]", + "name": "tuples", + "type": "tuple[3]" + } + ], + "name": "process13FixedComplexArray", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "components": [ + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "internalType": "struct TupleInputFunctionsContract.SimpleStruct", + "name": "simple", + "type": "tuple" + }, + { + "components": [ + { + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "internalType": "struct TupleInputFunctionsContract.AddressUintStruct", + "name": "userInfo", + "type": "tuple" + }, + { + "internalType": "bool", + "name": "isVerified", + "type": "bool" + } + ], + "internalType": "struct TupleInputFunctionsContract.NestedStruct[2]", + "name": "tuples", + "type": "tuple[2]" + } + ], + "name": "process14FixedNestedArray", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "devdoc": { + "details": "This contract demonstrates functions that take various structs (tuples) and complex data types as input parameters. It is designed to test the interaction with functions that require both simple and complex tuples, as well as arrays.", + "events": { + "StructProcessed(string,string,bytes32)": { + "details": "Event emitted when a function is called." + } + }, + "kind": "dev", + "methods": { + "process01SimpleStruct((uint256))": { + "params": { + "simple": "Struct with a `value` field." + } + }, + "process02DoubleUintStruct((uint256,uint256))": { + "params": { + "doubleUint": "Struct with `value1` and `value2` fields." + } + }, + "process03AddressUintStruct((address,uint256))": { + "params": { + "addressUint": "Struct with an address and a uint256 field." + } + }, + "process04ComplexStruct((uint256,address,bool))": { + "params": { + "complex": "Struct with `id`, `user`, and `isActive` fields." + } + }, + "process05NestedStruct(((uint256),(address,uint256),bool))": { + "params": { + "nested": "Nested struct containing other structs." + } + }, + "process06String(string)": { + "params": { + "value": "A string field." + } + }, + "process07Bytes32(bytes32)": { + "params": { + "value": "A bytes32 field." + } + }, + "process08ArrayOfStructs((uint256)[])": { + "params": { + "values": "An array of SimpleStruct." + } + }, + "process09Uint256Array(uint256[])": { + "params": { + "values": "An array of uint256 values." + } + }, + "process10StringArray(string[])": { + "params": { + "values": "An array of string values." + } + }, + "process11FixedAddressArray(address[3])": { + "params": { + "addresses": "A fixed-size array of 3 addresses." + } + }, + "process12ArrayOfComplexStructs((uint256,address,bool)[])": { + "params": { + "tuples": "An array of ComplexStruct." + } + }, + "process13FixedComplexArray((uint256,address,bool)[3])": { + "params": { + "tuples": "An array of 3 ComplexStruct." + } + }, + "process14FixedNestedArray(((uint256),(address,uint256),bool)[2])": { + "params": { + "tuples": "An array of 2 NestedStruct." + } + } + }, + "title": "TupleInputFunctionsContract", + "version": 1 + }, + "userdoc": { + "kind": "user", + "methods": { + "process01SimpleStruct((uint256))": { + "notice": "Processes a simple tuple with a single uint256 field." + }, + "process02DoubleUintStruct((uint256,uint256))": { + "notice": "Processes a tuple with two uint256 fields." + }, + "process03AddressUintStruct((address,uint256))": { + "notice": "Processes a tuple with an address and a uint256." + }, + "process04ComplexStruct((uint256,address,bool))": { + "notice": "Processes a more complex tuple with three mixed fields." + }, + "process05NestedStruct(((uint256),(address,uint256),bool))": { + "notice": "Processes a tuple that contains another nested struct." + }, + "process06String(string)": { + "notice": "Processes a struct with a string field." + }, + "process07Bytes32(bytes32)": { + "notice": "Processes a struct with a bytes32 field." + }, + "process08ArrayOfStructs((uint256)[])": { + "notice": "Processes an array of SimpleStruct." + }, + "process09Uint256Array(uint256[])": { + "notice": "Processes an array of uint256 values." + }, + "process10StringArray(string[])": { + "notice": "Processes an array of string values." + }, + "process11FixedAddressArray(address[3])": { + "notice": "Processes a fixed-size array of addresses." + }, + "process12ArrayOfComplexStructs((uint256,address,bool)[])": { + "notice": "Processes an array of complex structs." + }, + "process13FixedComplexArray((uint256,address,bool)[3])": { + "notice": "Processes a fixed-size array of tuples with mixed fields." + }, + "process14FixedNestedArray(((uint256),(address,uint256),bool)[2])": { + "notice": "Processes a fixed-size array of nested structs." + } + }, + "version": 1 + } + }, + "settings": { + "compilationTarget": { + "contracts/TupleInputFunctionsContract.sol": "TupleInputFunctionsContract" + }, + "evmVersion": "paris", + "libraries": {}, + "metadata": { + "bytecodeHash": "ipfs" + }, + "optimizer": { + "enabled": false, + "runs": 200 + }, + "remappings": [] + }, + "sources": { + "contracts/TupleInputFunctionsContract.sol": { + "keccak256": "0x6da901f1c951635457ed470d2251df9b4cf56880dcf2a73dfbc99baadf2f4f30", + "license": "MIT", + "urls": [ + "bzz-raw://7632a797d690d153058db2f5642b6dc7ed15e2d57d4f9d9078acc1003ee85c0b", + "dweb:/ipfs/QmU16rx4Uuz19wRjhP5txW3H8mnSre5Z8g5imeaioLKRQZ" + ] + } + }, + "version": 1 +} \ No newline at end of file diff --git a/src/components/AddressMoreInfo.vue b/src/components/AddressMoreInfo.vue index eb2f4f16e..a3d42d223 100644 --- a/src/components/AddressMoreInfo.vue +++ b/src/components/AddressMoreInfo.vue @@ -38,40 +38,40 @@ onBeforeMount(async () => { diff --git a/src/components/inputs/TupleStructInput.vue b/src/components/inputs/TupleStructInput.vue new file mode 100644 index 000000000..04ae810d4 --- /dev/null +++ b/src/components/inputs/TupleStructInput.vue @@ -0,0 +1,164 @@ + + + + + diff --git a/src/i18n/de-de/index.js b/src/i18n/de-de/index.js index ced60f0c7..69d5430e3 100644 --- a/src/i18n/de-de/index.js +++ b/src/i18n/de-de/index.js @@ -372,6 +372,11 @@ export default { incorrect_sigint_array_length: 'Das Array muss { size } signed Integers enthalten', incorrect_strings_array_length: 'Das Array sollte nur { size } Zeichenfolgen enthalten', incorrect_unsigint_array_length: 'Das Array muss { size } unsigned Integers enthalten', + incorrect_values_array_length: 'Es müssen { size } Werte im Array vorhanden sein', + incorrect_undefined_entry: 'Einige der Einträge sind nicht in einem gültigen Format', + incorrect_values_format: 'Einige der Werte sind nicht in einem gültigen Format', + tuple_struct_input_hint: 'Geben Sie die Tupelwerte in eckigen Klammern in der im Vertrag definierten Reihenfolge ein', + invalid_boolean_value: 'Der eingegebene Wert ist kein boolescher Wert', invalid_address_array_string: 'Eingegebener Wert repräsentiert kein Array von Adressen', invalid_booleans_array_string: 'Der eingegebene Wert entspricht keinem Array von bool(s)', invalid_bytes_array_string: 'Eingegebener Wert entspricht keinem Array von Bytes dar', diff --git a/src/i18n/en-us/index.js b/src/i18n/en-us/index.js index 0d0c14fcc..834825244 100644 --- a/src/i18n/en-us/index.js +++ b/src/i18n/en-us/index.js @@ -372,6 +372,11 @@ export default { incorrect_sigint_array_length: 'There should be { size } signed integers in the array', incorrect_strings_array_length: 'There should be { size } strings in the array', incorrect_unsigint_array_length: 'There should be { size } unsigned integers in the array', + incorrect_values_array_length: 'There must be { size } values in the array', + incorrect_undefined_entry: 'Some of the entries are not in a valid format', + incorrect_values_format: 'Some of the values are not in a valid format', + tuple_struct_input_hint: 'Enter the tuple values in square brackets in the order defined in the contract', + invalid_boolean_value: 'The entered value is not a boolean', invalid_address_array_string: 'Entered value does not represent an array of addresses', invalid_booleans_array_string: 'Entered value does not represent an array of bool', invalid_bytes_array_string: 'Entered value does not represent an array of bytes', diff --git a/src/i18n/es-es/index.js b/src/i18n/es-es/index.js index dce033b0d..1011d063b 100644 --- a/src/i18n/es-es/index.js +++ b/src/i18n/es-es/index.js @@ -372,6 +372,11 @@ export default { incorrect_sigint_array_length: 'Debe haber { size } enteros firmados en la matriz', incorrect_strings_array_length: 'Debe haber { size } cadenas en la matriz', incorrect_unsigint_array_length: 'Debe haber { size } enteros sin firmar en la matriz', + incorrect_values_array_length: 'Debe haber { size } valores en la matriz', + incorrect_undefined_entry: 'Alguna de las entradas no tiene un formato válido', + incorrect_values_format: 'Algunos de los valores no tienen un formato válido', + tuple_struct_input_hint: 'Ingrese los valores de la tupla entre paréntesis rectos en el orden en que se definen en el contrato', + invalid_boolean_value: 'El valor ingresado no es un booleano', invalid_address_array_string: 'El valor ingresado no representa una matriz de direcciones', invalid_booleans_array_string: 'El valor ingresado no representa una matriz de bool', invalid_bytes_array_string: 'El valor ingresado no representa una matriz de bytes', diff --git a/src/i18n/fr-fr/index.js b/src/i18n/fr-fr/index.js index d9421c2f8..38ef0d075 100644 --- a/src/i18n/fr-fr/index.js +++ b/src/i18n/fr-fr/index.js @@ -372,6 +372,11 @@ export default { incorrect_sigint_array_length: 'Le tableau doit contenir { size } entiers signés', incorrect_strings_array_length: 'Le tableau doit contenir { size } chaînes de caractères', incorrect_unsigint_array_length: 'Le tableau doit contenir { size } entiers non signés', + incorrect_values_array_length: 'Il doit y avoir { size } valeurs dans le tableau', + incorrect_undefined_entry: 'Certaines des entrées ne sont pas dans un format valide', + incorrect_values_format: 'Certaines des valeurs ne sont pas dans un format valide', + tuple_struct_input_hint: 'Entrez les valeurs de la structure de tuple entre crochets dans l\'ordre défini dans le contrat', + invalid_boolean_value: 'La valeur saisie n\'est pas un booléen', invalid_address_array_string: 'La valeur saisie ne represente pas un tableau d\'adresses', invalid_booleans_array_string: 'La valeur saisie ne represente pas un tableau de booléens', invalid_bytes_array_string: 'La valeur saisie ne represente pas un tableau de bytes', diff --git a/src/i18n/pt-br/index.js b/src/i18n/pt-br/index.js index 8cc076cd9..8857382e4 100644 --- a/src/i18n/pt-br/index.js +++ b/src/i18n/pt-br/index.js @@ -372,6 +372,11 @@ export default { incorrect_sigint_array_length: 'Deve haver { size } inteiros com sinal na matriz', incorrect_strings_array_length: 'Deve haver { size } strings (sequência de caracteres) na matriz', incorrect_unsigint_array_length: 'Deve haver { size } inteiros sem sinal na matriz', + incorrect_values_array_length: 'Devem haver { size } valores na matriz', + incorrect_undefined_entry: 'Algumas das entradas não estão em um formato válido', + incorrect_values_format: 'Alguns dos valores não estão em um formato válido', + tuple_struct_input_hint: 'Insira os valores da tupla entre colchetes na ordem definida no contrato', + invalid_boolean_value: 'O valor inserido não é um booleano', invalid_address_array_string: 'O valor inserido não representa uma matriz de endereços', invalid_booleans_array_string: 'O valor inserido não representa uma matriz de booleanos', invalid_bytes_array_string: 'O valor inserido não representa uma matriz de bytes', diff --git a/src/lib/contract/ContractManager.js b/src/lib/contract/ContractManager.js index 54dfadc89..79f70c8b6 100644 --- a/src/lib/contract/ContractManager.js +++ b/src/lib/contract/ContractManager.js @@ -387,10 +387,8 @@ export default class ContractManager { } else if (this.nullContractsManager.existsContract(addressLower)) { result = this.nullContractsManager.getContractInfo(addressLower); } else { - result = await this.getContract(addressLower); - if (result) { - result = this.nullContractsManager.getContractInfo(addressLower); - } + // We are going to always assume that if the address is a contract, it is already in the cache + // Because the indexer API should always return all involved contracts in a query response } return result; } diff --git a/src/lib/function-interface-utils.js b/src/lib/function-interface-utils.js index 783b6d4f2..c14e8e715 100644 --- a/src/lib/function-interface-utils.js +++ b/src/lib/function-interface-utils.js @@ -13,6 +13,8 @@ const asyncInputComponents = { UnsignedIntArrayInput: defineAsyncComponent(() => import('components/inputs/UnsignedIntArrayInput')), UnsignedIntInput: defineAsyncComponent(() => import('components/inputs/UnsignedIntInput')), SignedIntArrayInput: defineAsyncComponent(() => import('components/inputs/SignedIntArrayInput')), + TupleStructInput: defineAsyncComponent(() => import('components/inputs/TupleStructInput')), + TupleStructArrayInput: defineAsyncComponent(() => import('components/inputs/TupleStructArrayInput')), }; /** @@ -114,7 +116,33 @@ function parameterTypeIsUnsignedIntArray(type) { return /^uint\d+\[\d*]$/.test(type); } +/** + * Given a function interface type, returns true iff that type represents an signed integer, e.g. int32 + * @param {string} type + * @returns {boolean} + */ +function parameterTypeSignedInt(type) { + return /^int\d+$/.test(type); +} +/** + * Given a function interface type, returns true iff that type represents a tuple struct + * @param {string} type + * @returns {boolean} + */ + +function parameterTypeIsTupleStruct(type) { + return type === 'tuple'; +} + +/** + * Given a function interface type, returns true iff that type represents an array of tuple structs + * @param {string} type + * @returns {boolean} + */ +function parameterTypeIsTupleStructArray(type) { + return /^tuple\[\d*]$/.test(type); +} /** * Given a function interface type, returns true iff that type represents an array of any kind, e.g. string[] or uint8[] @@ -168,14 +196,17 @@ function integerSizeValidator(prop, signed) { * @returns {boolean} */ function inputIsComplex(type) { - return parameterIsIntegerType(type) || - parameterTypeIsAddress(type) || - parameterTypeIsAddressArray(type) || - parameterTypeIsBooleanArray(type) || - parameterTypeIsBytes(type) || - parameterTypeIsSignedIntArray(type) || - parameterTypeIsStringArray(type) || - parameterTypeIsUnsignedIntArray(type); + return parameterTypeIsSignedInt(type) || + parameterTypeIsAddress(type) || + parameterTypeIsAddressArray(type) || + parameterTypeIsBooleanArray(type) || + parameterTypeIsBytes(type) || + parameterTypeIsSignedIntArray(type) || + parameterTypeIsStringArray(type) || + parameterTypeIsUnsignedInt(type) || + parameterTypeIsUnsignedIntArray(type) || + parameterTypeIsTupleStruct(type) || + parameterTypeIsTupleStructArray(type); } /** @@ -208,6 +239,10 @@ function getComponentForInputType(type) { return asyncInputComponents.UnsignedIntInput; } else if (parameterTypeIsUnsignedIntArray(type)) { return asyncInputComponents.UnsignedIntArrayInput; + } else if (parameterTypeIsTupleStruct(type)) { + return asyncInputComponents.TupleStructInput; + } else if (parameterTypeIsTupleStructArray(type)) { + return asyncInputComponents.TupleStructArrayInput; } return undefined; @@ -338,7 +373,7 @@ function parseUintArrayString (str, expectedLength, expectedIntSize) { * Given a string, returns a BigNumber representation of that string iff it represents a solidity signed integer * and an expected size in bits is supplied * - * @param {string} str - e.g. "12" + * @param {string} str - e.g. "-12" * @param {number} expectedSizeInBits - integer from 8 to 256, must be multiple of 8, e.g. 64 for int64 * @returns {BigNumber|undefined} */ @@ -570,6 +605,191 @@ function parseStringArrayString(str, expectedLength) { return parsedArrayOfStrings; } +/** + * Given a string and a description (abi), returns a tuple struct iff the string is a valid JSON representation of a tuple + * + * @param str - JSON string representation of a tuple struct, e.g. '["abc", 23, 0x1234..12342]' + * @param abi - description of the tuple struct + * @returns {string|undefined} + */ +function parseTupleString(str, abi) { + const parsedTuple = parseTupleStringWithUnquotedAddresses(str); + try { + return processTupleJson(parsedTuple, abi); + } catch { + return undefined; + } +} + +/** + * Given a string, returns an JSON object representation of a tuple struct iff the string is a valid JSON representation + * It takes into account the possible unquoted addresses in the tuple struct + * @param {string} str - JSON string representation of a tuple struct, e.g. '["abc", 23, 0x1234..12342]' + */ +function parseTupleStringWithUnquotedAddresses(str) { + let parsedTuple; + + try { + parsedTuple = JSON.parse(str); + return parsedTuple; + } catch { + const notQuotedAddressRegex = /(? { + const quotedAddress = `"${_address}"`; + _str = str.replaceAll(_address, quotedAddress); + }); + + try { + parsedTuple = JSON.parse(_str); + return parsedTuple; + } catch { + return undefined; + } + } + + return undefined; + } +} + +/** + * Given an object and a description (abi), returns a tuple struct iff the object is a valid JSON representation of a tuple + * @param {object} json - JSON object representation of a tuple struct, e.g. { "0": "abc", "1": 23, "2": "0x1234..12342" } + * @param {object[]} abi - description of the tuple struct + * @returns {string|undefined} + */ +function processTupleJson(json, abi) { + if (Array.isArray(json) && json.length === abi.length) { + const parsed = []; + for (let i = 0; i < json.length; i++) { + const field = json[i]; + const fieldAbi = abi[i]; + const value = processTupleField(field, fieldAbi); + parsed.push(value); + } + return parsed; + } else { + throw new Error('Invalid tuple structure:\n' + JSON.stringify({ json, abi }, null, 4)); + } +} + +/** + * Given a field and its abi, returns the processed field + * @param {string} field + * @param {object} fieldAbi + * @returns {string} + */ +function processTupleField(field, fieldAbi) { + const uintMatch = /^uint(\d+)$/.exec(fieldAbi.type); + const intMatch = /^int(\d+)$/.exec(fieldAbi.type); + + if (uintMatch) { + const bits = parseInt(uintMatch[1], 10); + return parseUintString(field, bits); + } else if (intMatch) { + const bits = parseInt(intMatch[1], 10); + return parseSignedIntString(field, bits); + } else if (fieldAbi.type === 'address') { + return parseAddressString(field); + } else if (fieldAbi.type === 'bool') { + return parseBooleanString(field); + } else if (fieldAbi.type === 'string') { + return field; + } else if (fieldAbi.type === 'tuple') { + return parseTupleString(JSON.stringify(field), fieldAbi.components); + } else { + console.error('processTupleField() Unsupported tuple field type:', fieldAbi.type); + return field; + } +} + +/** + * Given a string and a description (abi), returns an array of tuple structs iff the string is a valid JSON representation of a tuple array + * @param {string} str - JSON string representation of a tuple array, e.g. '[["abc", 23, 0x1234..12342], ["def", 45, 0x5678..56789]]' + * @param {object[]} abi - description of the tuple struct + */ +function parseTupleArrayString(str, abi) { + const parsedTupleArray = parseTupleStringWithUnquotedAddresses(str); + try { + const parsed = []; + for (let i = 0; i < parsedTupleArray.length; i++) { + const tupleStr = JSON.stringify(parsedTupleArray[i]); + parsed.push(parseTupleString(tupleStr, abi)); + } + return parsed; + } catch { + return undefined; + } +} + + + +/** + * Given a function interface tuple input description, returns a placeholder string for that tuple input + */ +function createPlaceholderForTupleInput(componentDescription) { + let placeholder = '['; + for (let i = 0; i < +componentDescription.length; i++) { + if (parameterTypeIsSignedInt(componentDescription[i].type)) { + placeholder += '-123'; + } else if (parameterTypeIsUnsignedInt(componentDescription[i].type)) { + placeholder += '123'; + } else if (parameterTypeIsBoolean(componentDescription[i].type)) { + placeholder += 'true'; + } else if (parameterTypeIsString(componentDescription[i].type)) { + placeholder += '"abc"'; + } else if (parameterTypeIsAddress(componentDescription[i].type)) { + placeholder += '0x123...7890'; + } else if (parameterTypeIsBytes(componentDescription[i].type)) { + placeholder += '0x123...234'; + } else if (parameterTypeIsBooleanArray(componentDescription[i].type)) { + placeholder += '[true, false]'; + } else if (parameterTypeIsStringArray(componentDescription[i].type)) { + placeholder += '["abc", "def"]'; + } else if (parameterTypeIsAddressArray(componentDescription[i].type)) { + placeholder += '[0x123...7890, 0x123...7890]'; + } else if (parameterTypeIsUnsignedIntArray(componentDescription[i].type)) { + placeholder += '[123, 456]'; + } else if (parameterTypeIsSignedIntArray(componentDescription[i].type)) { + placeholder += '[-123, -456]'; + } else if (parameterTypeIsTupleStruct(componentDescription[i].type)) { + placeholder += createPlaceholderForTupleInput(componentDescription[i].components); + } else if (parameterTypeIsTupleStructArray(componentDescription[i].type)) { + const expectedSize = getExpectedArrayLengthFromParameterType(componentDescription[i].type); + placeholder += createPlaceholderForTupleArrayInput(componentDescription[i].components, expectedSize); + } + + if (i < +componentDescription.length - 1) { + placeholder += ', '; + } + } + placeholder += ']'; + return placeholder; +} + +/** + * Given a function interface tuple array input description, returns a placeholder string for that tuple array input + */ +function createPlaceholderForTupleArrayInput(componentDescription, expectedSize) { + let placeholder = '['; + const size = +expectedSize > 0 ? expectedSize : 1; + for (let i = 0; i < size; i++) { + placeholder += createPlaceholderForTupleInput(componentDescription); + if (i < size - 1) { + placeholder += ', '; + } + } + if (expectedSize === -1) { + placeholder += ', ...'; + } + placeholder += ']'; + return placeholder; +} + + export { parameterIsArrayType, @@ -590,8 +810,11 @@ export { parameterTypeIsSignedIntArray, parameterTypeIsString, parameterTypeIsStringArray, + parameterTypeSignedInt, parameterTypeIsUnsignedInt, parameterTypeIsUnsignedIntArray, + parameterTypeIsTupleStruct, + parameterTypeIsTupleStructArray, parseAddressArrayString, parseAddressString, @@ -602,4 +825,11 @@ export { parseStringArrayString, parseUintArrayString, parseUintString, + parseTupleString, + parseTupleArrayString, + + parseTupleStringWithUnquotedAddresses, + + createPlaceholderForTupleInput, + createPlaceholderForTupleArrayInput, }; diff --git a/src/pages/AccountPage.vue b/src/pages/AccountPage.vue index f204fbfaf..b415c5ad5 100644 --- a/src/pages/AccountPage.vue +++ b/src/pages/AccountPage.vue @@ -138,13 +138,19 @@ async function loadAccount() {