stellar / js-soroban-client

Main Soroban client library for the Javascript language
https://stellar.github.io/js-soroban-client/
Apache License 2.0
22 stars 17 forks source link

[Question] JS - Enum/struct as parameter to function #106

Closed yuriescl closed 1 year ago

yuriescl commented 1 year ago

In the Browser (not Node.js) I'm trying to invoke a contract function but one of parameters is a Enum in Rust. How do I build and pass an instance of MyEnum to the function?

I'm using this to import the JS SDK:

<script src="https://cdnjs.cloudflare.com/ajax/libs/soroban-client/0.8.0/soroban-client.js"></script>

This is the the code I'm trying to fix:

let transaction = new SorobanClient.TransactionBuilder(account, {
  fee: config.fee,
  networkPassphrase: config.networkPassphrase,
})
  .addOperation(
    contract.call(
      "myfunc",
      SorobanClient.xdr.ScVal.scvU32(param1),
      SorobanClient.xdr.ScVal.scvSymbol(param2),
      // <- how to pass an MyEnum instance here?
    )
  )
  .setTimeout(30)
  .build();

In the above code, the function myfunc receives two parameters, the first one is of type u32, and second one is of type Symbol. But in my contract, there's a third parameter of type MyEnum, which is an Enum:

#[derive(Clone, PartialEq, Debug)]
#[contracttype]
pub enum MyEnum {
    Identifier(Symbol),
    Count(u32),
}

...

fn myfunc(env: Env, param1: u32, param2: Symbol, param3: MyEnum) -> Option<u32>;

Also, if param3 was struct instead of Enum, how would I build and pass the struct to the function?

yuriescl commented 1 year ago

By looking at the Python Soroban SDK Enum implementation, it seems that enums can be converted into vectors:

def to_xdr_sc_val(self) -> stellar_xdr.SCVal:
    vec: List[stellar_xdr.SCVal] = [
        stellar_xdr.SCVal(
            stellar_xdr.SCValType.SCV_SYMBOL,
            sym=stellar_xdr.SCSymbol(self.key.encode()),
        ),
    ]
    if self.value is not None:
        vec.append(self.value)
    return stellar_xdr.SCVal.from_scv_vec(stellar_xdr.SCVec(vec))

So I was able to get it working by using a vector to represent the enum:

SorobanClient.xdr.ScVal.scvVec([
  SorobanClient.xdr.ScVal.scvSymbol(
    ethereumjs.Buffer.Buffer.from("Identifier", "utf-8")
  ),
  SorobanClient.xdr.ScVal.scvSymbol("IDENT1"),
])

Updated code:

SorobanClient.TransactionBuilder(account, {
  fee: config.fee,
  networkPassphrase: config.networkPassphrase,
})
  .addOperation(
    contract.call(
      "myfunc",
      SorobanClient.xdr.ScVal.scvU32(param1),
      SorobanClient.xdr.ScVal.scvSymbol(param2),
      SorobanClient.xdr.ScVal.scvVec([
        SorobanClient.xdr.ScVal.scvSymbol(
          ethereumjs.Buffer.Buffer.from("Identifier", "utf-8")
        ),
        SorobanClient.xdr.ScVal.scvSymbol("IDENT1"),
      ])
    )
  )
  .setTimeout(30)
  .build();

It would be nice to have built-in support for enums in JS SDK, similar to the Python SDK.