hashgraph / hashgraph/hedera-sdk-reference
ABI support in SDKs
- Dominant language
- HTML
- Stars
- 7
- Forks
- 3
- PR merge metrics
- No merged PRs in 30d
Description
### Problem
Across SDKs, we've got the following functionalities:
- ContractCallQuery - returning a result of executing a function
- ContractCreateFlow - which is returning only receipt
- ContractCreateTransaction - which is returning only the receipt
- ContractExecuteTransaction - which returns only receipt, but not a result of the call (if we call a function)
All those flows use `ContractFunctionParameters()`.
In the `ContractFunctionParameters()` we’ve got the following methods:
- addString
- addStringArray
- addBytes
- addBytes32
- addBytesArray
- addBytes32Array
- addBool
- addInt8
- addUint8
- addInt16
- addUint16
and so on…. [a file with `1700`](https://github.com/hashgraph/hedera-sdk-js/blob/develop/src/contract/ContractFunctionParameters.js) lines and a lot of methods, switch cases, and IFs.
### **The workflow is as follows:**
- We are calling some of the “add methods” of `ContractFunctionParameters`
- Then, we call `_addParam`
- Then we call `argumentToBytes` and convert the passing params to the function to bytes (`Uint8Array`)
Then we got `ContractFunctionSelector` [file with `1400`](https://github.com/hashgraph/hedera-sdk-js/blob/develop/src/contract/ContractFunctionSelector.js) lines of code.
We are using that file with all the helper methods inside to create the signature of the function.
### **For example:**
- We’ve got `ArgumentType` to integers
- We’ve got different methods such as `addString` which returns the signature of the function
- We’ve got `solidityTypeToString` where we are transpile solidity types to string, for example:
```
case ArgumentType.uint8:
s = "uint8";
```
This all is created because we are not requiring the ABI of a contract when we are doing:
- ContractCallQuery
- ContractCreateFlow
- ContractCreateTransaction
- ContractExecuteTransaction
- ….etc
**The above workflow assumes that the user will know the exact parameters that a function is accepting when performing the above calls. According to my opinion, this could lead to errors and unpredicted behavior because of the missing or wrong passed params.**
We can use the **ABI** of the contract and then pass params. We can leave the transforming of the contract function params to bytes to the SDK and then decode them back to the SDK.
For example, when we are retrieving results from:
- ContractFunctionResult
we need to decode manually the response again using similar functions as in `ContractFunctionParameters` :
- `getUint40` and to pass the index of the returned param of the contract function
As you can see, this is not convenient, because the users must know the signature of the functions (what is accepting and what is returning).
### Solution
### **Encoding and passing data to contract**
- We can add the following setter and function params:
```
setAbi()
```
```
callFunction
```
- setAbi will receive the ABI of the compiled contract, for example:
```
.setAbi(setDataContract.abi)
```
- callFunction will receive the signature of the function together with the passed params, for example:
```
callFunction("setMultipleMessages", [
"New Message",
"Second New Message",
]);
```
### **Decoding and retrieving data from the contract**
I’ve implemented a method called:
`const result = txResponse.getResult(["uint32", "uint64", "string"]);`
Where you can pass the signature of the function (from the ABI) and use it to decode and return the result.
The method `getResult` is tested in production (actually it is released because a lof of people had problems decoding data from contract calls).
### Alternatives
## **Notes from the last meeting:**
For passing the input:
- Maybe the whole ABI is too much information
- We can use a similar approach to the `getResult` function with something like:
- setValue (with passing the signature)
- setABIFunction (not sure the “ABI” terminology is used correctly here)
- setFunctionSignature
For getting the output:
- we can keep the method `getResult` passing the function signature
For different SDKs:
- We need to consider using the ready-to-be-used solutions for ABI encode/decode or write our own (this will be quite big enough because the SDKs are trying now to do it on their own and the result is that only the main cases (straightforward) are supported.
- SDKs potential libraries that we can use:
- GO SDK Quick example: https://go.dev/play/p/VSmWHUavjMZ (checked ✅)
- JAVA:
- for ABI encode/decode they are using headlong (checked ✅)
- for RLP operations they are using web3j (checked ✅)
- C++: 1. за `C++` - [[Silkworm](https://github.com/torquem-ch/silkworm)](https://github.com/torquem-ch/silkworm) (still WIP). Requires `C++20` compiler, which does not work at the moment because `Hedera C++ SDK` uses `C++17` (to be checked)
- Rust: https://github.com/gakonst/ethers-rs (to be checked)
- Swift: https://github.com/gnosis/Web3.swift or https://github.com/Boilertalk/Web3.swift (to be checked)
Contributor guide
Assessment
This issue has not been assessed yet.