Concordium / concordium-dapp-libraries

A coherent set of building blocks for making it as easy as possible for developers to build web-based dApps.
Apache License 2.0
7 stars 5 forks source link

Add `SignMessageObject` to `signMessage` function #32

Closed DOBEN closed 1 year ago

DOBEN commented 1 year ago

Purpose

The browser wallet can now sign bytes as well. Expanding the library to enable passing an object (with schema) to be signed.

Checklist

bisgardo commented 1 year ago

I can't get the call with a primitive string type to work with the mobile wallet: The parameter serialization fails as boiled down to the test

const { Buffer } = require('buffer/');
const { serializeUpdateContractParameters } = require('@concordium/common-sdk');

test('serialize plain string parameter', () => {
    const contractName = 'test';
    const receiveName = 'string';
    const parameters = 'xyz';
    const schema = 'FgI';
    const schemaVersion = 2;
    const res = serializeUpdateContractParameters(
        contractName,
        receiveName,
        parameters,
        Buffer.from(schema, 'base64'),
        schemaVersion
    );
    console.log({res});
});

which fails with the error

unable to deserialize parameters, due to: Parse error

@concordium/common-sdk is at version 6.4.1 which is the current version.

To run the test, add the test file to the project root, install jest (yarn add --dev jest) and run jest.

The test is based on the following example contract written by @DOBEN (deployed on testnet with index 4239):

use concordium_std::*;
#[derive(Serialize)]
struct State;
/// Init function that creates a new contract.
#[init(contract = "test")]
fn init<S: HasStateApi>(
    _ctx: &impl HasInitContext,
    _state_builder: &mut StateBuilder<S>,
) -> InitResult<()> {
    Ok(())
}
pub type Number = u64;
#[receive(
    contract = "test",
    name = "number",
    parameter = "Number",
)]
fn number<S: HasStateApi>(
    ctx: &impl HasReceiveContext,
    _host: &impl HasHost<State, StateApiType = S>,
) -> ReceiveResult<()> {
    let _ = ctx.parameter_cursor().get()?;
    Ok(())
}
pub type Bool = bool;
#[receive(
    contract = "test",
    name = "bool",
    parameter = "Bool",
)]
fn bool<S: HasStateApi>(
    ctx: &impl HasReceiveContext,
    _host: &impl HasHost<State, StateApiType = S>,
) -> ReceiveResult<()> {
    let _ = ctx.parameter_cursor().get()?;
    Ok(())
}
pub type St = String;
#[receive(
    contract = "test",
    name = "string",
    parameter = "St",
)]
fn string<S: HasStateApi>(
    ctx: &impl HasReceiveContext,
    _host: &impl HasHost<State, StateApiType = S>,
) -> ReceiveResult<()> {
    let _ = ctx.parameter_cursor().get()?;
    Ok(())
}

which produces the schema

{
  "contractName": "test",
  "entrypoints": {
    "bool": {
      "parameter": "AQ"
    },
    "number": {
      "parameter": "BQ"
    },
    "string": {
      "parameter": "FgI"
    }
  }
}

@shjortConcordium @abizjak is there something wrong with the way I call serializeUpdateContractParameters? What should be done to make the test pass?

shjortConcordium commented 1 year ago

If you want to use serializeUpdateContractParameters you need to supply the schema for the entire module. (Not the schema for the parameter itself, like "FgI" is) Otherwise you can use serializeTypeValue(parameters, Buffer.from(schema, 'base64')) .

bisgardo commented 1 year ago

If you want to use serializeUpdateContractParameters you need to supply the schema for the entire module. (Not the schema for the parameter itself, like "FgI" is) Otherwise you can use serializeTypeValue(parameters, Buffer.from(schema, 'base64')) .

How does the implementation tell which kind of schema is supplied? What does the browser wallet do? Try both and see which one works?

shjortConcordium commented 1 year ago

If you want to use serializeUpdateContractParameters you need to supply the schema for the entire module. (Not the schema for the parameter itself, like "FgI" is) Otherwise you can use serializeTypeValue(parameters, Buffer.from(schema, 'base64')) .

How does the implementation tell which kind of schema is supplied? What does the browser wallet do? Try both and see which one works?

For sendTransaction, it now takes a SchemaWithContext, which specifies which type. (If given only a string as the schema it assumes the old format, for backwards compatibility) In the SignMessageObject, it should always be the type specific schema.

bisgardo commented 1 year ago

@DOBEN I'm suggesting a different approach in https://github.com/Concordium/concordium-dapp-libraries/pull/35 which is consistent with #34, which was just merged.

DOBEN commented 1 year ago

Closing this MR:

Changes that were implemented in https://github.com/Concordium/concordium-dapp-libraries/pull/34 https://github.com/Concordium/concordium-dapp-libraries/pull/35 were tested in and satisfy the requirements so that this MR is obsolete.