Skip to content

Commit

Permalink
Merge pull request #663 from multiversx/development
Browse files Browse the repository at this point in the history
Update wallet section with Web-Wallet Guardians and xPortal Invisible Guardian
  • Loading branch information
schimih committed Jul 14, 2023
2 parents 8838502 + 0326976 commit 149af26
Show file tree
Hide file tree
Showing 62 changed files with 5,080 additions and 3,340 deletions.
138 changes: 138 additions & 0 deletions docs/developers/developer-reference/serialization-format.md
Original file line number Diff line number Diff line change
Expand Up @@ -573,3 +573,141 @@ export const ExampleTable = () => (
</tr>
</table>
);

## Defaults

### Built-in defaults

The serialization format naturally supports defaults for most types.

The default value of a type is the value that we receive when deserializing an empty buffer. The same value will serialize to an empty buffer. We like having easy access to empty serialized buffers, because that way we can easily clear storage and we minimize gas costs in transactions.

For instance, for all numeric types, zero is the default value, because we represent it as an empty buffer.

| Type | Default value |
| ----------------------------------------- | ------------------------------ |
| `u8` | `0` |
| `u16` | `0` |
| `u32` | `0` |
| `u64` | `0` |
| `usize` | `0` |
| `BigUnt` | `0` |
| `i8` | `0` |
| `i16` | `0` |
| `i32` | `0` |
| `i64` | `0` |
| `isize` | `0` |
| `BigInt` | `0` |
| `bool` | `false` |
| `Option<T>` | `None` |
| `ManagedBuffer` | `ManagedBuffer::empty()` |
| `Vec<T>` | `Vec::new()` |
| `String` | `"".to_string()` |
| `DayOfWeek` (see example above) | `DayOfWeek::Monday` |
| `EnumWithEverything` (see example above) | `EnumWithEverything::Default` |

### Types that have no defaults

Certain types have no values that can be represented as an empty buffer, and therefore they have no default value.

When trying to decode any of these types from an empty buffer, we will receive a deserialization error.

Examples:
- `(usize, usize)` always gets serialized as exactly 8 bytes, no less;
- `(usize, usize, usize)` always gets serialized as exactly 12 bytes;
- `[u8; 20]` always gets serialized as exactly 20 bytes.

The same goes for any custom `struct`, its representation is the concatenation of the nested encoding of its components, which is fixed size.

In some cases a custom `enum` faces the same problem. If the first variant has no additional data, the default is simply the first variant. We saw two examples above:
- `DayOfWeek` is a simple enum top to bottom, so `DayOfWeek::Monday` is naturally its default;
- `EnumWithEverything` has data in some of the variants, but not in the first, so in a similar manner, `EnumWithEverything::Default` works as its default.

However, if we were to define the enum:
```rust
#[derive(TopEncode, TopDecode)]
enum Either {
Something(u32),
SomethingElse(u64),
}
```
... there is no way to find a natural default value for it. Both variants are represented as non-empty buffers.

If you need the default, one workaround is to place these structures inside an `Option`. Options always have the default `None`, no matter the contents.

There is, however, another way to do it: for custom structures it is possible to define custom defaults, as we will see in the next section.

### Custom defaults

A structure that does not have a natural default value can receive one via custom code. First of all this applies to structures, but it can also be useful for some enums.

To do so, instead of deriving `TopEncode` and `TopDecode`, we will derive `TopEncodeOrDefault` and `TopDecodeOrDefault`, respectively.

We need to also specify what we want that default value to be, both when encoding and decoding. For this, we need to explicitly implement traits `EncodeDefault` and `DecodeDefault` for our structure.

Let's look at an example:

```rust
#[derive(TopEncodeOrDefault, TopDecodeOrDefault)]
pub struct StructWithDefault {
pub first_field: u16,
pub seq: Vec<u8>,
pub another_byte: u8,
pub uint_32: u32,
pub uint_64: u64,
}

impl EncodeDefault for StructWithDefault {
fn is_default(&self) -> bool {
self.first_field == 5
}
}

impl DecodeDefault for StructWithDefault {
fn default() -> Self {
StructWithDefault {
first_field: 5,
seq: vec![],
another_byte: 0,
uint_32: 0,
uint_64: 0,
}
}
}
```

