Skip to content

Commit

Permalink
Merge branch 'development' into update-minimum-requirements
Browse files Browse the repository at this point in the history
  • Loading branch information
dragos-rebegea authored Apr 16, 2024
2 parents 950c6ac + ccde57f commit b621c85
Show file tree
Hide file tree
Showing 100 changed files with 4,421 additions and 616 deletions.
20 changes: 20 additions & 0 deletions .github/workflows/test-build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: test-build

on:
pull_request:
branches: [main, development]
workflow_dispatch:

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Use Node.js
uses: actions/setup-node@v1
with:
node-version: "16.x"
- name: Install packages
run: npm install
- name: Build website
run: npm run build
2 changes: 1 addition & 1 deletion docs/developers/built-in-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ SetUserNameTransaction {
Receiver: <DNS address that corresponds to the sender>
Value: 0
GasLimit: 1_200_000
Data: "SetUserName@" +
Data: "SetUserName" +
"@" + <username in hexadecimal encoding>
}
```
Expand Down
15 changes: 9 additions & 6 deletions docs/developers/data/abi.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,6 @@ But here it gets interesting: the ABI also needs to describe types that are defi

There is simply not enough room to do it inline with the arguments, so a separate section is necessary, which contains all these descriptions. This section is called `"types"`, and it can describe `struct` and `enum` types.


Have a look at this example with custom types.

Let's take the following `enum` and `struct`:
Expand Down Expand Up @@ -264,7 +263,6 @@ And this is their json representation:
}
```


[comment]: # (mx-context-auto)

### Custom types: struct
Expand All @@ -283,7 +281,6 @@ ABI [structures](/developers/data/custom-types#custom-structures) are defined by

In the example above, we are declaring a structure called `MyAbiStruct`, with 3 fields, called `field1`, `field2`, and `field3`.


[comment]: # (mx-context-auto)

### Custom types: enum
Expand All @@ -308,6 +305,8 @@ You can read more about Rust enums [here](https://doc.rust-lang.org/book/ch06-01

## ESDT Attribute ABI

[comment]: # (mx-context-auto)

### Overview
The framework will export all data types found in arguments, results, and events, but it doesn't intrinsically know abut the data that we use in SFT and NFT attributes. This is why there is a special annotation to specify this explicitly.

Expand All @@ -327,12 +326,16 @@ The exported data will end up in 2 places:

More examples of this below.

[comment]: # (mx-context-auto)

### Details

A new field called `esdtAttributes` was added to the ABI file, where developers can find the structs (name, type) exported using the `esdt_attribute` trait annotation. Additionally, each `esdt_attribute` will create a new json file with the name given by the developer (followed by `.esdt-abi`) and containing its exported structs (names, types and descriptions).

The name/ticker is just a way to identify the idea of the token because we do not have the exact identifier or the possibility to create it through this annotation. We only use this annotation as a mark up for a specific ESDT, in order to define its fields' attributes type. It is useful to define ESDT attributes' type beforehand in order to get more specific and overall better results fetching data from other services.

[comment]: # (mx-context-auto)

### Example using basic types

Let's take a simple contract `SomeContract` as an example and try out the new annotation.
Expand Down Expand Up @@ -391,11 +394,12 @@ We can also check the specific json file exported for the newly defined type whe
}
```

[comment]: # (mx-context-auto)

### Using more complex types

Now, let's see what happens when we use other types than basic ones. Let's add a `Vec`, an `Enum (MyAbiEnum)` and an `Option` to our esdt attributes.


```rust title=lib.rs
#![no_std]

Expand Down Expand Up @@ -502,7 +506,6 @@ some_contract
│ ├── testVec.esdt-abi.json
```


As a final check, let's take a look at what changed in the main abi file, `some_contract.abi.json`, after adding multiple new attributes.

```json title=some_contract.abi.json
Expand Down Expand Up @@ -532,4 +535,4 @@ As a final check, let's take a look at what changed in the main abi file, `some_
}
```

You can find more examples containing multiple data types in the `abi-tester` from [here](https://github.com/multiversx/mx-sdk-rs/tree/master/contracts/feature-tests/abi-tester).
You can find more examples containing multiple data types in the `abi-tester` from [here](https://github.com/multiversx/mx-sdk-rs/tree/master/contracts/feature-tests/abi-tester).
1 change: 0 additions & 1 deletion docs/developers/data/composite-values.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ We often need to group simple values into more complex ones, without splitting t

Here too we opted for an encoding that is, above all, very easy to read.


[comment]: # (mx-context-auto)

### Lists of items
Expand Down
2 changes: 0 additions & 2 deletions docs/developers/data/custom-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ title: Custom Types

We sometimes create new types that we want to serialize and deserialize directly when interacting with contracts. For `struct`s and `enum`s it is very easy to set them up, with barely any code.



[comment]: # (mx-context-auto)

### Custom structures
Expand Down
5 changes: 2 additions & 3 deletions docs/developers/data/defaults.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ Smart contracts occasionally need to interact with uninitialized data. Most nota

Uninitialized storage is indistinguishable from empty storage values, or storage that has been deleted. It always acts like


[comment]: # (mx-context-auto)

## Built-in defaults
Expand Down Expand Up @@ -41,8 +40,6 @@ For instance, for all numeric types, zero is the default value, because we repre
| `DayOfWeek` (see example above) | `DayOfWeek::Monday` |
| `EnumWithEverything` (see example above) | `EnumWithEverything::Default` |



[comment]: # (mx-context-auto)

### Types that have no defaults
Expand Down Expand Up @@ -76,6 +73,8 @@ If you need the default, one workaround is to place these structures inside an `

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.

