mhw0 / libethc

Open-source Ethereum C library
https://mhw0.github.io/libethc/
MIT License
46 stars 8 forks source link

Encode array of tuples #38

Closed dkamm closed 7 months ago

dkamm commented 7 months ago

Is there a way to encode an array of tuples? Would like to do the following in ethc but didn't seem like it was supported

from eth_abi.abi import encode

print(encode(("(uint64,uint64)[]",),([(1,2),(3,4)],)).hex())
DerXanRam commented 7 months ago

Is there a way to encode an array of tuples? Would like to do the following in ethc but didn't seem like it was supported

from eth_abi.abi import encode

print(encode(("(uint64,uint64)[]",),([(1,2),(3,4)],)).hex())

Hello brother. If you are asking encoding of ABI that contains array, You can do like this

for Instance, when u decode a data for uniswap's getAmountsOut method, u can code like this

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <ethc/abi.h>
#include <ethc/unit.h>
#include <ethc/hex.h>
#include <string.h>

using namespace std;
#define ok(ethcop) assert(ethcop >= 0)

int main()
{
    string function = "getAmountsOut(uint256,address[])"; // method name
    string pathA = "0x55d398326f99059ff775485246999027b3197955", pathB = "0xe9e7cea3dedca5984780bafc599bd69add087d56";
    uint64_t amt = 10000000000;

    char *path0, *path1, *fn, *hex;
    path0 = strdup(pathA.c_str());
    path1 = strdup(pathB.c_str());
    fn = strdup(function.c_str());

    struct eth_abi abi;
    uint64_t arraySize = 2;
    size_t hexlen;

    eth_abi_init(&abi, ETH_ABI_ENCODE);
    eth_abi_call(&abi, &fn, NULL);
    eth_abi_uint64(&abi, &amt);
    eth_abi_array(&abi, &arraySize); // array begin
    eth_abi_address(&abi, &path0);
    eth_abi_address(&abi, &path1);
    eth_abi_array_end(&abi); // array end
    eth_abi_call_end(&abi);
    ok(eth_abi_to_hex(&abi, &hex, &hexlen));
    ok(eth_abi_free(&abi));
    cout << "0x" << hex << endl;
}

for more, u can refer the Documentation or the test folder

mhw0 commented 7 months ago

Hello @dkamm I think tuples are encoded & decoded as arrays. If the signature is (uint64,uint64)[] and you want to encode [(1,2),(3,4)], this should be valid:

eth_abi_array(&ab, &size);
  eth_abi_array(&abi, &size);
    // encode 1 and 2
  eth_abi_array_end(&abi);

  eth_abi_array(&abi, &size);
    // encode 3 and 4
  eth_abi_array_end(&abi);
eth_abi_array_end(&abi);

Please, let me know if this works. Thanks.

dkamm commented 7 months ago

@mhw0 @DerXanRam thanks for the quick response! I actually tried that and a got different result than my python script

Python result

000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004

Using nested array

#include <stdio.h>
#include <stdlib.h>
#include <ethc/abi.h>
#include <ethc/hex.h>

int main(void) {
  struct eth_abi abi;

  uint64_t a = 1, b = 2, c = 3, d = 4;
  eth_abi_init(&abi, ETH_ABI_ENCODE);
  eth_abi_array(&abi, NULL);
    eth_abi_array(&abi, NULL);
      eth_abi_uint64(&abi, &a);
      eth_abi_uint64(&abi, &b);
    eth_abi_array_end(&abi);
    eth_abi_array(&abi, NULL);
      eth_abi_uint64(&abi, &c);
      eth_abi_uint64(&abi, &d);
    eth_abi_array_end(&abi);
  eth_abi_array_end(&abi);

  char *hex;
  size_t hexlen;
  eth_abi_to_hex(&abi, &hex, &hexlen);

  printf("%s\n", hex);
  eth_abi_free(&abi);
  free(hex);
  return 0;
}

Result

00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004

Also tried this

#include <stdio.h>
#include <stdlib.h>
#include <ethc/abi.h>
#include <ethc/hex.h>

int main(void) {
  struct eth_abi abi;

  char* fn = "(uint64,uint64)";
  uint64_t a = 1, b = 2, c = 3, d = 4;
  eth_abi_init(&abi, ETH_ABI_ENCODE);
  eth_abi_array(&abi, NULL);
    eth_abi_call(&abi, &fn, NULL);
      eth_abi_uint64(&abi, &a);
      eth_abi_uint64(&abi, &b);
    eth_abi_call_end(&abi);
    eth_abi_call(&abi, &fn, NULL);
      eth_abi_uint64(&abi, &c);
      eth_abi_uint64(&abi, &d);
    eth_abi_call_end(&abi);
  eth_abi_array_end(&abi);

  char *hex;
  size_t hexlen;
  eth_abi_to_hex(&abi, &hex, &hexlen);

  printf("%s\n", hex);
  eth_abi_free(&abi);
  free(hex);
  return 0;
}

Result

000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000040a111f3f000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020a111f3f00000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004
DerXanRam commented 7 months ago

@mhw0 @DerXanRam thanks for the quick response! I actually tried that and a got different result than my python script

Python result

000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004

Using nested array

#include <stdio.h>
#include <stdlib.h>
#include <ethc/abi.h>
#include <ethc/hex.h>

int main(void) {
  struct eth_abi abi;

  uint64_t a = 1, b = 2, c = 3, d = 4;
  eth_abi_init(&abi, ETH_ABI_ENCODE);
  eth_abi_array(&abi, NULL);
    eth_abi_array(&abi, NULL);
      eth_abi_uint64(&abi, &a);
      eth_abi_uint64(&abi, &b);
    eth_abi_array_end(&abi);
    eth_abi_array(&abi, NULL);
      eth_abi_uint64(&abi, &c);
      eth_abi_uint64(&abi, &d);
    eth_abi_array_end(&abi);
  eth_abi_array_end(&abi);

  char *hex;
  size_t hexlen;
  eth_abi_to_hex(&abi, &hex, &hexlen);

  printf("%s\n", hex);
  eth_abi_free(&abi);
  free(hex);
  return 0;
}

Result

00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004

Also tried this

#include <stdio.h>
#include <stdlib.h>
#include <ethc/abi.h>
#include <ethc/hex.h>

int main(void) {
  struct eth_abi abi;

  char* fn = "(uint64,uint64)";
  uint64_t a = 1, b = 2, c = 3, d = 4;
  eth_abi_init(&abi, ETH_ABI_ENCODE);
  eth_abi_array(&abi, NULL);
    eth_abi_call(&abi, &fn, NULL);
      eth_abi_uint64(&abi, &a);
      eth_abi_uint64(&abi, &b);
    eth_abi_call_end(&abi);
    eth_abi_call(&abi, &fn, NULL);
      eth_abi_uint64(&abi, &c);
      eth_abi_uint64(&abi, &d);
    eth_abi_call_end(&abi);
  eth_abi_array_end(&abi);

  char *hex;
  size_t hexlen;
  eth_abi_to_hex(&abi, &hex, &hexlen);

  printf("%s\n", hex);
  eth_abi_free(&abi);
  free(hex);
  return 0;
}

Result

000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000040a111f3f000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020a111f3f00000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004

Do u tried @mhw0 solution ? I think that's the correct solution .

dkamm commented 7 months ago

@DerXanRam Yes, the first code block is his solution, although I didn't set the len field because it's ignored during encoding.

mhw0 commented 7 months ago

Okay, I think the library can't encode tuples. I'll open an issue. Thanks!