We just specified the following:
- `is_default`:whenever the `first_field` field is equal to 5, the other fields don't matter anymore and we save the structure as an empty buffer;
- `default`: whenever we try to decode an empty buffer, we yield a structure that has the `first_field` set to 5, and all the other fields empty or zero.

It should always be the case that `<T as EncodeDefault>::is_default(<T as EncodeDefault>::default())` is true. The framework does not enforce this in any way, but it should be common sense.

Other than that, there are no constraints on what the default value should be.

We can do the same for an enum:

```rust
#[derive(TopEncodeOrDefault, TopDecodeOrDefault)]
enum Either {
Something(u32),
SomethingElse(u64),
}

impl EncodeDefault for Either {
fn is_default(&self) -> bool {
matches!(*self, Either::Something(3))
}
}

impl DecodeDefault for Either {
fn default() -> Self {
Either::Something(3)
}
}
```

We just specified the following:
- `is_default`: whenever we have variant `Either::Something` _and_ the value contained is 3, encode as empty buffer;
- `default`: whenever we try to decode an empty buffer, we yield `Either::Something(3)`.

The same here, `<T as EncodeDefault>::is_default(<T as EncodeDefault>::default())` should be true. No other constraints over what the default value should be, of which variant. `Either::SomethingElse(0)` could also have been chosen to be the default.
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ You always need to add new fields at the end of the struct, otherwise, this appr
To fix this, we need to manually implement the decoding traits, which were previously automatically added through the derives.

```rust
use multiversx_sc::codec::{NestedDecodeInput, TopDecodeInput};

#[derive(TypeAbi, TopEncode, NestedEncode)]
pub struct UserData<M: ManagedTypeApi> {
pub stake_amount: BigUint<M>,
Expand All @@ -82,7 +84,7 @@ pub struct UserData<M: ManagedTypeApi> {
impl<M: ManagedTypeApi> TopDecode for UserData<M> {
fn top_decode<I>(input: I) -> Result<Self, DecodeError>
where
I: elrond_codec::TopDecodeInput,
I: TopDecodeInput,
{
let mut buffer = input.into_nested_buffer();
Self::dep_decode(&mut buffer)
Expand Down Expand Up @@ -126,6 +128,8 @@ Unless you want to remove the very last field of the struct, and change nothing
Assuming you simply want to remove `last_update_block` for the example above, the implementation would be as follows:

```rust
use multiversx_sc::codec::{NestedDecodeInput, TopDecodeInput};