[comment]: # (mx-context-auto)

## 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.
Expand Down
10 changes: 0 additions & 10 deletions docs/developers/data/multi-values.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ The absence of #[allow_multiple_var_args] as an endpoint attribute, along with t
However, when `#[allow_multiple_var_args]` is used, there is no other parsing validation (except the ones from above) to enforce the var-args rules mentioned before. In simpler terms, using the annotation implies that the developer is assuming responsibility for handling multiple var-args and anticipating the outcomes, effectively placing trust in their ability to manage the situation.
[comment]: # (mx-context-auto)
## Standard multi-values
Expand Down Expand Up @@ -99,7 +98,6 @@ These are the common multi-values provided by the framework:
- Sometimes, for backwards compatibility or other reasons it can happen to have (optional) arguments that are never used and not of interest. To avoid any useless deserialization, it is possible to define an argument of type `IgnoreValue` at the end.
- By doing so, any number of arguments are allowed at the end, all of which will be completely ignored.


So, to recap:

| Managed Version | Unmanaged version | What it represents | Similar single value |
Expand All @@ -112,8 +110,6 @@ So, to recap:
| `ManagedAsyncCallResult<T>` | `AsyncCallResult<T>` | Async call result in callback | `Result<T, String>` |
| `IgnoreValue` | | Any number of ignored arguments | Unit `()` |



[comment]: # (mx-context-auto)

## Storage mapper contents as multi-values
Expand All @@ -138,8 +134,6 @@ These storage mappers are, in no particular order:

## Multi-values in action

[comment]: # (mx-context-auto)

To clarify the way multi-values work in real life, let's provide some examples of how one would go avout calling an endpoint with variadic arguments.

