From 63cd4e1e3e337925a7af12ed66fa93c6c3e03f63 Mon Sep 17 00:00:00 2001 From: mihaicalinluca Date: Mon, 6 Nov 2023 15:53:57 +0100 Subject: [PATCH 01/10] added esdt_attribute description and short tutorial in abi page --- docs/developers/data/abi.md | 573 ++++++++++++++++++++++++++++++++++++ 1 file changed, 573 insertions(+) diff --git a/docs/developers/data/abi.md b/docs/developers/data/abi.md index 9e98c2748..9d2146835 100644 --- a/docs/developers/data/abi.md +++ b/docs/developers/data/abi.md @@ -279,3 +279,576 @@ Similarly, [enums](/developers/data/custom-types#custom-enums) are defined by: - Struct-like variants, with named fields. You can read more about Rust enums [here](https://doc.rust-lang.org/book/ch06-01-defining-an-enum.html). + +--- + +[comment]: # (mx-context-auto) + +## Custom ABI exports + +### Overview + +Even though the `#[derive(TypeAbi)]` annotation exports all the data types used in the contract along with the type descriptions, we have implemented a manual way to export any kind of data type (used inside the contract or not) in the ABI file in order to fetch it easier from other services (e.g. use-case: the developer can define the type of the attributes expected for a specific ESDT, fetch it from abi and use it easily in the frontend for a more specific result). + +Starting with the framework version `0.44`, developers can use the new trait annotation `#[esdt_attribute("name", Type)]` in order to export any data types in the ABI file. + +:::important Important +Please note that it is a `trait annotation`, meaning that it can only be used at trait level along with other `#[multiversx_sc]` annotation. Using it at endpoint level or at trait level outside `multiversx_sc` environment will not work. +::: + +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). + +### Basic types + +Let's take the `Adder` contract as an example and try out the new annotation. + +__adder.rs:__ +```rust +#[multiversx_sc::contract] +#[esdt_attribute("testBasic", BigUint)] +pub trait Adder { + #[view(getSum)] + #[storage_mapper("sum")] + fn sum(&self) -> SingleValueMapper; + + #[init] + fn init(&self, initial_value: BigUint) { + self.sum().set(initial_value); + } + + /// Add desired amount to the storage variable. + #[endpoint] + fn add(&self, value: BigUint) { + self.sum().update(|sum| *sum += value); + } +} +``` + +Adding the `#[esdt_attribute("testBasic", BigUint)]` at trait level along with `#[multiversx_sc::contract]` should export a new structure named `testBasic` with a `BigUint` field type. The abi can be generated calling `sc-meta all abi` in the contract folder, or by building the contract using `sc-meta all build` (this command also adds the wasm file to the `output` folder). + +Building the contract using `sc-meta all build` will generate the following folder structure: +``` +adder +├── output +│ ├── adder.abi.json +│ ├── adder.imports.json +| ├── adder.mxsc.json +| ├── adder.wasm +│ ├── testBasic.esdt-abi.json +``` + +Let's check out the `adder.abi.json` file first. Here we discover the new `esdtAttributes` field, containing the value mentioned in the annotation. + +```json +{ + "buildInfo": { + "rustc": { + "version": "1.71.0-nightly", + "commitHash": "a2b1646c597329d0a25efa3889b66650f65de1de", + "commitDate": "2023-05-25", + "channel": "Nightly", + "short": "rustc 1.71.0-nightly (a2b1646c5 2023-05-25)" + }, + "contractCrate": { + "name": "adder", + "version": "0.0.0", + "gitVersion": "v0.44.0" + }, + "framework": { + "name": "multiversx-sc", + "version": "0.44.0" + } + }, + "docs": [ + "One of the simplest smart contracts possible,", + "it holds a single variable in storage, which anyone can increment." + ], + "name": "Adder", + "constructor": { + "inputs": [ + { + "name": "initial_value", + "type": "BigUint" + } + ], + "outputs": [] + }, + "endpoints": [ + { + "name": "getSum", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "docs": [ + "Add desired amount to the storage variable." + ], + "name": "add", + "mutability": "mutable", + "inputs": [ + { + "name": "value", + "type": "BigUint" + } + ], + "outputs": [] + } + ], + "events": [], + "esdtAttributes": [ + { + "ticker": "testBasic", + "type": "BigUint" + } + ], + "hasCallback": false, + "types": {} +} +``` +We can also check the specific json file exported for the newly defined type where we can find information about the type separated from the main abi file. + +__testBasic.esdt-abi.json__ +```json +{ + "esdtAttribute": { + "ticker": "testBasic", + "type": "BigUint" + } +} +``` + +## Composite types + +Now, let's see what happens when we use other types than basic ones. Let's add a `Vec`, an `Enum` and an `Option` to our esdt attributes. + +__adder.rs:__ +```rust +#![no_std] + +use multiversx_sc::derive::TypeAbi; + +multiversx_sc::imports!(); + +/// One of the simplest smart contracts possible, +/// it holds a single variable in storage, which anyone can increment. +#[multiversx_sc::contract] +#[esdt_attribute("testBasic", BigUint)] +#[esdt_attribute("testVec", ManagedVec)] +#[esdt_attribute("testEnum", MyEnum)] +#[esdt_attribute("testOption", Option)] +pub trait Adder: module::ModuleExample { + #[view(getSum)] + #[storage_mapper("sum")] + fn sum(&self) -> SingleValueMapper; + + #[init] + fn init(&self, initial_value: BigUint) { + self.sum().set(initial_value); + } + + /// Add desired amount to the storage variable. + #[endpoint] + fn add(&self, value: BigUint) { + self.sum().update(|sum| *sum += value); + } +} + +#[derive(TypeAbi)] +pub enum MyEnum { + First, + Second, + Third, +} + +``` + +If we call `sc-meta all abi` (or `sc-meta all build` if we also wish to build the contract), the new attributes will be added to our __adder.abi.json__ file and new separate json files will be created for each attribute. + +__adder.abi.json:__ +```json +{ + "buildInfo": { + "rustc": { + "version": "1.71.0-nightly", + "commitHash": "a2b1646c597329d0a25efa3889b66650f65de1de", + "commitDate": "2023-05-25", + "channel": "Nightly", + "short": "rustc 1.71.0-nightly (a2b1646c5 2023-05-25)" + }, + "contractCrate": { + "name": "adder", + "version": "0.0.0", + "gitVersion": "v0.44.0" + }, + "framework": { + "name": "multiversx-sc", + "version": "0.44.0" + } + }, + "docs": [ + "One of the simplest smart contracts possible,", + "it holds a single variable in storage, which anyone can increment." + ], + "name": "Adder", + "constructor": { + "inputs": [ + { + "name": "initial_value", + "type": "BigUint" + } + ], + "outputs": [] + }, + "endpoints": [ + { + "name": "getSum", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "docs": [ + "Add desired amount to the storage variable." + ], + "name": "add", + "mutability": "mutable", + "inputs": [ + { + "name": "value", + "type": "BigUint" + } + ], + "outputs": [] + } + ], + "events": [], + "esdtAttributes": [ + { + "ticker": "testBasic", + "type": "BigUint" + }, + { + "ticker": "testVec", + "type": "List" + }, + { + "ticker": "testEnum", + "type": "MyEnum" + }, + { + "ticker": "testOption", + "type": "Option" + } + ], + "hasCallback": false, + "types": { + "MyEnum": { + "type": "enum", + "variants": [ + { + "name": "First", + "discriminant": 0 + }, + { + "name": "Second", + "discriminant": 1 + }, + { + "name": "Third", + "discriminant": 2 + } + ] + }, + } +} + +``` + +Now, if we take a look into the folder structure of the contract, we should see the following updated folder structure containing the newly generated files in `output`: + +``` +adder +├── output +│ ├── adder.abi.json +│ ├── adder.imports.json +| ├── adder.mxsc.json +| ├── adder.wasm +│ ├── testBasic.esdt-abi.json +│ ├── testEnum.esdt-abi.json +│ ├── testOption.esdt-abi.json +│ ├── testVec.esdt-abi.json +``` + +Each file contains the new struct with its name and the type field's description. + +__testEnum.esdt-abi.json:__ +```json +{ + "esdtAttribute": { + "ticker": "testEnum", + "type": "MyEnum" + }, + "types": { + "MyEnum": { + "type": "enum", + "variants": [ + { + "name": "First", + "discriminant": 0 + }, + { + "name": "Second", + "discriminant": 1 + }, + { + "name": "Third", + "discriminant": 2 + } + ] + } + } +} +``` + +__testOption.esdt-abi.json:__ +```json +{ + "esdtAttribute": { + "ticker": "testOption", + "type": "Option" + } +} +``` + +__testVec.esdt-abi.json:__ +```json +{ + "esdtAttribute": { + "ticker": "testVec", + "type": "List" + } +} +``` + +## Custom types + +Let's also add a custom `Struct` into the mix. Here is the updated code for __adder.rs:__ + +```rust +#![no_std] + +use multiversx_sc::derive::TypeAbi; + +multiversx_sc::imports!(); + +/// One of the simplest smart contracts possible, +/// it holds a single variable in storage, which anyone can increment. +#[multiversx_sc::contract] +#[esdt_attribute("testBasic", BigUint)] +#[esdt_attribute("testVec", ManagedVec)] +#[esdt_attribute("testEnum", MyEnum)] +#[esdt_attribute("testOption", Option)] +#[esdt_attribute("testStruct", MyStruct)] +pub trait Adder: module::ModuleExample { + #[view(getSum)] + #[storage_mapper("sum")] + fn sum(&self) -> SingleValueMapper; + + #[init] + fn init(&self, initial_value: BigUint) { + self.sum().set(initial_value); + } + + /// Add desired amount to the storage variable. + #[endpoint] + fn add(&self, value: BigUint) { + self.sum().update(|sum| *sum += value); + } +} + +#[derive(TypeAbi)] +pub struct MyStruct { + pub field1: BigUint, + pub field2: ManagedVec>, +} + +#[derive(TypeAbi)] +pub enum MyEnum { + First, + Second, + Third, +} + +``` + +Same as before, we use `sc-meta all abi` and a new file named `testStruct.esdt-abi.json` shows up in our folder structure: + +``` +adder +├── output +│ ├── adder.abi.json +│ ├── adder.imports.json +| ├── adder.mxsc.json +| ├── adder.wasm +│ ├── testBasic.esdt-abi.json +│ ├── testEnum.esdt-abi.json +│ ├── testOption.esdt-abi.json +│ ├── testStruct.esdt-abi.json +│ ├── testVec.esdt-abi.json +``` + +__testStruct.esdt-abi.json:__ +```json +{ + "esdtAttribute": { + "ticker": "testStruct", + "type": "MyStruct" + }, + "types": { + "MyStruct": { + "type": "struct", + "fields": [ + { + "name": "field1", + "type": "BigUint" + }, + { + "name": "field2", + "type": "List" + } + ] + } + } +} +``` + +As a final check, let's take a look at the main abi file, `adder.abi.json`, after adding multiple new attributes. + +__adder.abi.json:__ +```json +{ + "buildInfo": { + "rustc": { + "version": "1.71.0-nightly", + "commitHash": "a2b1646c597329d0a25efa3889b66650f65de1de", + "commitDate": "2023-05-25", + "channel": "Nightly", + "short": "rustc 1.71.0-nightly (a2b1646c5 2023-05-25)" + }, + "contractCrate": { + "name": "adder", + "version": "0.0.0", + "gitVersion": "v0.44.0" + }, + "framework": { + "name": "multiversx-sc", + "version": "0.44.0" + } + }, + "docs": [ + "One of the simplest smart contracts possible,", + "it holds a single variable in storage, which anyone can increment." + ], + "name": "Adder", + "constructor": { + "inputs": [ + { + "name": "initial_value", + "type": "BigUint" + } + ], + "outputs": [] + }, + "endpoints": [ + { + "name": "getSum", + "mutability": "readonly", + "inputs": [], + "outputs": [ + { + "type": "BigUint" + } + ] + }, + { + "docs": [ + "Add desired amount to the storage variable." + ], + "name": "add", + "mutability": "mutable", + "inputs": [ + { + "name": "value", + "type": "BigUint" + } + ], + "outputs": [] + } + ], + "events": [], + "esdtAttributes": [ + { + "ticker": "testBasic", + "type": "BigUint" + }, + { + "ticker": "testVec", + "type": "List" + }, + { + "ticker": "testEnum", + "type": "MyEnum" + }, + { + "ticker": "testOption", + "type": "Option" + }, + { + "ticker": "testStruct", + "type": "MyStruct" + } + ], + "hasCallback": false, + "types": { + "MyEnum": { + "type": "enum", + "variants": [ + { + "name": "First", + "discriminant": 0 + }, + { + "name": "Second", + "discriminant": 1 + }, + { + "name": "Third", + "discriminant": 2 + } + ] + }, + "MyStruct": { + "type": "struct", + "fields": [ + { + "name": "field1", + "type": "BigUint" + }, + { + "name": "field2", + "type": "List" + } + ] + } + } +} +``` \ No newline at end of file From 848d73fa71c0d36e3750f723fbdb4da87f7d1bdf Mon Sep 17 00:00:00 2001 From: mihaicalinluca Date: Wed, 8 Nov 2023 11:21:24 +0100 Subject: [PATCH 02/10] fix after review --- docs/developers/data/abi.md | 525 +++++++----------------------------- 1 file changed, 100 insertions(+), 425 deletions(-) diff --git a/docs/developers/data/abi.md b/docs/developers/data/abi.md index 9d2146835..5ed899ebd 100644 --- a/docs/developers/data/abi.md +++ b/docs/developers/data/abi.md @@ -93,6 +93,7 @@ At its base minimum, an ABI contains: } ], "events": [], + "esdtAttributes": [], "hasCallback": false, "types": {} } @@ -145,7 +146,27 @@ 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: +Have a look at this example with custom types. + +Let's take the following `enum` and `struct`: + +```rust +#[derive(TypeAbi)] +pub struct MyAbiStruct { + pub field1: BigUint, + pub field2: ManagedVec>, + pub field3: (bool, i32) +} + +#[derive(TypeAbi)] +pub enum MyAbiEnum { + Nothing, + Something(i32), + SomethingMore(u8, MyAbiStruct), +} +``` + +And this is their json representation: ```json { @@ -177,6 +198,7 @@ Have a look at this example with custom types: } ], "events": [], + "esdtAttributes": [], "hasCallback": false, "types": { "MyAbiStruct": { @@ -284,131 +306,69 @@ You can read more about Rust enums [here](https://doc.rust-lang.org/book/ch06-01 [comment]: # (mx-context-auto) -## Custom ABI exports +## ESDT Attribute ABI ### Overview +Even though the `#[derive(TypeAbi)]` annotation exports all the data types used in the contract along with the type descriptions, we have also implemented a manual way to export data about an ESDT. The structure resembles an ESDT ticker and its attributes' type and gets exported in the main ABI file (and also in separate json files) in order to fetch it easier from other services (e.g. the developer can define the type of the attributes expected for a specific ESDT, fetch it from abi and use it easily in the frontend for a more specific result). -Even though the `#[derive(TypeAbi)]` annotation exports all the data types used in the contract along with the type descriptions, we have implemented a manual way to export any kind of data type (used inside the contract or not) in the ABI file in order to fetch it easier from other services (e.g. use-case: the developer can define the type of the attributes expected for a specific ESDT, fetch it from abi and use it easily in the frontend for a more specific result). - -Starting with the framework version `0.44`, developers can use the new trait annotation `#[esdt_attribute("name", Type)]` in order to export any data types in the ABI file. +Starting with the framework version `0.44`, developers can use the new trait annotation `#[esdt_attribute("name", Type)]` in order to export ESDT attributes types in the ABI file. :::important Important -Please note that it is a `trait annotation`, meaning that it can only be used at trait level along with other `#[multiversx_sc]` annotation. Using it at endpoint level or at trait level outside `multiversx_sc` environment will not work. +Please note that it is a `trait annotation`, meaning that it can only be used at trait level along with `#[multiversx_sc::contract]` or `#[multiversx_sc::module]` annotations. Using it at endpoint level or at trait level outside `multiversx_sc` annotations will not work. ::: -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). +### Details -### Basic types +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). -Let's take the `Adder` contract as an example and try out the new annotation. +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. + +### Example using basic types + +Let's take a simple contract `SomeContract` as an example and try out the new annotation. + +```rust,file=lib.rs +#![no_std] + +multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); -__adder.rs:__ -```rust #[multiversx_sc::contract] #[esdt_attribute("testBasic", BigUint)] -pub trait Adder { - #[view(getSum)] - #[storage_mapper("sum")] - fn sum(&self) -> SingleValueMapper; +pub trait SomeContract { #[init] - fn init(&self, initial_value: BigUint) { - self.sum().set(initial_value); - } - - /// Add desired amount to the storage variable. - #[endpoint] - fn add(&self, value: BigUint) { - self.sum().update(|sum| *sum += value); - } + fn init(&self) {} } ``` -Adding the `#[esdt_attribute("testBasic", BigUint)]` at trait level along with `#[multiversx_sc::contract]` should export a new structure named `testBasic` with a `BigUint` field type. The abi can be generated calling `sc-meta all abi` in the contract folder, or by building the contract using `sc-meta all build` (this command also adds the wasm file to the `output` folder). +Adding the `#[esdt_attribute("testBasic", BigUint)]` at trait level along with `#[multiversx_sc::contract]` should export a new structure named `testBasic` with a `BigUint` field type. This structure resembles an ESDT with the ticker `testBasic` and the attributes fields of type `BigUint`. + +The abi can be generated calling `sc-meta all abi` in the contract folder, or by building the contract using `sc-meta all build` (this command also adds the `wasm` file to the `output` folder). Building the contract using `sc-meta all build` will generate the following folder structure: ``` -adder +some_contract ├── output -│ ├── adder.abi.json -│ ├── adder.imports.json -| ├── adder.mxsc.json -| ├── adder.wasm +│ ├── some_contract.abi.json +│ ├── some_contract.imports.json +| ├── some_contract.mxsc.json +| ├── some_contract.wasm │ ├── testBasic.esdt-abi.json ``` -Let's check out the `adder.abi.json` file first. Here we discover the new `esdtAttributes` field, containing the value mentioned in the annotation. +Let's check out the `some_contract.abi.json` file first. Here we discover the new `esdtAttributes` field, containing the value mentioned in the annotation. ```json { - "buildInfo": { - "rustc": { - "version": "1.71.0-nightly", - "commitHash": "a2b1646c597329d0a25efa3889b66650f65de1de", - "commitDate": "2023-05-25", - "channel": "Nightly", - "short": "rustc 1.71.0-nightly (a2b1646c5 2023-05-25)" - }, - "contractCrate": { - "name": "adder", - "version": "0.0.0", - "gitVersion": "v0.44.0" - }, - "framework": { - "name": "multiversx-sc", - "version": "0.44.0" - } - }, - "docs": [ - "One of the simplest smart contracts possible,", - "it holds a single variable in storage, which anyone can increment." - ], - "name": "Adder", - "constructor": { - "inputs": [ - { - "name": "initial_value", - "type": "BigUint" - } - ], - "outputs": [] - }, - "endpoints": [ - { - "name": "getSum", - "mutability": "readonly", - "inputs": [], - "outputs": [ - { - "type": "BigUint" - } - ] - }, - { - "docs": [ - "Add desired amount to the storage variable." - ], - "name": "add", - "mutability": "mutable", - "inputs": [ - { - "name": "value", - "type": "BigUint" - } - ], - "outputs": [] - } - ], - "events": [], "esdtAttributes": [ { "ticker": "testBasic", "type": "BigUint" } - ], - "hasCallback": false, - "types": {} + ] } + ``` We can also check the specific json file exported for the newly defined type where we can find information about the type separated from the main abi file. @@ -422,202 +382,70 @@ __testBasic.esdt-abi.json__ } ``` -## Composite types +## 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` and an `Option` to our esdt attributes. +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. -__adder.rs:__ -```rust -#![no_std] -use multiversx_sc::derive::TypeAbi; +```rust,file=lib.rs +#![no_std] multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); -/// One of the simplest smart contracts possible, -/// it holds a single variable in storage, which anyone can increment. #[multiversx_sc::contract] #[esdt_attribute("testBasic", BigUint)] -#[esdt_attribute("testVec", ManagedVec)] -#[esdt_attribute("testEnum", MyEnum)] +#[esdt_attribute("testEnum", MyAbiEnum)] #[esdt_attribute("testOption", Option)] -pub trait Adder: module::ModuleExample { - #[view(getSum)] - #[storage_mapper("sum")] - fn sum(&self) -> SingleValueMapper; - +#[esdt_attribute("testVec", ManagedVec)] +pub trait SomeContract { #[init] - fn init(&self, initial_value: BigUint) { - self.sum().set(initial_value); - } - - /// Add desired amount to the storage variable. - #[endpoint] - fn add(&self, value: BigUint) { - self.sum().update(|sum| *sum += value); - } + fn init(&self) {} } - -#[derive(TypeAbi)] -pub enum MyEnum { - First, - Second, - Third, -} - ``` -If we call `sc-meta all abi` (or `sc-meta all build` if we also wish to build the contract), the new attributes will be added to our __adder.abi.json__ file and new separate json files will be created for each attribute. +If we call `sc-meta all abi` (or `sc-meta all build` if we also wish to build the contract), the new attributes will be added to our __some_contract.abi.json__ file and new separate json files will be created for each attribute. Now, our `esdtAttributes` section from our abi file should look like this: -__adder.abi.json:__ +__some_contract.abi.json__ ```json { - "buildInfo": { - "rustc": { - "version": "1.71.0-nightly", - "commitHash": "a2b1646c597329d0a25efa3889b66650f65de1de", - "commitDate": "2023-05-25", - "channel": "Nightly", - "short": "rustc 1.71.0-nightly (a2b1646c5 2023-05-25)" - }, - "contractCrate": { - "name": "adder", - "version": "0.0.0", - "gitVersion": "v0.44.0" - }, - "framework": { - "name": "multiversx-sc", - "version": "0.44.0" - } - }, - "docs": [ - "One of the simplest smart contracts possible,", - "it holds a single variable in storage, which anyone can increment." - ], - "name": "Adder", - "constructor": { - "inputs": [ - { - "name": "initial_value", - "type": "BigUint" - } - ], - "outputs": [] - }, - "endpoints": [ - { - "name": "getSum", - "mutability": "readonly", - "inputs": [], - "outputs": [ - { - "type": "BigUint" - } - ] - }, - { - "docs": [ - "Add desired amount to the storage variable." - ], - "name": "add", - "mutability": "mutable", - "inputs": [ - { - "name": "value", - "type": "BigUint" - } - ], - "outputs": [] - } - ], - "events": [], "esdtAttributes": [ { "ticker": "testBasic", "type": "BigUint" }, - { - "ticker": "testVec", - "type": "List" - }, { "ticker": "testEnum", - "type": "MyEnum" + "type": "MyAbiEnum" }, { "ticker": "testOption", "type": "Option" + }, + { + "ticker": "testVec", + "type": "List" } ], - "hasCallback": false, - "types": { - "MyEnum": { - "type": "enum", - "variants": [ - { - "name": "First", - "discriminant": 0 - }, - { - "name": "Second", - "discriminant": 1 - }, - { - "name": "Third", - "discriminant": 2 - } - ] - }, - } } - ``` Now, if we take a look into the folder structure of the contract, we should see the following updated folder structure containing the newly generated files in `output`: ``` -adder +some_contract ├── output -│ ├── adder.abi.json -│ ├── adder.imports.json -| ├── adder.mxsc.json -| ├── adder.wasm +│ ├── some_contract.abi.json +│ ├── some_contract.imports.json +| ├── some_contract.mxsc.json +| ├── some_contract.wasm │ ├── testBasic.esdt-abi.json │ ├── testEnum.esdt-abi.json │ ├── testOption.esdt-abi.json │ ├── testVec.esdt-abi.json ``` -Each file contains the new struct with its name and the type field's description. - -__testEnum.esdt-abi.json:__ -```json -{ - "esdtAttribute": { - "ticker": "testEnum", - "type": "MyEnum" - }, - "types": { - "MyEnum": { - "type": "enum", - "variants": [ - { - "name": "First", - "discriminant": 0 - }, - { - "name": "Second", - "discriminant": 1 - }, - { - "name": "Third", - "discriminant": 2 - } - ] - } - } -} -``` +Each file contains the new struct with its name and the type field's description such as: __testOption.esdt-abi.json:__ ```json @@ -629,76 +457,37 @@ __testOption.esdt-abi.json:__ } ``` -__testVec.esdt-abi.json:__ -```json -{ - "esdtAttribute": { - "ticker": "testVec", - "type": "List" - } -} -``` - -## Custom types +Let's also add a custom `struct` into the mix. For this example we are going to use `MyAbiStruct` declared above. -Let's also add a custom `Struct` into the mix. Here is the updated code for __adder.rs:__ +Here is the updated code for __lib.rs:__ -```rust +```rust,file=lib.rs #![no_std] -use multiversx_sc::derive::TypeAbi; - multiversx_sc::imports!(); +multiversx_sc::derive_imports!(); -/// One of the simplest smart contracts possible, -/// it holds a single variable in storage, which anyone can increment. #[multiversx_sc::contract] #[esdt_attribute("testBasic", BigUint)] -#[esdt_attribute("testVec", ManagedVec)] -#[esdt_attribute("testEnum", MyEnum)] +#[esdt_attribute("testEnum", MyAbiEnum)] #[esdt_attribute("testOption", Option)] -#[esdt_attribute("testStruct", MyStruct)] -pub trait Adder: module::ModuleExample { - #[view(getSum)] - #[storage_mapper("sum")] - fn sum(&self) -> SingleValueMapper; - +#[esdt_attribute("testVec", ManagedVec)] +#[esdt_attribute("testStruct", MyAbiStruct)] +pub trait SomeContract { #[init] - fn init(&self, initial_value: BigUint) { - self.sum().set(initial_value); - } - - /// Add desired amount to the storage variable. - #[endpoint] - fn add(&self, value: BigUint) { - self.sum().update(|sum| *sum += value); - } + fn init(&self) {} } - -#[derive(TypeAbi)] -pub struct MyStruct { - pub field1: BigUint, - pub field2: ManagedVec>, -} - -#[derive(TypeAbi)] -pub enum MyEnum { - First, - Second, - Third, -} - ``` Same as before, we use `sc-meta all abi` and a new file named `testStruct.esdt-abi.json` shows up in our folder structure: ``` -adder +some_contract ├── output -│ ├── adder.abi.json -│ ├── adder.imports.json -| ├── adder.mxsc.json -| ├── adder.wasm +│ ├── some_contract.abi.json +│ ├── some_contract.imports.json +| ├── some_contract.mxsc.json +| ├── some_contract.wasm │ ├── testBasic.esdt-abi.json │ ├── testEnum.esdt-abi.json │ ├── testOption.esdt-abi.json @@ -706,149 +495,35 @@ adder │ ├── testVec.esdt-abi.json ``` -__testStruct.esdt-abi.json:__ -```json -{ - "esdtAttribute": { - "ticker": "testStruct", - "type": "MyStruct" - }, - "types": { - "MyStruct": { - "type": "struct", - "fields": [ - { - "name": "field1", - "type": "BigUint" - }, - { - "name": "field2", - "type": "List" - } - ] - } - } -} -``` -As a final check, let's take a look at the main abi file, `adder.abi.json`, after adding multiple new attributes. +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. -__adder.abi.json:__ +__some_contract.abi.json:__ ```json { - "buildInfo": { - "rustc": { - "version": "1.71.0-nightly", - "commitHash": "a2b1646c597329d0a25efa3889b66650f65de1de", - "commitDate": "2023-05-25", - "channel": "Nightly", - "short": "rustc 1.71.0-nightly (a2b1646c5 2023-05-25)" - }, - "contractCrate": { - "name": "adder", - "version": "0.0.0", - "gitVersion": "v0.44.0" - }, - "framework": { - "name": "multiversx-sc", - "version": "0.44.0" - } - }, - "docs": [ - "One of the simplest smart contracts possible,", - "it holds a single variable in storage, which anyone can increment." - ], - "name": "Adder", - "constructor": { - "inputs": [ - { - "name": "initial_value", - "type": "BigUint" - } - ], - "outputs": [] - }, - "endpoints": [ - { - "name": "getSum", - "mutability": "readonly", - "inputs": [], - "outputs": [ - { - "type": "BigUint" - } - ] - }, - { - "docs": [ - "Add desired amount to the storage variable." - ], - "name": "add", - "mutability": "mutable", - "inputs": [ - { - "name": "value", - "type": "BigUint" - } - ], - "outputs": [] - } - ], - "events": [], "esdtAttributes": [ { "ticker": "testBasic", "type": "BigUint" }, - { - "ticker": "testVec", - "type": "List" - }, { "ticker": "testEnum", - "type": "MyEnum" + "type": "MyAbiEnum" }, { "ticker": "testOption", "type": "Option" }, + { + "ticker": "testVec", + "type": "List" + }, { "ticker": "testStruct", - "type": "MyStruct" + "type": "MyAbiStruct" } ], - "hasCallback": false, - "types": { - "MyEnum": { - "type": "enum", - "variants": [ - { - "name": "First", - "discriminant": 0 - }, - { - "name": "Second", - "discriminant": 1 - }, - { - "name": "Third", - "discriminant": 2 - } - ] - }, - "MyStruct": { - "type": "struct", - "fields": [ - { - "name": "field1", - "type": "BigUint" - }, - { - "name": "field2", - "type": "List" - } - ] - } - } } -``` \ No newline at end of file +``` + +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). \ No newline at end of file From 0fe18e19a0a2400934f3cc50f269597f87c9bfb9 Mon Sep 17 00:00:00 2001 From: mihaicalinluca Date: Wed, 8 Nov 2023 12:14:49 +0100 Subject: [PATCH 03/10] added title to code snippets --- docs/developers/data/abi.md | 18 +++++++----------- docs/developers/tutorials/crowdfunding-p1.md | 4 ++-- docs/developers/tutorials/crowdfunding-p2.md | 8 ++++---- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/docs/developers/data/abi.md b/docs/developers/data/abi.md index 5ed899ebd..c60c447ea 100644 --- a/docs/developers/data/abi.md +++ b/docs/developers/data/abi.md @@ -327,7 +327,7 @@ The name/ticker is just a way to identify the idea of the token because we do no Let's take a simple contract `SomeContract` as an example and try out the new annotation. -```rust,file=lib.rs +```rust title=lib.rs #![no_std] multiversx_sc::imports!(); @@ -372,8 +372,7 @@ Let's check out the `some_contract.abi.json` file first. Here we discover the ne ``` We can also check the specific json file exported for the newly defined type where we can find information about the type separated from the main abi file. -__testBasic.esdt-abi.json__ -```json +```json title=testBasic.esdt-abi.json { "esdtAttribute": { "ticker": "testBasic", @@ -387,7 +386,7 @@ __testBasic.esdt-abi.json__ 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,file=lib.rs +```rust title=lib.rs #![no_std] multiversx_sc::imports!(); @@ -406,8 +405,7 @@ pub trait SomeContract { If we call `sc-meta all abi` (or `sc-meta all build` if we also wish to build the contract), the new attributes will be added to our __some_contract.abi.json__ file and new separate json files will be created for each attribute. Now, our `esdtAttributes` section from our abi file should look like this: -__some_contract.abi.json__ -```json +```json title=some_contract.abi.json { "esdtAttributes": [ { @@ -447,8 +445,7 @@ some_contract Each file contains the new struct with its name and the type field's description such as: -__testOption.esdt-abi.json:__ -```json +```json title=testOption.esdt-abi.json { "esdtAttribute": { "ticker": "testOption", @@ -461,7 +458,7 @@ Let's also add a custom `struct` into the mix. For this example we are going to Here is the updated code for __lib.rs:__ -```rust,file=lib.rs +```rust title=lib.rs #![no_std] multiversx_sc::imports!(); @@ -498,8 +495,7 @@ some_contract 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. -__some_contract.abi.json:__ -```json +```json title=some_contract.abi.json { "esdtAttributes": [ { diff --git a/docs/developers/tutorials/crowdfunding-p1.md b/docs/developers/tutorials/crowdfunding-p1.md index 199a4554e..ff2cf6183 100644 --- a/docs/developers/tutorials/crowdfunding-p1.md +++ b/docs/developers/tutorials/crowdfunding-p1.md @@ -86,7 +86,7 @@ Let's have a quick look around the project. Open `Cargo.toml` in the text editor of your choice, and add the following content: -```toml,file=Cargo.toml +```toml title=Cargo.toml [package] name = "crowdfunding" version = "0.0.0" @@ -117,7 +117,7 @@ Let's see what this means: With the structure in place, you can now write the code and build it. Open `src/crowdfunding.rs` , remove the existing `Empty` code and insert the following: -```rust,file=hello-world.rs +```rust title=hello-world.rs #![no_std] multiversx_sc::imports!(); diff --git a/docs/developers/tutorials/crowdfunding-p2.md b/docs/developers/tutorials/crowdfunding-p2.md index 309098408..282a687d1 100644 --- a/docs/developers/tutorials/crowdfunding-p2.md +++ b/docs/developers/tutorials/crowdfunding-p2.md @@ -41,7 +41,7 @@ Also note that BigUint logic does not reside in the contract, but is built into Let's test that initialization works. -```json,file=crowdfunding-init.scen.json +```json title=crowdfunding-init.scen.json { "name": "crowdfunding deployment test", "steps": [ @@ -151,7 +151,7 @@ To test the function, we'll add a new test file, in the same `scenarios` folder. To avoid duplicating the deployment code, we import it from `crowdfunding-init.scen.json` . -```json,file=crowdfunding-fund.scen.json +```json title=crowdfunding-fund.scen.json { "name": "crowdfunding funding", "steps": [ @@ -268,7 +268,7 @@ It doesn't make sense to fund after the deadline has passed, so fund transaction We'll create another test file to verify that the validation works: `test-fund-too-late.scen.json` . -```json,file=crowdfunding-fund-too-late.scen.json +```json title=crowdfunding-fund-too-late.scen.json { "name": "trying to fund one block too late", "steps": [ @@ -468,7 +468,7 @@ The only new function here is `self.send().direct_egld()`, which simply forwards If you followed all the steps presented until now, you should have ended up with a contract that looks something like: -```rust,file=final.rs +```rust title=final.rs #![no_std] multiversx_sc::imports!(); From a5f9fdb22131fb3f8e3afa7bade1439cf6e0d816 Mon Sep 17 00:00:00 2001 From: mihaicalinluca Date: Wed, 8 Nov 2023 12:42:56 +0100 Subject: [PATCH 04/10] small title fix --- docs/developers/data/abi.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/developers/data/abi.md b/docs/developers/data/abi.md index c60c447ea..4ef04d531 100644 --- a/docs/developers/data/abi.md +++ b/docs/developers/data/abi.md @@ -381,7 +381,7 @@ We can also check the specific json file exported for the newly defined type whe } ``` -## Using more complex types +### 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. From 195a3d64717eafe2d6a769925845320a4f90b6e4 Mon Sep 17 00:00:00 2001 From: mihaicalinluca Date: Wed, 8 Nov 2023 14:20:38 +0100 Subject: [PATCH 05/10] added docs for sc-meta all abi --- docs/developers/meta/sc-meta-cli.md | 34 ++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/docs/developers/meta/sc-meta-cli.md b/docs/developers/meta/sc-meta-cli.md index 6d13acbf6..3cb3bb962 100644 --- a/docs/developers/meta/sc-meta-cli.md +++ b/docs/developers/meta/sc-meta-cli.md @@ -280,7 +280,6 @@ Paramameters: - Creates test files if they don't exist. - --- [comment]: # (mx-exclude-context) @@ -289,6 +288,39 @@ Paramameters: [comment]: # (mx-context-auto) +### Calling `abi` + +ABI generation can be triggered by calling `sc-meta all abi` or `cargo run abi` in the contract root folder. This command generates the main ABI file of the contract (`.abi.json`) along with all the other json files created if `#[esdt_attribute("name", type)]` was used (`.esdt-abi.json`). You can read more about ESDT Attribute ABI [here](/developers/data/abi#esdt-attribute-abi). + +For a simple contract such as: + +```rust title=lib.rs +#[multiversx_sc::contract] +#[esdt_attribute("myTicker", u64)] +pub trait SomeContract { + #[init] + fn init(&self) {} +} +``` + +The produced files are: + +```text +output +├── myTicker.esdt-abi.json +├── some_contract.abi.json +``` + +Arguments: + +- `--path` Used to specify a target directory where to call all contract meta crates. Will be current directory if not specified. +- `--ignore` Followed by a name is used to ignore all directories with these names [default: `target`]. +- `--no-abi-git-version` Skips loading the Git version into the ABI +- `--target-dir-meta` For the meta crates, allows specifying the target directory where the Rust compiler will build the intermediary files. Sharing the same target directory can speed up building multiple contract crates at once. +- `--target-dir-all` Overrides both the `--target-dir-meta` and the `--target-dir-wasm` args. + +[comment]: # (mx-context-auto) + ### Calling `build` A build can be triggered by calling either `sc-meta all build` or `cargo run build` in the meta crate of the contract. In fact, the standalone `sc-meta` tool simply forwards the command to the contract meta crate itself. From f8b73ce9083d8419df404ea118b6b6ee66908756 Mon Sep 17 00:00:00 2001 From: mihaicalinluca Date: Wed, 8 Nov 2023 14:22:15 +0100 Subject: [PATCH 06/10] small fix in output folder structure sc-meta all abi --- docs/developers/meta/sc-meta-cli.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/developers/meta/sc-meta-cli.md b/docs/developers/meta/sc-meta-cli.md index 3cb3bb962..c3fe06577 100644 --- a/docs/developers/meta/sc-meta-cli.md +++ b/docs/developers/meta/sc-meta-cli.md @@ -308,7 +308,7 @@ The produced files are: ```text output ├── myTicker.esdt-abi.json -├── some_contract.abi.json +└── some_contract.abi.json ``` Arguments: From ca7a622604999ec1c3949b26a3b7655f3e836730 Mon Sep 17 00:00:00 2001 From: mihaicalinluca Date: Wed, 8 Nov 2023 21:17:03 +0100 Subject: [PATCH 07/10] added docs for the new annotation allow_multiple_var_args --- docs/developers/data/multi-values.md | 40 +++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/docs/developers/data/multi-values.md b/docs/developers/data/multi-values.md index e05abc039..a87dfb542 100644 --- a/docs/developers/data/multi-values.md +++ b/docs/developers/data/multi-values.md @@ -26,7 +26,42 @@ In effect, all serializable types implement the multi-value traits. ## Parsing and limitations -It is important to understand that arguments get read one by one from left to right, so there are some limitations as to how var-args can be positioned. Argument types also define how the arguments are consumed, so, for instance, if a type specifies that all remaining arguments will be consumed, it doesn't really make sense to have any other argument after that. +It is important to understand that arguments get read one by one from left to right, so there are some limitations as to how var-args can be positioned. Argument types also define how the arguments are consumed, so, for instance, if a type specifies that all remaining arguments will be consumed, it doesn't really make sense to have any other argument after that. + +For instance, let's consider the behavior of `MultiValueEncoded`, which consumes all subsequent arguments. Hence, it's advisable to place it as the last argument in the function, like so: + +```rust +#[endpoint(myEndpoint)] +fn my_endpoint(&self, first_arg: ManagedBuffer, second_arg: TokenIdentifier, last_arg: MultiValueEncoded) +``` +Placing any argument after `MultiValueEncoded` will not initialize that argument, because `MultiValueEncoded` will consume all arguments following it. An important rule to remember is that an endpoint can have only one `MultiValueEncoded` argument, and it should always occupy the last position in order to achieve the desired outcome. + +Another scenario to consider involves the use of multiple `Option` arguments. Take, for instance, the following endpoint: + +```rust +#[endpoint(myOptionalEndpoint)] +fn my_optional_endpoint(&self, first_arg: Option, second_arg: Option) +``` +In this context, both arguments (or none) should be provided at the same time in order to get the desired effect. Since arguments are processed sequentially from left to right, supplying a single value will automatically assign it to the first argument, making it impossible to determine which argument should receive that value. + +The same rule applies when any regular argument is placed after a var-arg, so we have enforced a strong restriction regarding arguments' order. Regular arguments `must not` be placed after var-args. + +To further enhance clarity and minimize potential errors related to var-args, starting from framework version `v0.44.0`, we have introduced a new annotation called `#[allow_multiple_var_args]`. + +:::info Note +`#[allow_multiple_var_args]` is required when using more than one var-arg in an endpoint and is placed at the endpoint level, alongside the `#[endpoint]` annotation. Utilizing `#[allow_multiple_var_args]` in any other manner will not work. + +Considering this, our optional endpoint from the example before becomes: +```rust +#[allow_multiple_var_args] +#[endpoint(myOptionalEndpoint)] +fn my_optional_endpoint(&self, first_arg: Option, second_arg: Option) +``` +::: + +The only parsing validations are taking into account the number of var-args and their position. Not having `#[allow_multiple_var_args]` as an endpoint attribute if the endpoint is using more than one var-arg and/or placing regular arguments after var-args will fail the build. + +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) @@ -218,3 +253,6 @@ 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). + + + From 1521c72b5937977437b3fb43773d84920c602df1 Mon Sep 17 00:00:00 2001 From: mihaicalinluca Date: Thu, 9 Nov 2023 13:12:53 +0100 Subject: [PATCH 08/10] fix after review --- docs/developers/data/multi-values.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/developers/data/multi-values.md b/docs/developers/data/multi-values.md index a87dfb542..5cdb750b2 100644 --- a/docs/developers/data/multi-values.md +++ b/docs/developers/data/multi-values.md @@ -40,13 +40,13 @@ Another scenario to consider involves the use of multiple `Option` arguments. Ta ```rust #[endpoint(myOptionalEndpoint)] -fn my_optional_endpoint(&self, first_arg: Option, second_arg: Option) +fn my_optional_endpoint(&self, first_arg: OptionalValue, second_arg: OptionalValue) ``` In this context, both arguments (or none) should be provided at the same time in order to get the desired effect. Since arguments are processed sequentially from left to right, supplying a single value will automatically assign it to the first argument, making it impossible to determine which argument should receive that value. -The same rule applies when any regular argument is placed after a var-arg, so we have enforced a strong restriction regarding arguments' order. Regular arguments `must not` be placed after var-args. +The same rule applies when any regular argument is placed after a var-arg, thus, a strong restriction regarding arguments' order has been enforced. Regular arguments `must not` be placed after var-args. -To further enhance clarity and minimize potential errors related to var-args, starting from framework version `v0.44.0`, we have introduced a new annotation called `#[allow_multiple_var_args]`. +To further enhance clarity and minimize potential errors related to var-args, starting from framework version `v0.44.0`, it is no longer allowed by default to have multiple var-args. This restriction can be lifted by using the #[allow_multiple_var_args] annotation. :::info Note `#[allow_multiple_var_args]` is required when using more than one var-arg in an endpoint and is placed at the endpoint level, alongside the `#[endpoint]` annotation. Utilizing `#[allow_multiple_var_args]` in any other manner will not work. @@ -55,11 +55,11 @@ Considering this, our optional endpoint from the example before becomes: ```rust #[allow_multiple_var_args] #[endpoint(myOptionalEndpoint)] -fn my_optional_endpoint(&self, first_arg: Option, second_arg: Option) +fn my_optional_endpoint(&self, first_arg: OptionalValue, second_arg: OptionalValue) ``` ::: -The only parsing validations are taking into account the number of var-args and their position. Not having `#[allow_multiple_var_args]` as an endpoint attribute if the endpoint is using more than one var-arg and/or placing regular arguments after var-args will fail the build. +The absence of #[allow_multiple_var_args] as an endpoint attribute, along with the use of multiple var-args and/or the placement of regular arguments after var-args, leads to build failure, as the parsing validations now consider the count and positions of var-args. 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. From b72f99a8017f1ad97056f2b31a27532d7df75e14 Mon Sep 17 00:00:00 2001 From: mihaicalinluca Date: Thu, 9 Nov 2023 15:26:57 +0100 Subject: [PATCH 09/10] fix after review --- docs/developers/data/abi.md | 13 +++++++++++-- docs/developers/meta/sc-meta-cli.md | 2 ++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/docs/developers/data/abi.md b/docs/developers/data/abi.md index 4ef04d531..b2b3a6d81 100644 --- a/docs/developers/data/abi.md +++ b/docs/developers/data/abi.md @@ -309,14 +309,23 @@ You can read more about Rust enums [here](https://doc.rust-lang.org/book/ch06-01 ## ESDT Attribute ABI ### Overview -Even though the `#[derive(TypeAbi)]` annotation exports all the data types used in the contract along with the type descriptions, we have also implemented a manual way to export data about an ESDT. The structure resembles an ESDT ticker and its attributes' type and gets exported in the main ABI file (and also in separate json files) in order to fetch it easier from other services (e.g. the developer can define the type of the attributes expected for a specific ESDT, fetch it from abi and use it easily in the frontend for a more specific result). +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. Starting with the framework version `0.44`, developers can use the new trait annotation `#[esdt_attribute("name", Type)]` in order to export ESDT attributes types in the ABI file. +The name field is an arbitrary name provided by the developer, to identify the token. Token identifiers are not hard-coded in contracts, but it can make sense to use the ticker here, if known. + +The type field is simply the name of the type, as it would show up in regular smart contract code. + :::important Important -Please note that it is a `trait annotation`, meaning that it can only be used at trait level along with `#[multiversx_sc::contract]` or `#[multiversx_sc::module]` annotations. Using it at endpoint level or at trait level outside `multiversx_sc` annotations will not work. +The annotation can only be used at trait level along with `#[multiversx_sc::contract]` or `#[multiversx_sc::module]` annotations. Using it anywhere else will not work. ::: +The exported data will end up in 2 places: +1. In the contract ABI, in a special `"esdt_attributes"` section; +2. In a special ESDT ABI file (`name.esdt-abi.json`), one for each such declared ESDT. +More examples of this below. + ### 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). diff --git a/docs/developers/meta/sc-meta-cli.md b/docs/developers/meta/sc-meta-cli.md index c3fe06577..89448bf11 100644 --- a/docs/developers/meta/sc-meta-cli.md +++ b/docs/developers/meta/sc-meta-cli.md @@ -292,6 +292,8 @@ Paramameters: ABI generation can be triggered by calling `sc-meta all abi` or `cargo run abi` in the contract root folder. This command generates the main ABI file of the contract (`.abi.json`) along with all the other json files created if `#[esdt_attribute("name", type)]` was used (`.esdt-abi.json`). You can read more about ESDT Attribute ABI [here](/developers/data/abi#esdt-attribute-abi). +ABI generation will also be triggered for all the other contract commands, such as `build`, `build-dbg`, `update`, etc. The `abi` command is for when we just want to generate the ABI and do nothing else. + For a simple contract such as: ```rust title=lib.rs From cd0081774360230eec9c8011d05d269e11d5c5ee Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Mon, 20 Nov 2023 10:40:59 +0200 Subject: [PATCH 10/10] formatting fix --- docs/developers/data/abi.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/developers/data/abi.md b/docs/developers/data/abi.md index b2b3a6d81..5a14f3034 100644 --- a/docs/developers/data/abi.md +++ b/docs/developers/data/abi.md @@ -324,6 +324,7 @@ The annotation can only be used at trait level along with `#[multiversx_sc::cont The exported data will end up in 2 places: 1. In the contract ABI, in a special `"esdt_attributes"` section; 2. In a special ESDT ABI file (`name.esdt-abi.json`), one for each such declared ESDT. + More examples of this below. ### Details