#[derive(TypeAbi, TopEncode, NestedEncode)]
pub struct UserData<M: ManagedTypeApi> {
pub stake_amount: BigUint<M>,
Expand All @@ -134,7 +138,7 @@ pub struct UserData<M: ManagedTypeApi> {
impl<M: ManagedTypeApi> TopDecode for UserData<M> {
fn top_decode<I>(input: I) -> Result<Self, DecodeError>
where
I: elrond_codec::TopDecodeInput,
I: TopDecodeInput,
{
let mut buffer = input.into_nested_buffer();
Self::dep_decode(&mut buffer)
Expand Down
2 changes: 1 addition & 1 deletion docs/developers/sc-calls-format.md
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ numeric --> hex
```
7 --> 07
10 --> 0a
35 --> 25
35 --> 23
```

[comment]: # (mx-context-auto)
Expand Down
1 change: 0 additions & 1 deletion docs/tokens/esdt-tokens.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,6 @@ Where the constants represent:
- `MIN_GAS_LIMIT` - the minimum gas limit of a transaction. Each transaction will have at least this cost. Can be fetched from [here](/sdk-and-tools/rest-api/network/#get-network-configuration).
- `GAS_PER_DATA_BYTE` - the amount of gas to be used for each character of the data field. Can be fetched from [here](/sdk-and-tools/rest-api/network/#get-network-configuration).
- `ESDT_TRANSFER_FUNCTION_COST` - the cost of the `ESDTTransfer` function. Can be fetched from [here](https://gateway.multiversx.com/network/gas-configs).
- `ESDT_TRANSFER_FUNCTION_COST` - the cost of the `ESDTTransfer` function. Can be fetched from [here](https://gateway.multiversx.com/network/gas-configs).

The current values of these constants are:

Expand Down
10 changes: 5 additions & 5 deletions docs/tokens/nft-tokens.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ The existing roles are:
For NFT:

- ESDTRoleNFTCreate : this role allows one to create a new NFT
- ESDTRoleNFTBurn : this role allows one to burn quantity of a specific NFT
- ESDTRoleNFTBurn : this role allows one to burn a specific NFT
- ESDTRoleNFTUpdateAttributes : this role allows one to change the attributes of a specific NFT
- ESDTRoleNFTAddURI : this role allows one add URIs for a specific NFT
- ESDTTransferRole : this role enables transfer only to specified addresses. The addresses with the transfer role can transfer anywhere.
Expand Down Expand Up @@ -556,7 +556,7 @@ ESDTNFTUpdateAttributesTransaction {
GasLimit: 10000000
Data: "ESDTNFTUpdateAttributes" +
"@" + <token identifier in hexadecimal encoding> +
"@" + <NFT nonce in hexadecimal encoding> +
"@" + <NFT or SFT nonce in hexadecimal encoding> +
"@" + <Attributes in hexadecimal encoding>
}
```
Expand All @@ -580,7 +580,7 @@ ESDTNFTAddURITransaction {
GasLimit: 10000000
Data: "ESDTNFTAddURI" +
"@" + <token identifier in hexadecimal encoding> +
"@" + <NFT nonce in hexadecimal encoding> +
"@" + <NFT or SFT nonce in hexadecimal encoding> +
"@" + <URI in hexadecimal encoding> +
"@" + <URI in hexadecimal encoding> +
...
Expand All @@ -605,7 +605,7 @@ AddQuantityTransaction {
GasLimit: 10000000
Data: "ESDTNFTAddQuantity" +
"@" + <token identifier in hexadecimal encoding> +
"@" + <NFT nonce in hexadecimal encoding>
"@" + <SFT nonce in hexadecimal encoding>
"@" + <quantity to add in hexadecimal encoding>
}
```
Expand All @@ -628,7 +628,7 @@ BurnQuantityTransaction {
GasLimit: 10000000
Data: "ESDTNFTBurn" +
"@" + <token identifier in hexadecimal encoding> +
"@" + <NFT nonce in hexadecimal encoding>
"@" + <SFT nonce in hexadecimal encoding>
"@" + <quantity to burn in hexadecimal encoding>
}
```
Expand Down
11 changes: 11 additions & 0 deletions docs/utils.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -275,3 +275,14 @@ $$

<iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/bXbBfJCRVqE?playlist=bXbBfJCRVqE&loop=1" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
$$
## Mermaid diagrams
```mermaid
graph TD;
A-->B;
A-->C;
B-->D;
C-->D;
```
2 changes: 1 addition & 1 deletion docs/validators/delegation-manager.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ To customize the information for your delegation contract, which will be availab

Please fill in the **avatar picture** and edit the profile providing the **name**, **bio**, **website** and **twitter** (if applicable). This information together with the **service fee, percentage filled** and **APR** will be displayed for every delegation contract on the delegation pages in the web wallet and xPortal. If this information cannot be found a generic logo and the delegation contract's address is displayed.

In order to complete the matching between the delegation contract and GitHub identity of the staking pool, a repository needs to be created with the name "multiversx" which contains one single file: "keys.json". This file contains a json array with the provider's address and the node BLSes, just like it was on GitHub. For devnet/testnet, you need to have a folder called devnet/testnet in the same repository, with the "keys.json" file underneath.
In order to complete the matching between the delegation contract and GitHub identity of the staking pool, a repository needs to be created with the name "multiversx" which contains one single file: "keys.json". This file contains a json array with the provider's smart contract address, just like it was on Keybase. For devnet/testnet, you need to have a folder called devnet/testnet in the same repository, with the "keys.json" file underneath.

An example for the contents of the `keys.json` file for the `"testmxprovider"` GitHub identity would be:

Expand Down
Loading

0 comments on commit 149af26

Please sign in to comment.