[comment]: # (mx-context-auto)
Expand All @@ -162,7 +156,6 @@ We want to call these endpoints with arguments: `TOKEN-123456` (`0x544f4b454e2d3
- Endpoint 1: `myOptArgEndpoint1@544f4b454e2d313233343536@010000000000000005`
- Endpoint 2: `myOptArgEndpoint2@544f4b454e2d313233343536@05`


:::info Note
In the first case, we are dealing with an [Option](/developers/data/composite-values#options), whose first encoded byte needs to be `0x01`, to signal `Some`. In the second case there is no need for `Option`, `Some` is signalled simply by the fact that the argument was provided.

Expand Down Expand Up @@ -225,7 +218,6 @@ It is a lot more readable, for several reasons:

Once again, the multi-value implementation is more efficient in terms of gas. All the contract needs to do is to make sure that the number of arguments is a multiple of 3, and then top-decode each value. Conversely, in the first example, a lot more memory needs to be moved around when splitting the large argument into pieces.


[comment]: # (mx-context-auto)

## Implementation details
Expand Down Expand Up @@ -254,5 +246,3 @@ where

To create a custom multi-value type, one needs to manually implement these two traits for the type. Unlike for single values, there is no [equivalent derive syntax](/developers/data/custom-types).



2 changes: 0 additions & 2 deletions docs/developers/data/simple-values.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ We will start by going through the basic types used in smart contracts:
- Arbitrary width (big) numbers
- Boolean values


[comment]: # (mx-context-auto)

### Fixed-width numbers
Expand Down Expand Up @@ -182,7 +181,6 @@ We consider best practice to use Unicode on the frontend, but keep all messages
| `&'static str` | `"abc"` | `0x616263` | `0x00000003616263` | Unicode string (slice). |
| `String` | `"abc".to_string()` | `0x616263` | `0x00000003616263` | Unicode string (owned). |


:::info Note
Inside contracts, `ManagedBuffer` is [the only recommended type for generic bytes](developers/best-practices/the-dynamic-allocation-problem).
:::
Expand Down
27 changes: 0 additions & 27 deletions docs/developers/developer-reference/sc-contract-calls.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ The system we present below works just as well on- and off-chain. Think of it as
The more primitive way to perform these calls is to just use the API methods directly, to serialize arguments in code and to specify endpoints as strings. But this does not give the compiler a chance to verify the correctness of the calls, and is very limited in how much we configure the call. It also normally leads to a lot of code duplication. For this reason we recommend always using contract call syntax when formatting transactions.
:::


---

[comment]: # (mx-context-auto)
Expand Down Expand Up @@ -49,8 +48,6 @@ There are three ways of doing these calls:
- writing the proxy manually
- manually serializing the function name and arguments (not recommended)



[comment]: # (mx-context-auto)

### Proxies from contracts
Expand Down Expand Up @@ -121,8 +118,6 @@ Importing a smart contract crate only works if both contracts use the exact fram
In case the target contract is not under our control, it is often wiser to just manually compose the proxy of interest.
:::



[comment]: # (mx-context-auto)

### Manually specified proxies
Expand Down Expand Up @@ -159,8 +154,6 @@ Manually declared proxies are no different from the auto-generated ones, so call
fn callee_contract_proxy(&self, sc_address: ManagedAddress) -> callee_proxy::Proxy<Self::Api>;
```



[comment]: # (mx-context-auto)

### No proxy
Expand Down Expand Up @@ -188,7 +181,6 @@ contract_call.push_raw_argument(arg2_encoded);

<!-- TODO: we need slightly better syntax for the arguments. Was overlooked because we never used them like this -->


[comment]: # (mx-context-auto)

### Diagram
Expand Down Expand Up @@ -223,7 +215,6 @@ fn my_payable_endpoint(&self, arg: BigUint) -> BigUint {

More on payable endpoints and simple transfers [here](/developers/developer-reference/sc-payments). This section refers to transfers during contract calls only.


[comment]: # (mx-context-auto)

### EGLD transfer
Expand All @@ -240,7 +231,6 @@ Note that this method returns a new type of object, `ContractCallWithEgld`, inst
- We can restrict at compile time what methods are available in the builder. For instance, it is possible to add ESDT transfers to `ContractCallNoPayment`, but not to `ContractCallWithEgld`. We thus no longer need to enforce at runtime the restriction that EGLD and ESDT cannot coexist. This restriction is also more immediately obvious to developers.
- The contracts end up being smaller, because the compiler knows which kinds of transfers occur in the contract, and which do not. For instance, if a contract only ever transfers EGLD, there is not need for the code that prepares ESDT transfers in the contract. If the check had been done only at runtime, this optimisation would not have been possible.


[comment]: # (mx-context-auto)

### ESDT transfers
Expand Down Expand Up @@ -281,8 +271,6 @@ self.callee_contract_proxy(callee_sc_address)

where `payments` is a `ManagedVec` of `EsdtTokenPayment`.



[comment]: # (mx-context-auto)

### Mixed transfers
Expand All @@ -300,7 +288,6 @@ self.callee_contract_proxy(callee_sc_address)

The most general such object is `ContractCallWithAnyPayment`, which can take any payment possible on the blockchain: either EGLD, or one or more ESDTs.


```rust
let payments = self.call_value().any_payment();
self.callee_contract_proxy(callee_sc_address)
Expand Down Expand Up @@ -364,7 +351,6 @@ There are several ways in which contract calls are launched from another contrac

Out of these, the asynchronous calls and the promises need some additional configuration, whereas the other can be launched right away.


[comment]: # (mx-context-auto)

### Asynchronous calls
Expand Down Expand Up @@ -440,7 +426,6 @@ Callbacks should be prevented from failing, at all costs. Failed callbacks canno
For this reason we recommend keeping callback code as simple as possible.
:::


Callbacks can also receive payments, both EGLD and ESDT. They are always payable, there is never any need to annotate them with ``#[payable]`. They will receive payments if the called contract sends back tokens to the caller. In this case, they can query the received payments, just like a regular payable endpoint would.

```rust
Expand All @@ -456,7 +441,6 @@ fn callee_endpoint_callback(&self, #[call_result] result: ManagedAsyncCallResult
Even though, in theory, smart contract can only have ONE callback function, the Rust framework handles this for you by saving an ID for the callback function in storage when you fire the async call, and it knows how to retrieve the ID and call the correct function once the call returns.
:::


[comment]: # (mx-context-auto)

### The callback closure
Expand Down Expand Up @@ -515,8 +499,6 @@ self.callbacks().callee_endpoint_callback(caller)

You can then use `original_caller` in the callback like any other function argument.



[comment]: # (mx-context-auto)

### Promises
Expand Down Expand Up @@ -583,8 +565,6 @@ The differences are:
- We need to specify the gas for the call, because the execution of our transaction will continue and it needs to know how much gas it can keep.
- We need to specify the amount of gas for the callback. This is the exact amount of gas reserved for the callback, irrespective of how much the target contract consumes.



[comment]: # (mx-context-auto)

### Transfer-execute
Expand All @@ -602,8 +582,6 @@ self.callee_contract_proxy(callee_sc_address)
.transfer_execute();
```



[comment]: # (mx-context-auto)

### Synchronous calls
Expand Down Expand Up @@ -638,7 +616,6 @@ The method `execute_on_dest_context` is by far the more common when performing s
- `execute_on_dest_context_readonly` - enforces that the target contract does not change state, at blockchain level;
- `execute_on_same_context` - useful for library-like contracts, all changes are saved in the caller instead of the called contract.


[comment]: # (mx-context-auto)

### Diagram
Expand Down Expand Up @@ -778,17 +755,14 @@ self.callee_contract_proxy()

## Contract deploy: execution


[comment]: # (mx-context-auto)

### Deploy


There are several ways to launch a contract deploy, different from a regular contract call.

The simplest deploy operation we can perform is simply calling `deploy_contract`:


```rust
let (new_address, result) = self.callee_contract_proxy()
.init(my_biguint_arg)
Expand All @@ -805,7 +779,6 @@ The methods for executing contract deploys are as follows:
- `.deploy_contract(code, code_metadata)` - deploys a new contract with the code given by the contract.
- `.deploy_from_source(source_address, code_metadata)` - deploys a new contract with the same code as the code of the contract at `source_address`. The advantage is that the contract doesn't need to handle the new contract code, which could be quite a large data blob. This saves gas. It requires that we have the code already deployed somewhere else.


[comment]: # (mx-context-auto)

### Upgrade
Expand Down
Loading

0 comments on commit b621c85

Please sign in to comment.