How can I pass a complex type when calling my smart contract on Hedera? - hedera-hashgraph

I have a basic contract that looks like this:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
pragma abicoder v2;
contract testStruct {
struct Example {
uint256 number;
address user;
}
Example public example;
function set_struct(Example memory _example) public {
example = _example;
}
}
I have tried using this sdk like this.
//Create the transaction
const transaction = new ContractExecuteTransaction()
.setContractId(newContractId)
.setGas(100_000_000)
.setFunction("set_struct", new ContractFunctionParameters()
.addBytesArray(byte[][] structInBytes)
Some data type are not presented in the SDK. How can I call a smart contract and pass a complex type like a struct ?

If you are using structs as inputs/outputs to your contracts, or data types that aren't supported by the SDKs, you should check this example repo out which shows how to use commonly known libraries (web3.js, ethers.js, web3.j and abiDecode.js) to encode and decode contract function parameters and results https://github.com/hashgraph/hedera-smart-contracts-libs-lab
For example:
// get the constructor parameter
// .slice(2) to remove leading '0x'
const constructParameterAsHexString = abiInterface.encodeDeploy([constructMessage]).slice(2);
// convert to a Uint8Array
const constructorParametersAsUint8Array = Buffer.from(constructParameterAsHexString, 'hex');

Related

return nested array solidity

Is it possible to return an array in solidity?
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0 <0.9.0;
pragma experimental ABIEncoderV2;
contract Test {
constructor() {}
function multiArray() external pure returns (uint256[2][] memory doubleArray) {
doubleArray[0] = [uint(12345678),uint(1234567)];
return doubleArray;
}
}
this does not work, but I thought with solidity > 0.8.0 it should be possible, also with "ABIEncoderV2"?
Nested arrays are still incomplete but they work at a certain level.
Currently, nested arrays can only be used within an internal call to functions that are either private or internal. They should also be stored in storage or memory.
The biggest issue is using them in the calldata as a parameter or return statement which is not yet supported.
I'll recommend trying to find another way to return the nested array information like a mapping, struct, or even returning multiple lists and then working with them inside the function.
Another alternative is to pass the data as bytes and extract the array data or vice-versa. However, this can have a high gas cost on large arrays and some other problems. To use this method you can take advantage of the new ABI encoder.
Solidity support 1D array only. Multidimensional arrays are yet to come.
// SPDX-License-Identifier: GPL-3.0;
pragma solidity >=0.7.0 <0.9.0;
contract Test{
string[] A=["A","B"];
function fun() public view returns(string[] memory){
return A;
}
}
Try to initialize the array first and then return values by index. You can also use a mapping, but keep in mind you can't easily iterate over it.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract NestedArrays{
mapping(uint256 => uint256[]) mappingArray;
uint256[2][] multiArray;
constructor(){
multiArray.push([1,2]);
multiArray.push([3,4]);
mappingArray[0] = [10,20];
mappingArray[1] = [30,40];
}
function getMultiArray() public view returns(uint256[2][] memory){
return multiArray;
}
function getMultiArrayMember(uint256 index) public view returns(uint256[2] memory){
require(multiArray.length > index, "wrong index");
return multiArray[index];
}
function getMappingArrayMember(uint256 index) public view returns(uint256[] memory){
return mappingArray[index];
}
}

Swift - Generic Structs in array, casting back and sending as a method parameter

I am having a generic struct that can be passed to a generic method as a parameter. This works well.
But I need to store these structs in an array and pass it to that generic method later.
The problem is that I cannot cast it back to the type.
Playground code will explain what is my problem:
import Foundation
protocol ThingProtocol { }
struct Thing<T>: ThingProtocol {
}
func doSomethingWithThing<T>(thing: Thing<T>) {
print(thing)
}
let t1 = Thing<Int>()
let t2 = Thing<String>()
let t3 = Thing<Date> ()
doSomethingWithThing(thing: t1)
doSomethingWithThing(thing: t2)
doSomethingWithThing(thing: t3)
var thingArray = [t1, t2, t3] as [ThingProtocol]
thingArray.forEach {
//How to call doSomethingWithThing with $0?
//doSomethingWithThing(thing: $0)
}
I've been trying to use protocols, but that didn't work well.
All Generics conform to Decodable protocol, but I cannot make a use of it.
Any ideas of how to achieve something like that?
PS. method doSomethingWithThing cannot be changed to use a protocol, it needs to be a generic method
I cannot extend all used types in that generic (too many of them)

Solidity - initialize string array in struct

I am currently working on my first smart contract. After already reading a few topics out there I still don't have a clue on how to initialize the string array inside my struct.
The idea is that the customer can always choose from a variety of energysources on a homepage which then gets deployed on the smart contract if he's done choosing.
So what would be the best/efficient way to implement this idea onto the blockchain?
pragma solidity ^0.4.23; /* solhint-disable */
contract EnergyContract {
struct EnContract {
uint price;
uint amount;
string[] energysource;
address creator;
}
EnContract[] aContract;
function createContract(uint _price, uint _amount, address _creator) public {
aContract.length += 1;
EnContract storage _EnContract = aContract[aContract.length - 1];
_EnContract.price = _price;
_EnContract.amount = _amount;
_EnContract.creator = _creator;
}
}
The way you declare your array is correct. You don't need to do anything else. You can just start pushing data into the array.

Solidity: UnimplementedFeatureError: Nested dynamic arrays not implemented here

