hackbg / hackbg/fadroma

Avoid the use of `serde_json::Value` in `DeserializeFlat`

Open
#38 5 comments 0 reactions 0 assignees View on GitHub
easy hacktoberfest rust
Dominant language
TypeScript
Stars
53
Forks
15
PR merge metrics
No merged PRs in 30d

Description

The purpose of the [DeserializeFlat](https://github.com/hackbg/fadroma/blob/21.09/lib/derive-contract/src/deserialize_flat.rs) derive macro is to avoid the nested JSON representation of enum tuple variants. This is really important when we want integrate with external services/apps like the [Keplr](https://www.keplr.app/) wallet that expect an exact message format. We can't simply not utilize tuple variants as this is how reusable contract components are implemented in the `derive-contract` macro.

A practical example is trying to create a SecretNetwork viewing key via Keplr. Keplr expects the contract to accept the following message: `{ set_viewing_key: { key: "my_key", padding: null } }`, which would require the handle message enum in our contract to have a variant that looks like this:

```rust
#[derive(Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum HandleMsg {
SetViewingKey {
key: String,
padding: Option,
}
}
```
We can avoid implementing this logic in our contract by using Fadroma's auth module and including it in the contract definition. However, the resulting message generated by the `derive-contract` macro will look something like this:

```rust
#[derive(Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum HandleMsg {
Auth(AuthHandleMsg)
}
```
making the JSON that the contract actually accepts to be this: `{ auth: { set_viewing_key: { key: "my_key", padding: null } } }`.

`DeserializeFlat` provides a custom implementation of the `serde::de::Deserialize` trait that tries to deserialize the incoming JSON as the standard `derive(Deserialize)` would first and if that fails, it tries to deserialize each of the tuple enum variants directly (in the above example that would the `AuthHandleMsg` type).

The current implementation of this macro makes use of `serde_json`'s [Value](https://docs.serde.rs/serde_json/enum.Value.html) type which defeats the entire purpose of the `serde_json_wasm` crate to not use dynamic memory allocation so this is not really usable in its current state. It also doesn't actually work, since calls to `deserialize_any` are forbidden in `serde_json_wasm` and this method is called by the `serde_json::Value` type.

How can the current logic be implemented without using `serde_json` or ideally, not having knowledge of what `Deserializer` implementation is actually being used. Alternative ideas are very welcome as well!

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.