Javascript Node SDK - Update Contract with Params

Hi all, I’m trying to use the node sdk to update a simple contract on the testnet.

here’s the parameter struct and function from my contract:

#[derive(Serialize, SchemaType)]
struct SendMessageParameter {
    message: String,
}

#[receive(
    contract = "factory",
    name = "send_message",
    parameter = "SendMessageParameter",
    mutable
)]
fn send_message<S: HasStateApi>(
    ctx: &impl HasReceiveContext,
    _host: &mut impl HasHost<State<S>, StateApiType = S>,
) -> ReceiveResult<String> {
    let parameter: SendMessageParameter = ctx.parameter_cursor().get()?;
    Ok(parameter.message)
}

js client (values filled in for clarity):

const params = serializeUpdateContractParameters(
    "factory", 
    "factory.send_message",
    { message: 'hello world' }, 
    Buffer.from(readFileSync('../contracts/factory/dist/factory/schema.bin'))
)

const tx = {
    header: {
        expiry: new TransactionExpiry(new Date(Date.now() + 3600000)),
        nonce: 164n,
        sender: new AccountAddress("3KkSDCzdpXqw7ShVhEGbMbVtp4QScVdazTR8ux5KUNX4ErCXbe"),
    },
    payload: {
        amount: new CcdAmount(0n),
        address: { index: BigInt(3222), subindex: BigInt(0) },
        receiveName: "factory.send_message",
        message: params,
        maxContractExecutionEnergy: 300000n
    },
    type: AccountTransactionType.Update
}

/// sign and send tx....

result:

{
  "outcomes": {
    "d729b1644742d6e14083a3dced9a275e6f9af760a77acce89a50153f7d89c682": {
      "cost": "1878856",
      "energyCost": "1009",
      "hash": "c0131741396e17060dea3f7c7bb88e208cc37d72a76c48c7f7a9a8a225b26072",
      "index": "0",
      "result": {
        "outcome": "reject",
        "rejectReason": {
          "contractAddress": {
            "index": "3222",
            "subindex": 0
          },
          "parameter": "",
          "receiveName": "factory.send_message",
          "rejectReason": -2147483646,
          "tag": "RejectedReceive"
        }
      },
      "sender": "3KkSDCzdpXqw7ShVhEGbMbVtp4QScVdazTR8ux5KUNX4ErCXbe",
      "type": {
        "contents": "update",
        "type": "accountTransaction"
      }
    }
  },
  "status": "finalized"
}

Also, I tried the same logic to update a parameterless contract function and was successful.

any help here would be greatly appreciated. thanks!

In here the receiveName should just be send_message. Does that fix your issue?

It seems that an error is not properly reported, and you get an empty parameter as a result. That’s not great and I’ll file an issue to get that fixed.

Actually we have this issue almost exactly reported already Calling `serializeUpdateContractParameters` with wrong receive name returns empty buffer · Issue #116 · Concordium/concordium-node-sdk-js · GitHub

unfortunately no, changing the receive name to “send_message” did not resolve the issue but I think we are a bit closer. I’m fairly certain that you are correct that something is wrong with the serialized parameters:

buffer was empty:

const params = serializeUpdateContractParameters(
    "factory", 
    "factory.send_message",
    { message: 32 }, 
    Buffer.from(readFileSync('../contracts/factory/dist/factory/schema.bin')) 
)
    
console.log(params)

>>> <Buffer >

buffer is not empty

const params = serializeUpdateContractParameters(
    "factory", 
    "send_message",
    { message: 32 }, 
    Buffer.from(readFileSync('../contracts/factory/dist/factory/schema.bin')) 
)
    
console.log(params)

>>> <Buffer 20 00 00 00>

here’s the new error:

{
  "outcomes": {
    "7dc0cedfeb0db7c05467480f9fb348c21ec236b64a962c62d3af455332d24683": {
      "cost": "366368",
      "energyCost": "201",
      "hash": "98ee001a6ff0182d5bd06d59b70219fa7a1bc6816c8a04aa0a207f298f2927c0",
      "index": "0",
      "result": {
        "outcome": "reject",
        "rejectReason": {
          "tag": "SerializationFailure"
        }
      },
      "sender": "3KkSDCzdpXqw7ShVhEGbMbVtp4QScVdazTR8ux5KUNX4ErCXbe",
      "type": {
        "contents": null,
        "type": "accountTransaction"
      }
    }
  },
  "status": "finalized"
}

any ideas?

nevermind, we got it! I had assumed that the updateTxParameter “receiveName” was identical to the payload “receiveName.” appreciate the help!

...

const contractName = "factory"
const functionName = "send_message"
const receiveName = `${contractName}.${functionName}`,
const userInput = { message: 123 }
const schemaBytes = Buffer.from(readFileSync('../contracts/factory/dist/factory/schema.bin'))

const message = serializeUpdateContractParameters(
    contractName, 
    functionName,
    userInput,
)

...

const payload = {
    amount,
    address,
    receiveName,
    message,
    maxContractExecutionEnergy
}
2 Likes

Yeah, this inconsistency is not great. It would be better if we expected the same in both in the SDK.

Glad you got it working.