When I try to do this in Solidity, it gives me
UnimplementedFeatureError: Nested dynamic arrays not implemented here.
I see this in code examples. Does Solidity not support this?
Edit - posted complete code below. So I figured out the problem is only in the last function. It doesn't like that I am returning a dynamic array. How could I implement the same functionality (I want to return a string array of data)?
pragma solidity ^0.4.6;
contract EmailIntegrity {
// Map an array of EmailIntegrityStructs for each email address.
// The first element will be used for the integrity record.
// The rest will be used for audit records.
enum ItemType { Integrity, Audit }
struct EmailIntegrityStruct {
ItemType itemType;
uint timestamp;
string data;
}
mapping(address => EmailIntegrityStruct[]) emailIntegrityStructs;
function hasEmailIntegrityData(address emailAddress) public constant returns(bool isEmail) {
return emailIntegrityStructs[emailAddress][0].timestamp == 0;
}
function insertIntegrityData(address emailAddress, uint timestamp, string data) public returns(bool success) {
if (hasEmailIntegrityData(emailAddress)) {
revert();
}
EmailIntegrityStruct memory integrityData;
integrityData.itemType = ItemType.Integrity;
integrityData.timestamp = timestamp;
integrityData.data = data;
emailIntegrityStructs[emailAddress].push(integrityData);
return emailIntegrityStructs[emailAddress].length == 1;
}
function insertAuditData(address emailAddress, uint timestamp, string data) public returns(bool success) {
if (!hasEmailIntegrityData(emailAddress)) {
revert();
}
EmailIntegrityStruct memory auditData;
auditData.itemType = ItemType.Audit;
auditData.timestamp = timestamp;
auditData.data = data;
emailIntegrityStructs[emailAddress].push(auditData);
return emailIntegrityStructs[emailAddress].length > 1;
}
function getIntegrityData(address emailAddress) public constant returns(string data) {
if (!hasEmailIntegrityData(emailAddress)) {
revert();
}
return emailIntegrityStructs[emailAddress][0].data;
}
function getAuditData(address emailAddress) public constant returns(string[] data) {
if (!hasEmailIntegrityData(emailAddress)) {
revert();
}
var length = emailIntegrityStructs[emailAddress].length;
string[] memory auditData = new string[](length - 1);
for (uint i = 1; i < length ; i++) {
auditData[i] = emailIntegrityStructs[emailAddress][i].data;
}
return auditData;
}
}
Solidity and Javascript allow nested arrays but we do not have the ability to pull a nested dynamic array from the solidity over to javascript world.
it is the limitation of the bridge between solidity and javascript. Since strings inside of solidity are represented as dynamic arrays, we cannot transfer array of strings.
UPDATE
Since then, solidity has evolved, you can return dynamic array including structs. A test contract:
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
contract Test {
struct User{
string name;
string LastName;
}
User[] public store;
function addToStorage() external returns (User[] memory ) {
User memory newUser=User(
"yilmads","bin"
);
store.push(newUser);
return store;
}
}
This compiled fine for me.
I added a definition of MyStruct and upped the Solidity version to the current one (though it compiled fine with the old pragma too). Here's the code I compiled via Remix:
pragma solidity ^0.4.19;
contract MyContract{
struct MyStruct {
uint256 foo;
}
mapping(address => MyStruct[]) myStruct;
}
Could it be that you're using an older version of the Solidity compiler? (The ^0.4.6 made me think that perhaps you are.)
What's your MyStruct? Perhaps a more interesting structure there would fail. In general, please try to provide full code samples that reproduce the problem you're seeing.

How to get the class of a VALUE in Ruby C API

I created some classes with Ruby's C API. I want to create a function whose behavior will change depending on the class of the Ruby object.
I tried to use is_a? from Ruby, however, I don't think it's the good way to do this. I checked "Creating Extension Libraries for Ruby" without success. The only direct way to check classes is with the default types.
I have my class "Klass" already created:
VALUE rb_cKlass = rb_define_class("Klass", rb_cObject);
And how I wanted to check if the class is the good one:
VALUE my_function(VALUE self, VALUE my_argument) {
if(rb_check_class(my_argument), rb_cKlass)) {
// do something if my_argument is an instance of Klass
} else {
return Qnil;
}
}
Is there a way to do this?
I came across this recently, and used the RBASIC_CLASS macro, but was getting segfaults in certain scenarios for some unexplained reason.
After scanning through ruby.h, I found the CLASS_OF macro, which returns the class as VALUE of a given object.
VALUE obj = INT2NUM(10);
VALUE klass = CLASS_OF(obj); // rb_cInteger
Using Ruby 2.5
Every ruby object is internally represented by RObject struct (I will copy the source here for the sake of future readers):
struct RObject {
struct RBasic basic;
union {
struct {
uint32_t numiv;
VALUE *ivptr;
void *iv_index_tbl; /* shortcut for RCLASS_IV_INDEX_TBL(rb_obj_class(obj)) */
} heap;
VALUE ary[ROBJECT_EMBED_LEN_MAX];
} as;
};
The very first member, RBasic, defines the class:
struct RBasic {
VALUE flags;
const VALUE klass;
}
To get an access to RBasic metadata of anything, one might use RBASIC macro:
RBASIC(my_argument)
To get the class directly, one might use RBASIC_CLASS macro:
RBASIC_CLASS(my_argument)
If you want to stay close to the is_a? Ruby fashion (i.e. check if any of the ancestors is the expected class), you could directly use the C implementation of is_a?, rb_obj_is_kind_of:
rb_obj_is_kind_of(my_argument, rb_cKlass) // Qtrue OR Qfalse
And since Qfalse == 0, you can just use that method as a condition:
VALUE my_function(VALUE self, VALUE my_argument) {
if(rb_obj_is_kind_of(my_argument, rb_cKlass)) {
// do something if my_argument is an instance of Klass
} else {
return Qnil;
}
}
To find this method, just check Object#is_a? documentation and click to toggle source, you'll see the C implementation if it is a C function (hence this will work for most of the standard lib).

Resources