diff --git a/.eslintrc b/.eslintrc index 320057018..5bf90ea75 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,6 +1,11 @@ { "extends": ["plugin:@fuels/next"], "rules": { - "import/no-unresolved": "off" + "import/no-named-as-default-member": "off", + "import/no-named-as-default": "off", + "import/default": "off", + "import/namespace": "off", + "import/no-unresolved": "off", + "import/order": "off" } } diff --git a/.eslintrc.prod b/.eslintrc.prod index f5b6ca38b..5bf90ea75 100644 --- a/.eslintrc.prod +++ b/.eslintrc.prod @@ -1,6 +1,10 @@ { "extends": ["plugin:@fuels/next"], "rules": { + "import/no-named-as-default-member": "off", + "import/no-named-as-default": "off", + "import/default": "off", + "import/namespace": "off", "import/no-unresolved": "off", "import/order": "off" } diff --git a/.github/actions/setup-node/action.yaml b/.github/actions/setup-node/action.yaml index c3f25b5f2..dae359e61 100644 --- a/.github/actions/setup-node/action.yaml +++ b/.github/actions/setup-node/action.yaml @@ -2,7 +2,7 @@ name: "CI setup" inputs: node-version: description: "Node version" - default: 18.14.1 + default: 18.18.2 pnpm-version: description: "PNPM version" default: latest diff --git a/.github/workflows/guides.yml b/.github/workflows/guides.yml index bc1109bba..71c978f67 100644 --- a/.github/workflows/guides.yml +++ b/.github/workflows/guides.yml @@ -53,32 +53,20 @@ jobs: - uses: ./.github/actions/setup-node with: install: false + - uses: dtolnay/rust-toolchain@stable # INSTALLATIONS - name: Install dependencies run: pnpm install - name: Install Playwright Browsers run: npx playwright install --with-deps chromium - - name: Install Rust - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - name: Install cargo-generate - uses: actions-rs/cargo@v1 - with: - command: install - args: cargo-generate + run: cargo install cargo-generate --locked - name: Install Fuelup run: | curl --proto '=https' --tlsv1.2 -sSf https://install.fuel.network/fuelup-init.sh | sh - name: Modify Path run: echo "$HOME/.fuelup/bin:${GITHUB_PATH}" >> $GITHUB_PATH - - # CONFIGURE FUEL TOOLCHAIN - - name: Set Default Beta-4 Toolchain - run: fuelup toolchain install beta-4 && fuelup default beta-4 # RUN E2E TESTS - name: Run Playwright tests for ${{ matrix.guide }} diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml index dde62cd4a..e318c3e8a 100644 --- a/.github/workflows/links.yml +++ b/.github/workflows/links.yml @@ -30,4 +30,4 @@ jobs: - name: Check All Links run: | - linkchecker --check-extern --no-warnings --ignore-url=crates.io --ignore-url=127.0.0.1 --ignore-url=block-explorer-v2 --ignore-url=localhost: --ignore-url=infura.io --ignore-url=chainsecurity.com --ignore-url=-indexer.fuel.network --ignore-url=beta-4.fuel.network/graphql ${{ github.event.deployment_status.environment_url }}/sitemap.xml + linkchecker --check-extern --no-warnings --ignore-url=crates.io --ignore-url=127.0.0.1 --ignore-url=block-explorer-v2 --ignore-url=localhost: --ignore-url=infura.io --ignore-url=chainsecurity.com --ignore-url=-indexer.fuel.network --ignore-url=beta-5.fuel.network/graphql ${{ github.event.deployment_status.environment_url }}/sitemap.xml \ No newline at end of file diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 8bef81660..4f942f70f 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -23,7 +23,11 @@ jobs: steps: - uses: actions/checkout@v3 - uses: ./.github/actions/setup-node - - run: pnpm audit --prod + with: + install: false + - run: | + pnpm install + pnpm audit --prod lint: name: Lint @@ -36,9 +40,11 @@ jobs: - name: Checkout uses: actions/checkout@v3 - - name: Setup Node - uses: ./.github/actions/setup-node + - uses: ./.github/actions/setup-node + with: + install: false - name: Run lint run: | + pnpm install pnpm check:prod diff --git a/.gitmodules b/.gitmodules index b7bff65d0..34ea7dfc6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,9 +22,6 @@ [submodule "docs/fuelup"] path = docs/fuelup url = https://github.com/FuelLabs/fuelup.git -[submodule "docs/fuel-indexer"] - path = docs/fuel-indexer - url = https://github.com/FuelLabs/fuel-indexer.git [submodule "docs/fuel-specs"] path = docs/fuel-specs url = https://github.com/FuelLabs/fuel-specs.git @@ -61,6 +58,3 @@ [submodule "docs/nightly/fuelup"] path = docs/nightly/fuelup url = https://github.com/FuelLabs/fuelup.git -[submodule "docs/nightly/fuel-indexer"] - path = docs/nightly/fuel-indexer - url = https://github.com/FuelLabs/fuel-indexer.git diff --git a/.markdownlintignore b/.markdownlintignore index cbf0bdbfe..3c5d82da2 100644 --- a/.markdownlintignore +++ b/.markdownlintignore @@ -9,3 +9,4 @@ docs/fuels-wallet docs/fuel-specs docs/fuel-indexer docs/fuel-graphql-docs +docs/beta-4 diff --git a/contentlayer.config.ts b/contentlayer.config.ts index d4591e389..fced1cc85 100644 --- a/contentlayer.config.ts +++ b/contentlayer.config.ts @@ -51,56 +51,57 @@ const MdDoc = defineDocumentType(() => ({ })); const includeDirs = [ + // DEFAULT DOCS & GUIDES 'docs/sway/docs/book/src', 'docs/fuelup/docs/src', 'docs/fuels-rs/docs/src', 'docs/fuels-ts/apps/docs/src', - 'docs/fuel-indexer/docs/src', 'docs/fuel-specs/src', 'docs/fuel-graphql-docs/docs', 'docs/fuels-wallet/packages/docs/docs', 'docs/guides/docs', 'docs/intro', - // 'docs/fuel-nix/book/src', - // 'docs/about-fuel', + // NIGHTLY DOCS 'docs/nightly/sway/docs/book/src', 'docs/nightly/fuelup/docs/src', 'docs/nightly/fuels-rs/docs/src', 'docs/nightly/fuels-ts/apps/docs/src', - 'docs/nightly/fuel-indexer/docs/src', 'docs/nightly/fuel-specs/src', 'docs/nightly/fuel-graphql-docs/docs', 'docs/nightly/fuels-wallet/packages/docs/docs', - // 'docs/nightly/guides/docs', - // 'docs/nightly/about-fuel', + // BETA-4 DOCS + 'docs/beta-4/sway/docs/book/src', + 'docs/beta-4/fuelup/docs/src', + 'docs/beta-4/fuels-rs/docs/src', + 'docs/beta-4/fuels-ts/apps/docs/src', + 'docs/beta-4/fuel-specs/src', + 'docs/beta-4/fuel-graphql-docs/docs', + 'docs/beta-4/fuels-wallet/packages/docs/docs', + // 'docs/beta-4/guides/docs', ]; const excludeDirs = [ + // DEFAULT DOCS & GUIDES 'docs/guides/docs/guides.json', 'docs/guides/docs/nav.json', + 'docs/guides/docs/migration-guide/breaking-change-log/README.md', + 'docs/guides/docs/migration-guide/breaking-change-log/package.json', + 'docs/guides/docs/migration-guide/breaking-change-log/pnpm-lock.yaml', 'docs/intro/nav.json', - // 'docs/about-fuel/nav.json', 'docs/sway/docs/book/src/SUMMARY.md', - 'docs/sway/docs/book/src/forc/commands/forc_deploy.md', - 'docs/sway/docs/book/src/forc/commands/forc_run.md', 'docs/fuelup/docs/src/SUMMARY.md', 'docs/fuels-rs/docs/src/SUMMARY.md', - 'docs/fuel-indexer/docs/src/SUMMARY.md', 'docs/fuel-specs/src/SUMMARY.md', - // 'docs/nightly/guides/docs/guides.json', - // 'docs/nightly/guides/docs/nav.json', - // 'docs/nightly/about-fuel/nav.json', + // NIGHTLY DOCS 'docs/nightly/sway/docs/book/src/SUMMARY.md', - 'docs/nightly/sway/docs/book/src/forc/commands/forc_deploy.md', - 'docs/nightly/sway/docs/book/src/forc/commands/forc_run.md', 'docs/nightly/fuelup/docs/src/SUMMARY.md', 'docs/nightly/fuels-rs/docs/src/SUMMARY.md', - 'docs/nightly/fuel-indexer/docs/src/SUMMARY.md', 'docs/nightly/fuel-specs/src/SUMMARY.md', - // 'docs/fuel-nix/book/src/SUMMARY.md', - 'docs/guides/docs/migration-guide/breaking-change-log/README.md', - 'docs/guides/docs/migration-guide/breaking-change-log/package.json', - 'docs/guides/docs/migration-guide/breaking-change-log/pnpm-lock.yaml', + // BETA-4 DOCS + 'docs/beta-4/sway/docs/book/src/SUMMARY.md', + 'docs/beta-4/fuelup/docs/src/SUMMARY.md', + 'docs/beta-4/fuels-rs/docs/src/SUMMARY.md', + 'docs/beta-4/fuel-specs/src/SUMMARY.md', ]; export default makeSource({ diff --git a/docs/beta-4/builds/sway/master/book/advanced/advanced_types.html b/docs/beta-4/builds/sway/master/book/advanced/advanced_types.html new file mode 100644 index 000000000..04db5a394 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/advanced/advanced_types.html @@ -0,0 +1,224 @@ + + + + + + Advanced Types - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Advanced Types

+

Creating Type Synonyms with Type Aliases

+

Sway provides the ability to declare a type alias to give an existing type another name. For this we use the type keyword. For example, we can create the alias Kilometers to u64 like so:

+
type Kilometers = u64;
+
+

Now, the alias Kilometers is a synonym for u64. Note that Kilometers is not a separate new type. Values that have the type Kilometers will be treated the same as values of type u64:

+
    let x: u64 = 5;
+    let y: Kilometers = 5;
+    assert(x + y == 10);
+
+

Because Kilometers and u64 are the same type, we can add values of both types and we can pass Kilometers values to functions that take u64 parameters. However, using this method, we don’t get the type checking benefits that we get from introducing a separate new type called Kilometers. In other words, if we mix up Kilometers and i32 values somewhere, the compiler will not give us an error.

+

The main use case for type synonyms is to reduce repetition. For example, we might have a lengthy array type like this:

+
[MyStruct<u64, b256>; 5]
+
+

Writing this lengthy type in function signatures and as type annotations all over the code can be tiresome and error prone. Imagine having a project full of code like this:

+
fn foo_long(array: [MyStruct<u64, b256>; 5]) -> [MyStruct<u64, b256>; 5] {
+    array
+}
+
+

A type alias makes this code more manageable by reducing the repetition. Below, we’ve introduced an alias named MyArray for the verbose type and can replace all uses of the type with the shorter alias MyArray:

+
type MyArray = [MyStruct<u64, b256>; 5];
+
+fn foo_shorter(array: MyArray) -> MyArray {
+    array
+}
+
+

This code is much easier to read and write! Choosing a meaningful name for a type alias can help communicate your intent as well.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/advanced/assembly.html b/docs/beta-4/builds/sway/master/book/advanced/assembly.html new file mode 100644 index 000000000..5717f85a2 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/advanced/assembly.html @@ -0,0 +1,248 @@ + + + + + + Assembly - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Inline Assembly in Sway

+

While many users will never have to touch assembly language while writing sway code, it is a powerful tool that enables many advanced use-cases (ie: optimizations, building libraries, etc).

+

ASM Block

+

In Sway, the way we use assembly inline is to declare an asm block like this:

+
asm() {...}
+
+

Declaring an asm block is similar to declaring a function. +We can specify register names to operate on as arguments, we can perform operations within the block, and we can return a value. +Here's an example showing what this might look like:

+
pub fn add_1(num: u32) -> u32 {
+    asm(r1: num, r2) {
+        add r2 r1 one;
+        r2: u32
+    }
+}
+
+

An asm block can only return a single register. If you really need to return more than one value, you can modify a tuple. Here's an example showing how can implement this (u64, u64):

+
script;
+
+fn adder(a: u64, b: u64, c: u64) -> (u64, u64) {
+    let empty_tuple = (0u64, 0u64);
+    asm(output: empty_tuple, r1: a, r2: b, r3: c, r4, r5) {
+        add  r4 r1 r2; // add a & b and put the result in r4
+        add  r5 r2 r3; // add b & c and put the result in r5
+        sw   output r4 i0; // store the word in r4 in output + 0 words
+        sw   output r5 i1; // store the word in r5 in output + 1 word
+        output: (u64, u64) // return both values
+    }
+}
+
+fn main() -> bool {
+    let (first, second) = adder(1, 2, 3);
+    assert(first == 3);
+    assert(second == 5);
+    true
+}
+
+

Note that this is contrived example meant to demonstrate the syntax; there's absolutely no need to use assembly to add integers!

+

Note that in the above example:

+
    +
  • we initialized the register r1 with the value of num.
  • +
  • we declared a second register r2 (you may choose any register names you want).
  • +
  • we use the add opcode to add one to the value of r1 and store it in r2.
  • +
  • one is an example of a "reserved register", of which there are 16 in total. Further reading on this is linked below under "Semantics".
  • +
  • we return r2 & specify the return type as being u32 (the return type is u64 by default).
  • +
+

An important note is that the ji and jnei opcodes are not available within an asm block. For those looking to introduce control flow to asm blocks, it is recommended to surround smaller chunks of asm with control flow (if, else, and while).

+ +

For examples of assembly in action, check out the Sway standard library.

+

For a complete list of all instructions supported in the FuelVM: Instructions.

+

And to learn more about the FuelVM semantics: Semantics.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/advanced/associated_types.html b/docs/beta-4/builds/sway/master/book/advanced/associated_types.html new file mode 100644 index 000000000..6135eccab --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/advanced/associated_types.html @@ -0,0 +1,248 @@ + + + + + + Associated Types - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Associated Types

+

Associated types in Sway allow you to define placeholder types within a trait, which can be customized by concrete +implementations of that trait. These associated types are used to specify the return types of trait methods or to +define type relationships within the trait.

+

Associated types are a powerful feature of Sway's trait system, enabling generic programming and abstraction over +types. They help improve code clarity and maintainability by allowing you to define generic traits without committing +to specific types.

+

Declaring Associated Types

+

Associated types are declared within a trait using the type keyword. Here's the syntax for declaring an associated type:

+
trait MyTrait {
+    type AssociatedType;
+}
+
+

Implementing Associated Types

+

Concrete implementations of a trait with associated types must provide a specific type for each associated type +defined in the trait. Here's an example of implementing a trait with an associated type:

+
struct MyStruct;
+
+impl MyTrait for MyStruct {
+    type AssociatedType = u32; // Implementing the associated type with u32
+}
+
+

In this example, MyStruct implements MyTrait and specifies that the associated type AssociatedType is u32.

+

Using Associated Types

+

Associated types are used within trait methods or where the trait is used as a bound for generic functions or +structs. You can use the associated type like any other type. Here's an example:

+
trait MyTrait {
+    type AssociatedType;
+    
+    fn get_value(self) -> Self::AssociatedType;
+}
+
+struct MyStruct;
+
+impl MyTrait for MyStruct {
+    type AssociatedType = u32;
+
+    fn get_value(self) -> Self::AssociatedType {
+        42
+    }
+}
+
+

In this example, get_value is a trait method that returns an associated type AssociatedType.

+

Use Cases

+

Associated types are particularly useful in scenarios where you want to define traits that work with different +types of data structures or abstractions, allowing the implementor to specify the concrete types. Some common use cases include:

+
    +
  • Collections: Traits for generic collections that allow users to specify the type of elements.
  • +
  • Iterator Patterns: Traits for implementing iterators with varying element types.
  • +
  • Serialization and Deserialization: Traits for serializing and deserializing data with different data formats.
  • +
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/advanced/generic_types.html b/docs/beta-4/builds/sway/master/book/advanced/generic_types.html new file mode 100644 index 000000000..c67640e2d --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/advanced/generic_types.html @@ -0,0 +1,293 @@ + + + + + + Generic Types - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Generic Types

+

Basics

+

In Sway, generic types follow a very similar pattern to those in Rust. Let's look at some example syntax, +starting with a generic function:

+
fn noop<T>(argument: T) -> T {
+    argument
+}
+
+

Here, the noop() function trivially returns exactly what was given to it. T is a type parameter, and it says +that this function exists for all types T. More formally, this function could be typed as:

+
noop :: ∀T. T -> T
+
+

Generic types are a way to refer to types in general, meaning without specifying a single type. Our noop function +would work with any type in the language, so we don't need to specify noop(argument: u8) -> u8, noop(argument: u16) -> u16, etc.

+

Code Generation

+

One question that arises when dealing with generic types is: how does the assembly handle this? There are a few approaches to handling +generic types at the lowest level. Sway uses a technique called monomorphization. This +means that the generic function is compiled to a non-generic version for every type it is called on. In this way, generic functions are +purely shorthand for the sake of ergonomics.

+

Trait Constraints

+

Important background to know before diving into trait constraints is that the where clause can be used to specify the required traits for the generic argument. So, when writing something like a HashMap you may +want to specify that the generic argument implements a Hash trait.

+
fn get_hashmap_key<T>(Key : T) -> b256
+    where T: Hash
+{
+    // Code within here can then call methods associated with the Hash trait on Key
+}
+
+

Of course, our noop() function is not useful. Often, a programmer will want to declare functions over types which satisfy certain traits. +For example, let's try to implement the successor function, successor(), for all numeric types.

+
fn successor<T>(argument: T)
+    where T: Add
+{
+    argument + 1
+}
+
+

Run forc build, and you will get:

+
.. |
+ 9 |   where T: Add
+10 |   {
+11 |       argument + 1                                        
+   |                  ^ Mismatched types: expected type "T" but saw type "u64"
+12 |   }
+13 |
+
+

This is because we don't know for a fact that 1, which in this case defaulted to 1u64, actually can be added to T. What if T is f64? Or b256? What does it mean to add 1u64 in these cases?

+

We can solve this problem with another trait constraint. We can only find the successor of some value of type T if that type T defines some incrementor. Let's make a trait:

+
trait Incrementable {
+    /// Returns the value to add when calculating the successor of a value.
+    fn incrementor() -> Self;
+}
+
+

Now, we can modify our successor() function:

+
fn successor<T>(argument: T)
+    where T: Add,
+          T: Incrementable
+{
+    argument + T::incrementor()
+}
+
+

Generic Structs and Enums

+

Just like functions, structs and enums can be generic. Let's take a look at the standard library version of Option<T>:

+
enum Option<T> {
+    Some: T,
+    None: (),
+}
+
+

Just like an unconstrained generic function, this type exists for all (∀) types T. Result<T, E> is another example:

+
enum Result<T, E> {
+    Ok: T,
+    Err: E,
+}
+
+

Both generic enums and generic structs can be trait constrained, as well. Consider this struct:

+
struct Foo<T>
+    where T: Add
+{
+    field_one: T,
+}
+
+

Type Arguments

+

Similar to Rust, Sway has what is colloquially known as the turbofish. The turbofish looks like this: ::<> (see the little fish with bubbles behind it?). The turbofish is used to annotate types in a generic context. Say you have the following function:

+
fn foo<T, E>(t: T) -> Result<T, E> {
+    Ok(t)
+}
+
+

In this code example, which is admittedly asinine, you can't possibly know what type E is. You'd need to provide the type manually, with a turbofish:

+
fn foo<T, E>(t: T) -> Result<T, E> {
+    Ok::<T, MyErrorType>(t)
+}
+
+

It is also common to see the turbofish used on the function itself:

+
fn main() {
+    foo::<Bar, Baz>()
+}
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/advanced/generics_and_trait_constraints.html b/docs/beta-4/builds/sway/master/book/advanced/generics_and_trait_constraints.html new file mode 100644 index 000000000..860824840 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/advanced/generics_and_trait_constraints.html @@ -0,0 +1,266 @@ + + + + + + Generics and Trait Constraints - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Generics and Trait Constraints

+

Generics as Constraints

+

At a high level, Sway allows you to define constraints, or restrictions, that +allow you to strike a balance between writing abstract and reusable code and +enforcing compile-time checks to determine if the abstract code that you've +written is correct.

+

The "abstract and reusable" part largely comes from generic types and the +"enforcing compile-time checks" part largely comes from trait constraints. +Generic types can be used with functions, structs, and enums (as we have seen in +this book), but they can also be used with traits.

+

Generic Traits

+

Combining generic types with traits allows you to write abstract and reusable +traits that can be implemented for any number of data types.

+

For example, imagine that you want to write a trait for converting between +different types. This would be similar to Rust's Into and From traits. In +Sway your conversion trait would look something like:

+
trait Convert<T> {
+    fn from(t: T) -> Self;
+}
+
+

The trait Convert takes a generic type T. Convert has one method +from, which takes one parameter of type T and returns a Self. This means +that when you implement Convert for a data type, from will return the type +of that data type but will take as input the type that you define as T. Here +is an example:

+
struct Square {
+    width: u64,
+}
+
+struct Rectangle {
+    width: u64,
+    length: u64,
+}
+
+impl Convert<Square> for Rectangle {
+    fn from(t: Square) -> Self {
+        Self {
+            width: t.width,
+            length: t.width,
+        }
+    }
+}
+
+

In this example, you have two different data types, Square and Rectangle. +You know that all squares are rectangles and thus Square can convert into Rectangle (but not vice +versa) and thus you can implement the conversion trait for those types.

+

If we want to call these methods we can do so by:

+
fn main() {
+    let s = Square { width: 5 };
+    let r = Rectangle::from(s);
+}
+
+

Trait Constraints

+

Trait constraints allow you to use generic types and traits to place constraints +on what abstract code you are willing to accept in your program as correct. +These constraints take the form of compile-time checks for correctness.

+

If we wanted to use trait constraints with our Convert trait from the previous +section we could do so like so:

+
fn into_rectangle<T>(t: T) -> Rectangle
+where
+    Rectangle: Convert<T>
+{
+    Rectangle::from(t)
+}
+
+

This function allows you to take any generic data type T and convert it to the +type Rectangle as long as Convert<T> is implemented for Rectangle. +Calling this function with a type T for which Convert<T> is not implemented +for Rectangle will fail Sway's compile-time checks.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/advanced/index.html b/docs/beta-4/builds/sway/master/book/advanced/index.html new file mode 100644 index 000000000..b75420b2f --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/advanced/index.html @@ -0,0 +1,207 @@ + + + + + + Advanced Concepts - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + +
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/advanced/traits.html b/docs/beta-4/builds/sway/master/book/advanced/traits.html new file mode 100644 index 000000000..7baba70a8 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/advanced/traits.html @@ -0,0 +1,388 @@ + + + + + + Traits - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Traits

+

Declaring a Trait

+

A trait opts a type into a certain type of behavior or functionality that can be shared among types. This allows for easy reuse of code and generic programming. If you have ever used a typeclass in Haskell, a trait in Rust, or even an interface in Java, these are similar concepts.

+

Let's take a look at some code:

+
trait Compare {
+    fn equals(self, b: Self) -> bool;
+} {
+    fn not_equals(self, b: Self) -> bool {
+        !self.equals(b)
+    }
+}
+
+

We have just declared a trait called Compare. After the name of the trait, there are two blocks of code (a block is code enclosed in { curly brackets }). The first block is the interface surface. The second block is the methods provided by the trait. If a type can provide the methods in the interface surface, then it gets access to the methods in the trait for free! What the above trait is saying is: if you can determine if two values are equal, then for free, you can determine that they are not equal. Note that trait methods have access to the methods defined in the interface surface.

+

Implementing a Trait

+

Ok, so I know that numbers can be equal. I want to implement my Compare trait for u64. Let's take a look at how that is done:

+
impl Compare for u64 {
+    fn equals(self, b: Self) -> bool {
+        self == b
+    }
+}
+
+

The above snippet declares all of the methods in the trait Compare for the type u64. Now, we have access to both the equals and not_equals methods for u64, as long as the trait Compare is in scope.

+

Supertraits

+

When using multiple traits, scenarios often come up where one trait may require functionality from another trait. This is where supertraits come in as they allow you to require a trait when implementing another +trait (ie. a trait with a trait). A good example of this is the Ord trait of the core library of Sway. The Ord trait requires the Eq trait, so Eq is kept as a separate trait as one may decide to implement Eq +without implementing other parts of the Ord trait.

+

+trait Eq {
+    fn equals(self, b: Self) -> bool;
+}
+
+trait Ord: Eq {
+    fn gte(self, b: Self) -> bool;
+}
+
+impl Ord for u64 {
+    fn gte(self, b: Self) -> bool {
+        // As `Eq` is a supertrait of `Ord`, `Ord` can access the equals method
+        self.equals(b) || self.gt(b)
+    }
+}
+
+

To require a supertrait, add a : after the trait name and then list the traits you would like to require and separate them with a +.

+

ABI supertraits

+

ABIs can also have supertrait annotations:

+
contract;
+
+struct Foo {}
+impl ABIsupertrait for Foo {
+    fn foo() {}
+}
+
+trait ABIsupertrait {
+    fn foo();
+}
+
+abi MyAbi : ABIsupertrait {
+    fn bar();
+} {
+    fn baz() {
+        Self::foo() // supertrait method usage
+    }
+}
+
+impl ABIsupertrait for Contract {
+    fn foo() {}
+}
+
+// The implementation of MyAbi for Contract must also implement ABIsupertrait
+impl MyAbi for Contract {
+    fn bar() {
+        Self::foo() // supertrait method usage
+    }
+}
+
+

The implementation of MyAbi for Contract must also implement the ABIsupertrait trait. Methods in ABIsupertrait are not available externally, i.e. they're not actually contract methods, but they can be used in the actual contract methods, as shown in the example above.

+

ABI supertraits are intended to make contract implementations compositional, allowing combining orthogonal contract features using, for instance, libraries.

+

SuperABIs

+

In addition to supertraits, ABIs can have superABI annotations:

+
contract;
+
+abi MySuperAbi {
+    fn foo();
+}
+
+abi MyAbi : MySuperAbi {
+    fn bar();
+}
+
+impl MySuperAbi for Contract {
+    fn foo() {}
+}
+
+// The implementation of MyAbi for Contract must also implement MySuperAbi
+impl MyAbi for Contract {
+    fn bar() {}
+}
+
+

The implementation of MyAbi for Contract must also implement the MySuperAbi superABI. Methods in MySuperAbi will be part of the MyAbi contract interface, i.e. will be available externally (and hence cannot be called from other MyAbi contract methods).

+

SuperABIs are intended to make contract implementations compositional, allowing combining orthogonal contract features using, for instance, libraries.

+

Associated Items

+

Traits can declare different kinds of associated items in their interface surface:

+ +

Associated functions

+

Associated functions in traits consist of just function signatures. This indicates that each implementation of the trait for a given type must define all the trait functions.

+
trait Trait {
+    fn associated_fn(self, b: Self) -> bool;
+}
+
+

Associated constants

+

Associated constants are constants associated with a type.

+
trait Trait {
+    const ID: u32 = 0;
+}
+
+

The initializer expression of an associated constants in a trait definition may be omitted to indicate that each implementation of the trait for a given type must specify an initializer:

+
trait Trait {
+    const ID: u32;
+}
+
+

Check the associated consts section on constants page.

+

Associated types

+

Associated types in Sway allow you to define placeholder types within a trait, which can be customized by concrete +implementations of that trait. These associated types are used to specify the return types of trait methods or to +define type relationships within the trait.

+
trait MyTrait {
+    type AssociatedType;
+}
+
+

Check the associated types section on associated types page.

+

Use Cases

+

Custom Types (structs, enums)

+

Often, libraries and APIs have interfaces that are abstracted over a type that implements a certain trait. It is up to the consumer of the interface to implement that trait for the type they wish to use with the interface. For example, let's take a look at a trait and an interface built off of it.

+
library;
+
+pub enum Suit {
+    Hearts: (),
+    Diamonds: (),
+    Clubs: (),
+    Spades: (),
+}
+
+pub trait Card {
+    fn suit(self) -> Suit;
+    fn value(self) -> u8;
+}
+
+fn play_game_with_deck<T>(a: Vec<T>) where T: Card {
+    // insert some creative card game here
+}
+
+
+

Note Trait constraints (i.e. using the where keyword) have not yet been implemented

+
+

Now, if you want to use the function play_game_with_deck with your struct, you must implement Card for your struct. Note that the following code example assumes a dependency games has been included in the Forc.toml file.

+
script;
+
+use games::*;
+
+struct MyCard {
+    suit: Suit,
+    value: u8
+}
+
+impl Card for MyCard {
+    fn suit(self) -> Suit {
+        self.suit
+    }
+    fn value(self) -> u8 {
+        self.value
+    }
+}
+
+fn main() {
+    let mut i = 52;
+    let mut deck: Vec<MyCard> = Vec::with_capacity(50);
+    while i > 0 {
+        i = i - 1;
+        deck.push(MyCard { suit: generate_random_suit(), value: i % 4}
+    }
+    play_game_with_deck(deck);
+}
+
+fn generate_random_suit() -> Suit {
+  [ ... ]
+}
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/basics/blockchain_types.html b/docs/beta-4/builds/sway/master/book/basics/blockchain_types.html new file mode 100644 index 000000000..dac61b6f3 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/basics/blockchain_types.html @@ -0,0 +1,263 @@ + + + + + + Blockchain Types - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Blockchain Types

+

Sway is fundamentally a blockchain language, and it offers a selection of types tailored for the blockchain use case.

+

These are provided via the standard library (lib-std) which both add a degree of type-safety, as well as make the intention of the developer more clear.

+

Address Type

+ + +

The Address type is a type-safe wrapper around the primitive b256 type. Unlike the EVM, an address never refers to a deployed smart contract (see the ContractId type below). An Address can be either the hash of a public key (effectively an externally owned account if you're coming from the EVM) or the hash of a predicate. Addresses own UTXOs.

+ +

An Address is implemented as follows.

+
pub struct Address {
+    value: b256,
+}
+
+

Casting between the b256 and Address types must be done explicitly:

+
let my_number: b256 = 0x000000000000000000000000000000000000000000000000000000000000002A;
+let my_address: Address = Address::from(my_number);
+let forty_two: b256 = my_address.into();
+
+

ContractId Type

+ + +

The ContractId type is a type-safe wrapper around the primitive b256 type. A contract's ID is a unique, deterministic identifier analogous to a contract's address in the EVM. Contracts cannot own UTXOs but can own assets.

+ +

A ContractId is implemented as follows.

+
pub struct ContractId {
+    value: b256,
+}
+
+

Casting between the b256 and ContractId types must be done explicitly:

+
let my_number: b256 = 0x000000000000000000000000000000000000000000000000000000000000002A;
+let my_contract_id: ContractId = ContractId::from(my_number);
+let forty_two: b256 = my_contract_id.into();
+
+

Identity Type

+ + +

The Identity type is an enum that allows for the handling of both Address and ContractId types. This is useful in cases where either type is accepted, e.g. receiving funds from an identified sender, but not caring if the sender is an address or a contract.

+ +

An Identity is implemented as follows.

+
pub enum Identity {
+    Address: Address,
+    ContractId: ContractId,
+}
+
+

Casting to an Identity must be done explicitly:

+
        let raw_address: b256 = 0xddec0e7e6a9a4a4e3e57d08d080d71a299c628a46bc609aab4627695679421ca;
+        let my_identity: Identity = Identity::Address(Address::from(raw_address));
+
+

A match statement can be used to return to an Address or ContractId as well as handle cases in which their execution differs.

+
        let my_contract_id: ContractId = match my_identity {
+            Identity::ContractId(identity) => identity,
+            _ => revert(0),
+        };
+
+
        match my_identity {
+            Identity::Address(address) => transfer_to_address(address, token_id, amount),
+            Identity::ContractId(contract_id) => force_transfer_to_contract(contract_id, token_id, amount),
+        };
+
+ + +

A common use case for Identity is for access control. The use of Identity uniquely allows both ContractId and Address to have access control inclusively.

+ +
        let sender = msg_sender().unwrap();
+        require(sender == storage.owner.read(), MyError::UnauthorizedUser(sender));
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/basics/built_in_types.html b/docs/beta-4/builds/sway/master/book/basics/built_in_types.html new file mode 100644 index 000000000..8f34bc086 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/basics/built_in_types.html @@ -0,0 +1,356 @@ + + + + + + Built-in Types - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Built-in Types

+

Every value in Sway is of a certain type. Although deep down, all values are just ones and zeroes in the underlying virtual machine, Sway needs to know what those ones and zeroes actually mean. This is accomplished with types.

+ + +

Sway is a statically typed language. At compile time, the types of every value must be known. This does not mean you need to specify every single type: usually, the type can be reasonably inferred by the compiler.

+ +

Primitive Types

+ + +

Sway has the following primitive types:

+
    +
  1. u8 (8-bit unsigned integer)
  2. +
  3. u16 (16-bit unsigned integer)
  4. +
  5. u32 (32-bit unsigned integer)
  6. +
  7. u64 (64-bit unsigned integer)
  8. +
  9. u256 (256-bit unsigned integer)
  10. +
  11. str[] (fixed-length string)
  12. +
  13. str (string slices)
  14. +
  15. bool (Boolean true or false)
  16. +
  17. b256 (256 bits (32 bytes), i.e. a hash)
  18. +
+

All other types in Sway are built up of these primitive types, or references to these primitive types. You may notice that there are no signed integers—this is by design. In the blockchain domain that Sway occupies, floating-point values and negative numbers have smaller utility, so their implementation has been left up to libraries for specific use cases.

+ +

Numeric Types

+

All of the unsigned integer types are numeric types.

+

Numbers can be declared with binary syntax, hexadecimal syntax, base-10 syntax, and underscores for delineation. Let's take a look at the following valid numeric primitives:

+
0xffffff    // hexadecimal
+0b10101010  // binary
+10          // base-10
+100_000     // underscore delineated base-10
+0x1111_0000 // underscore delineated binary
+0xfff_aaa   // underscore delineated hexadecimal
+
+ + +

The default numeric type is u64. The FuelVM's word size is 64 bits, and the cases where using a smaller numeric type saves space are minimal.

+

If a 64-bit or 256-bit arithmetic operation produces an overflow or an underflow, +computation gets reverted automatically by FuelVM.

+

8/16/32-bit arithmetic operations are emulated using their 64-bit analogues with +additional overflow/underflow checks inserted, which generally results in +somewhat higher gas consumption.

+

The same does not happen with 256-bit operations, including b256, which uses specialized operations and are as performant as possible.

+ +

Boolean Type

+ + +

The boolean type (bool) has two potential values: true or false. Boolean values are typically used for conditional logic or validation, for example in if expressions. Booleans can be negated, or flipped, with the unary negation operator !.

+ +

For example:

+
fn returns_false() -> bool {
+    let boolean_value: bool = true;
+    !boolean_value
+}
+
+

String Slices

+ + +

In Sway, string literals are stored as variable length string slices. Which means that they are stored as a pointer to the actual string data and its length.

+ +
let my_string: str = "fuel";
+
+

String slices, because they contain pointers have limited usage. They cannot be used is constants, storages, configurables, nor as main function argument or returns.

+

For these cases one must use string arrays, as described below.

+

String Arrays

+ + +

In Sway, static-length strings are a primitive type. This means that when you declare a string array, its size is a part of its type. This is necessary for the compiler to know how much memory to give for the storage of that data. The size of the string is denoted with square brackets.

+ +

Let's take a look:

+
let my_string: str[4] = __to_str_array("fuel");
+
+

Because the string literal "fuel" is four letters, the type is str[4], denoting a static length of 4 characters. Strings default to UTF-8 in Sway.

+

As above, string literals are typed as string slices. So that is why the need for __to_str_array that convert them to string arrays at compile time.

+

Conversion during runtime can be done with from_str_array and try_as_str_array. The latter can fail, given that the specified string array must be big enough for the string slice content.

+
let a: str = "abcd";
+let b: str[4] = a.try_as_str_array().unwrap();
+let c: str = from_str_array(b);
+
+

Compound Types

+

Compound types are types that group multiple values into one type. In Sway, we have arrays and tuples.

+

Tuple Types

+ + +

A tuple is a general-purpose static-length aggregation of types. In more plain terms, a tuple is a single type that consists of an aggregate of zero or more types. The internal types that make up a tuple, and the tuple's arity, define the tuple's type.

+ +

Let's take a look at some examples.

+
let x: (u64, u64) = (0, 0);
+
+

This is a tuple, denoted by parenthesized, comma-separated values. Note that the type annotation, (u64, u64), is similar in syntax to the expression which instantiates that type, (0, 0).

+
let x: (u64, bool) = (42, true);
+assert(x.1);
+
+

In this example, we have created a new tuple type, (u64, bool), which is a composite of a u64 and a bool.

+ + +

To access a value within a tuple, we use tuple indexing: x.1 stands for the first (zero-indexed, so the bool) value of the tuple. Likewise, x.0 would be the zeroth, u64 value of the tuple. Tuple values can also be accessed via destructuring.

+ +
struct Foo {}
+let x: (u64, Foo, bool) = (42, Foo {}, true);
+let (number, foo, boolean) = x;
+
+

To create one-arity tuples, we will need to add a trailing comma:

+
let x: u64 = (42);     // x is of type u64
+let y: (u64) = (42);   // y is of type u64
+let z: (u64,) = (42,); // z is of type (u64), i.e. a one-arity tuple
+let w: (u64) = (42,);  // type error
+
+

Arrays

+ + +

An array is similar to a tuple, but an array's values must all be of the same type. Arrays can hold arbitrary types including non-primitive types.

+ +

An array is written as a comma-separated list inside square brackets:

+
let x = [1, 2, 3, 4, 5];
+
+ + +

Arrays are allocated on the stack since their size is known. An array's size is always static, i.e. it cannot change. An array of five elements cannot become an array of six elements.

+

Arrays can be iterated over, unlike tuples. An array's type is written as the type the array contains followed by the number of elements, semicolon-separated and within square brackets, e.g. [u64; 5]. To access an element in an array, use the array indexing syntax, i.e. square brackets.

+ +

Array elements can also be mutated if the underlying array is declared as mutable:

+
let mut x = [1, 2, 3, 4, 5];
+x[0] = 0;
+
+
script;
+
+struct Foo {
+    f1: u32,
+    f2: b256,
+}
+
+fn main() {
+    // Array of integers with type ascription
+    let array_of_integers: [u8; 5] = [1, 2, 3, 4, 5];
+
+    // Array of strings
+    let array_of_strings = ["Bob", "Jan", "Ron"];
+
+    // Array of structs
+    let array_of_structs: [Foo; 2] = [
+        Foo {
+            f1: 11,
+            f2: 0x1111111111111111111111111111111111111111111111111111111111111111,
+        },
+        Foo {
+            f1: 22,
+            f2: 0x2222222222222222222222222222222222222222222222222222222222222222,
+        },
+    ];
+
+    // Accessing an element of an array
+    let mut array_of_bools: [bool; 2] = [true, false];
+    assert(array_of_bools[0]);
+
+    // Mutating the element of an array
+    array_of_bools[1] = true;
+    assert(array_of_bools[1]);
+}
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/basics/comments_and_logging.html b/docs/beta-4/builds/sway/master/book/basics/comments_and_logging.html new file mode 100644 index 000000000..33f3f577f --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/basics/comments_and_logging.html @@ -0,0 +1,276 @@ + + + + + + Comments and Logging - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Comments and Logging

+

Comments

+ + +

Comments in Sway start with two slashes and continue until the end of the line. For comments that extend beyond a single line, you'll need to include // on each line.

+ +
// hello world
+
+
// let's make a couple of lines
+// commented.
+
+

You can also place comments at the ends of lines containing code.

+
fn main() {
+    let baz = 8; // Eight is a lucky number
+}
+
+

You can also do block comments

+
fn main() {
+    /*
+    You can write on multiple lines
+    like this if you want
+    */
+    let baz = 8;
+}
+
+

Logging

+ + +

The logging library provides a generic log function that can be imported using use std::logging::log and used to log variables of any type. Each call to log appends a receipt to the list of receipts. There are two types of receipts that a log can generate: Log and LogData.

+ +
fn log_values(){
+  // Generates a Log receipt
+  log(42);
+
+  // Generates a LogData receipt
+  let string = "sway";
+  log(string);
+}
+
+

Log Receipt

+ + +

The Log receipt is generated for non-reference types, namely bool, u8, u16, u32, and u64.

+ +

For example, logging an integer variable x that holds the value 42 using log(x) may generate the following receipt:

+
"Log": {
+  "id": "0000000000000000000000000000000000000000000000000000000000000000",
+  "is": 10352,
+  "pc": 10404,
+  "ra": 42,
+  "rb": 1018205,
+  "rc": 0,
+  "rd": 0
+}
+
+

Note that ra will include the value being logged. The additional registers rc and rd will be zero when using log while rb may include a non-zero value representing a unique ID for the log instance. The unique ID is not meaningful on its own but allows the Rust and the TS SDKs to know the type of the data being logged, by looking up the log ID in the JSON ABI file.

+

LogData Receipt

+ + +

LogData is generated for reference types which include all types except for non_reference types; and for non-reference types bigger than 64-bit integers, for example, u256;

+ +

For example, logging a b256 variable b that holds the value 0x1111111111111111111111111111111111111111111111111111111111111111 using log(b) may generate the following receipt:

+
"LogData": {
+  "data": "1111111111111111111111111111111111111111111111111111111111111111",
+  "digest": "02d449a31fbb267c8f352e9968a79e3e5fc95c1bbeaa502fd6454ebde5a4bedc",
+  "id": "0000000000000000000000000000000000000000000000000000000000000000",
+  "is": 10352,
+  "len": 32,
+  "pc": 10444,
+  "ptr": 10468,
+  "ra": 0,
+  "rb": 1018194
+}
+
+

Note that data in the receipt above will include the value being logged as a hexadecimal. Similarly to the Log receipt, additional registers are written: ra will always be zero when using log, while rb will contain a unique ID for the log instance.

+
+

Note +The Rust SDK exposes APIs that allow you to retrieve the logged values and display them nicely based on their types as indicated in the JSON ABI file.

+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/basics/commonly_used_library_types.html b/docs/beta-4/builds/sway/master/book/basics/commonly_used_library_types.html new file mode 100644 index 000000000..1a12c4083 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/basics/commonly_used_library_types.html @@ -0,0 +1,283 @@ + + + + + + Commonly Used Library Types - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Commonly Used Library Types

+

The Sway Standard Library is the foundation of portable Sway software, a set of minimal shared abstractions for the broader Sway ecosystem. It offers core types, library-defined operations on language primitives, native asset management, blockchain contextual operations, access control, storage management, and support for types from other VMs, among many other things. Reference the standard library docs here.

+

Result<T, E>

+ + +

Type Result is the type used for returning and propagating errors. It is an enum with two variants: Ok(T), representing success and containing a value, and Err(E), representing error and containing an error value. The T and E in this definition are type parameters, allowing Result to be generic and to be used with any types.

+ +
/// `Result` is a type that represents either success (`Ok`) or failure (`Err`).
+pub enum Result<T, E> {
+    /// Contains the success value.
+    Ok: T,
+    /// Contains the error value.
+    Err: E,
+}
+
+ + +

Functions return Result whenever errors are expected and recoverable.

+ +

Take the following example:

+
script;
+
+enum MyContractError {
+    DivisionByZero: (),
+}
+
+fn divide(numerator: u64, denominator: u64) -> Result<u64, MyContractError> {
+    if (denominator == 0) {
+        return Err(MyContractError::DivisionByZero);
+    } else {
+        Ok(numerator / denominator)
+    }
+}
+
+fn main() -> Result<u64, str[4]> {
+    let result = divide(20, 2);
+    match result {
+        Ok(value) => Ok(value),
+        Err(MyContractError::DivisionByZero) => Err(__to_str_array("Fail")),
+    }
+}
+
+

Option<T>

+ + +

Type Option represents an optional value: every Option is either Some and contains a value, or None, and does not. Option types are very common in Sway code, as they have a number of uses:

+
    +
  • Initial values where None can be used as an initializer.
  • +
  • Return value for otherwise reporting simple errors, where None is returned on error.
  • +
+

The implementation of Option matches on the variant: if it's Ok it returns the inner value, if it's None, it reverts.

+ +
/// A type that represents an optional value, either `Some(val)` or `None`.
+pub enum Option<T> {
+    /// No value.
+    None: (),
+    /// Some value of type `T`.
+    Some: T,
+}
+
+ + +

Option is commonly paired with pattern matching to query the presence of a value and take action, allowing developers to choose how to handle the None case.

+ +

Below is an example that uses pattern matching to handle invalid divisions by 0 by returning an Option:

+
script;
+
+fn divide(numerator: u64, denominator: u64) -> Option<u64> {
+    if denominator == 0 {
+        None
+    } else {
+        Some(numerator / denominator)
+    }
+}
+
+fn main() {
+    let result = divide(6, 2);
+    // Pattern match to retrieve the value
+    match result {
+        // The division was valid
+        Some(x) => std::logging::log(x),
+        // The division was invalid
+        None => std::logging::log("Cannot divide by 0"),
+    }
+}
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/basics/constants.html b/docs/beta-4/builds/sway/master/book/basics/constants.html new file mode 100644 index 000000000..2acbda925 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/basics/constants.html @@ -0,0 +1,301 @@ + + + + + + Constants - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Constants

+ + +

Constants are similar to variables; however, there are a few differences:

+
    +
  • Constants are always evaluated at compile-time.
  • +
  • Constants can be declared both inside of a function and at global / impl scope.
  • +
  • The mut keyword cannot be used with constants.
  • +
+ +
const ID: u32 = 0;
+
+

Constant initializer expressions can be quite complex, but they cannot use, for +instance, assembly instructions, storage access, mutable variables, loops and +return statements. Although, function calls, primitive types and compound data +structures are perfectly fine to use:

+
fn bool_to_num(b: bool) -> u64 {
+    if b {
+        1
+    } else {
+        0
+    }
+}
+
+fn arr_wrapper(a: u64, b: u64, c: u64) -> [u64; 3] {
+    [a, b, c]
+}
+
+const ARR2 = arr_wrapper(bool_to_num(1) + 42, 2, 3);
+
+

Associated Constants

+ + +

Associated constants are constants associated with a type and can be declared in an impl block or in a trait definition.

+

Associated constants declared inside a trait definition may omit their initializers to indicate that each implementation of the trait must specify those initializers.

+

The identifier is the name of the constant used in the path. The type is the type that the +definition has to implement.

+ +

You can define an associated const directly in the interface surface of a trait:

+
script;
+
+trait ConstantId {
+    const ID: u32 = 0;
+}
+
+

Alternatively, you can also declare it in the trait, and implement it in the interface of the +types implementing the trait.

+
script;
+
+trait ConstantId {
+    const ID: u32;
+}
+
+struct Struct {}
+
+impl ConstantId for Struct {
+    const ID: u32 = 1;
+}
+
+fn main() -> u32 {
+    Struct::ID
+}
+
+

impl self Constants

+

Constants can also be declared inside non-trait impl blocks.

+
script;
+
+struct Point {
+    x: u64,
+    y: u64,
+}
+
+impl Point {
+    const ZERO: Point = Point { x: 0, y: 0 };
+}
+
+fn main() -> u64  {
+    Point::ZERO.x
+}
+
+

Configurable Constants

+ + +

Configurable constants are special constants that behave like regular constants in the sense that they cannot change during program execution, but they can be configured after the Sway program has been built. The Rust and TS SDKs allow updating the values of these constants by injecting new values for them directly in the bytecode without having to build the program again. These are useful for contract factories and behave somewhat similarly to immutable variables from languages like Solidity.

+ +

Configurable constants are declared inside a configurable block and require a type ascription and an initializer as follows:

+
configurable {
+    U8: u8 = 8u8,
+    BOOL: bool = true,
+    ARRAY: [u32; 3] = [253u32, 254u32, 255u32],
+    STR_4: str[4] = __to_str_array("fuel"),
+    STRUCT: StructWithGeneric<u8> = StructWithGeneric {
+        field_1: 8u8,
+        field_2: 16,
+    },
+    ENUM: EnumWithGeneric<bool> = EnumWithGeneric::VariantOne(true),
+}
+
+

At most one configurable block is allowed in a Sway project. Moreover, configurable blocks are not allowed in libraries.

+

Configurable constants can be read directly just like regular constants:

+
    fn return_configurables() -> (u8, bool, [u32; 3], str[4], StructWithGeneric<u8>) {
+        (U8, BOOL, ARRAY, STR_4, STRUCT)
+    }
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/basics/control_flow.html b/docs/beta-4/builds/sway/master/book/basics/control_flow.html new file mode 100644 index 000000000..f143c8c8b --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/basics/control_flow.html @@ -0,0 +1,338 @@ + + + + + + Control Flow - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Control Flow

+

if expressions

+ + +

Sway supports if, else, and else if expressions that allow you to branch your code depending on conditions.

+ +

For example:

+
fn main() {
+    let number = 6;
+
+    if number % 4 == 0 {
+        // do something
+    } else if number % 3 == 0 {
+        // do something else
+    } else {
+        // do something else
+    }
+}
+
+

Using if in a let statement

+

Like Rust, ifs are expressions in Sway. What this means is you can use if expressions on the right side of a let statement to assign the outcome to a variable.

+
let my_data = if some_bool < 10 { foo() } else { bar() };
+
+

Note that all branches of the if expression must return a value of the same type.

+

match expressions

+ + +

Sway supports advanced pattern matching through exhaustive match expressions. Unlike an if statement, a match expression asserts at compile time that all possible patterns have been matched. If you don't handle all the patterns, you will get compiler error indicating that your match expression is non-exhaustive.

+ +

The basic syntax of a match statement is as follows:

+
let result = match expression {
+    pattern1 => code_to_execute_if_expression_matches_pattern1,
+    pattern2 => code_to_execute_if_expression_matches_pattern2,
+    pattern3 | pattern4 => code_to_execute_if_expression_matches_pattern3_or_pattern4
+    ...
+    _ => code_to_execute_if_expression_matches_no_pattern,
+}
+
+

Some examples of how you can use a match statement:

+
script;
+
+// helper functions for our example
+fn on_even(num: u64) {
+    // do something with even numbers
+}
+fn on_odd(num: u64) {
+    // do something with odd numbers
+}
+
+fn main(num: u64) -> u64 {
+    // Match as an expression
+    let is_even = match num % 2 {
+        0 => true,
+        _ => false,
+    };
+
+    // Match as control flow
+    let x = 12;
+    match x {
+        5 => on_odd(x),
+        _ => on_even(x),
+    };
+
+    // Match an enum
+    enum Weather {
+        Sunny: (),
+        Rainy: (),
+        Cloudy: (),
+        Snowy: (),
+    }
+    let current_weather = Weather::Sunny;
+    let avg_temp = match current_weather {
+        Weather::Sunny => 80,
+        Weather::Rainy => 50,
+        Weather::Cloudy => 60,
+        Weather::Snowy => 20,
+    };
+
+    let is_sunny = match current_weather {
+        Weather::Sunny => true,
+        Weather::Rainy | Weather::Cloudy | Weather::Snowy => false,
+    };
+
+    // match expression used for a return
+    let outside_temp = Weather::Sunny;
+    match outside_temp {
+        Weather::Sunny => 80,
+        Weather::Rainy => 50,
+        Weather::Cloudy => 60,
+        Weather::Snowy => 20,
+    }
+}
+
+

Loops

+

while

+

Loops in Sway are currently limited to while loops. This is what they look like:

+
while counter < 10 {
+    counter = counter + 1;
+}
+
+

You need the while keyword, some condition (value < 10 in this case) which will be evaluated each iteration, and a block of code inside the curly braces ({...}) to execute each iteration.

+

break and continue

+

break and continue keywords are available to use inside the body of a while loop. The purpose of the break statement is to break out of a loop early:

+
fn break_example() -> u64 {
+    let mut counter = 1;
+    let mut sum = 0;
+    let num = 10;
+    while true {
+        if counter > num {
+            break;
+        }
+        sum += counter;
+        counter += 1;
+    }
+    sum // 1 + 2 + .. + 10 = 55
+}
+
+

The purpose of the continue statement is to skip a portion of a loop in an iteration and jump directly into the next iteration:

+
fn continue_example() -> u64 {
+    let mut counter = 0;
+    let mut sum = 0;
+    let num = 10;
+    while counter < num {
+        counter += 1;
+        if counter % 2 == 0 {
+            continue;
+        }
+        sum += counter;
+    }
+    sum // 1 + 3 + .. + 9 = 25
+}
+
+

Nested loops

+

You can also use nested while loops if needed:

+
while condition_1 == true {
+    // do stuff...
+    while condition_2 == true {
+        // do more stuff...
+    }
+}
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/basics/functions.html b/docs/beta-4/builds/sway/master/book/basics/functions.html new file mode 100644 index 000000000..3ea90d65c --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/basics/functions.html @@ -0,0 +1,258 @@ + + + + + + Functions - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Functions

+

Functions in Sway are declared with the fn keyword. Let's take a look:

+
fn equals(first_param: u64, second_param: u64) -> bool {
+    first_param == second_param
+}
+
+

We have just declared a function named equals which takes two parameters: first_param and second_param. The parameters must both be 64-bit unsigned integers.

+

This function also returns a bool value, i.e. either true or false. This function returns true if the two given parameters are equal, and false if they are not. If we want to use this function, we can do so like this:

+
fn main() {
+    equals(5, 5); // evaluates to `true`
+    equals(5, 6); // evaluates to `false`
+}
+
+

Mutable Parameters

+ + +

We can make a function parameter mutable by adding ref mut before the parameter name. This allows mutating the argument passed into the function when the function is called.

+ +

For example:

+
fn increment(ref mut num: u32) {
+    let prev = num;
+    num = prev + 1u32;
+}
+
+

This function is allowed to mutate its parameter num because of the mut keyword. In addition, the ref keyword instructs the function to modify the argument passed to it when the function is called, instead of modifying a local copy of it.

+
    let mut num: u32 = 0;
+    increment(num);
+    assert(num == 1u32); // The function `increment()` modifies `num`
+
+

Note that the variable num itself has to be declared as mutable for the above to compile.

+
+

Note +It is not currently allowed to use mut without ref or vice versa for a function parameter.

+
+

Similarly, ref mut can be used with more complex data types such as:

+
fn swap_tuple(ref mut pair: (u64, u64)) {
+    let temp = pair.0;
+    pair.0 = pair.1;
+    pair.1 = temp;
+}
+
+fn update_color(ref mut color: Color, new_color: Color) {
+    color = new_color;
+}
+
+

We can then call these functions as shown below:

+
    let mut tuple = (42, 24);
+    swap_tuple(tuple);
+    assert(tuple.0 == 24); // The function `swap_tuple()` modifies `tuple.0`
+    assert(tuple.1 == 42); // The function `swap_tuple()` modifies `tuple.1`
+    let mut color = Color::Red;
+    update_color(color, Color::Blue);
+    assert(match color {
+        Color::Blue => true,
+        _ => false,
+    }); // The function `update_color()` modifies the color to Blue
+
+
+

Note +The only place, in a Sway program, where the ref keyword is valid is before a mutable function parameter.

+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/basics/index.html b/docs/beta-4/builds/sway/master/book/basics/index.html new file mode 100644 index 000000000..b43848edf --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/basics/index.html @@ -0,0 +1,212 @@ + + + + + + Sway Language Basics - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Sway Language basics

+

Sway is a programming language designed for the FuelVM. It is a statically typed, compiled language with type inference and traits. Sway aims to make smart contract development safer and more performant through the use of strong static analysis and compiler feedback.

+

Get started with the basics of Sway:

+ + +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/basics/methods_and_associated_functions.html b/docs/beta-4/builds/sway/master/book/basics/methods_and_associated_functions.html new file mode 100644 index 000000000..675d19bb7 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/basics/methods_and_associated_functions.html @@ -0,0 +1,257 @@ + + + + + + Methods and Associated Functions - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Methods and Associated Functions

+ + +

Methods are similar to functions in that we declare them with the fn keyword and they have parameters and return a value. However, unlike functions, Methods are defined within the context of a struct (or enum), and either refers to that type or mutates it. The first parameter of a method is always self, which represents the instance of the struct the method is being called on.

+

Associated functions are very similar to methods, in that they are also defined in the context of a struct or enum, but they do not actually use any of the data in the struct and as a result do not take self as a parameter. Associated functions could be standalone functions, but they are included in a specific type for organizational or semantic reasons.

+

To declare methods and associated functions for a struct or enum, use an impl block. Here, impl stands for implementation.

+ +
script;
+
+struct Foo {
+    bar: u64,
+    baz: bool,
+}
+
+impl Foo {
+    // this is a _method_, as it takes `self` as a parameter.
+    fn is_baz_true(self) -> bool {
+        self.baz
+    }
+
+    // this is an _associated function_, since it does not take `self` as a parameter.
+    fn new_foo(number: u64, boolean: bool) -> Foo {
+        Foo {
+            bar: number,
+            baz: boolean,
+        }
+    }
+}
+
+fn main() {
+    let foo = Foo::new_foo(42, true);
+    assert(foo.is_baz_true());
+}
+
+ + +

To call a method, simply use dot syntax: foo.iz_baz_true().

+ + + +

Similarly to free functions, methods and associated functions may accept ref mut parameters.

+ +

For example:

+
struct Coordinates {
+    x: u64,
+    y: u64,
+}
+
+impl Coordinates {
+    fn move_right(ref mut self, distance: u64) {
+        self.x += distance;
+    }
+}
+
+

and when called:

+
    let mut point = Coordinates { x: 1, y: 1 };
+    point.move_right(5);
+    assert(point.x == 6);
+    assert(point.y == 1);
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/basics/structs_tuples_and_enums.html b/docs/beta-4/builds/sway/master/book/basics/structs_tuples_and_enums.html new file mode 100644 index 000000000..ccee591f1 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/basics/structs_tuples_and_enums.html @@ -0,0 +1,462 @@ + + + + + + Structs, Tuples, and Enums - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Structs, Tuples, and Enums

+

Structs

+ + +

Structs in Sway are a named grouping of types. You may also be familiar with structs via another name: product types. Sway does not make any significantly unique usages of structs; they are similar to most other languages which have structs. If you're coming from an object-oriented background, a struct is like the data attributes of an object.

+ +

Firstly, we declare a struct named Foo with two fields. The first field is named bar and it accepts values of type u64, the second field is named baz and it accepts bool values.

+
library;
+
+// Declare a struct type
+pub struct Foo {
+    bar: u64,
+    baz: bool,
+}
+
+// Struct types for destructuring
+pub struct Point {
+    x: u64,
+    y: u64,
+}
+
+pub struct Line {
+    p1: Point,
+    p2: Point,
+}
+
+pub struct TupleInStruct {
+    nested_tuple: (u64, (u32, (bool, str))),
+}
+
+ + +

In order to instantiate the struct we use struct instantiation syntax, which is very similar to the declaration syntax except with expressions in place of types.

+

There are three ways to instantiate the struct.

+
    +
  • Hardcoding values for the fields
  • +
  • Passing in variables with names different than the struct fields
  • +
  • Using a shorthand notation via variables that are the same as the field names
  • +
+ +
library;
+
+mod data_structures;
+use data_structures::{Foo, Line, Point, TupleInStruct};
+
+fn hardcoded_instantiation() -> Foo {
+    // Instantiate `foo` as `Foo`
+    let mut foo = Foo {
+        bar: 42,
+        baz: false,
+    };
+
+    // Access and write to "baz"
+    foo.baz = true;
+
+    // Return the struct
+    foo
+}
+
+fn variable_instantiation() -> Foo {
+    // Declare variables with the same names as the fields in `Foo`
+    let number = 42;
+    let truthness = false;
+
+    // Instantiate `foo` as `Foo`
+    let mut foo = Foo {
+        bar: number,
+        baz: truthness,
+    };
+
+    // Access and write to "baz"
+    foo.baz = true;
+
+    // Return the struct
+    foo
+}
+
+fn shorthand_instantiation() -> Foo {
+    // Declare variables with the same names as the fields in `Foo`
+    let bar = 42;
+    let baz = false;
+
+    // Instantiate `foo` as `Foo`
+    let mut foo = Foo { bar, baz };
+
+    // Access and write to "baz"
+    foo.baz = true;
+
+    // Return the struct
+    foo
+}
+
+fn struct_destructuring() {
+    let point1 = Point { x: 0, y: 0 };
+    // Destructure the values from the struct into variables
+    let Point { x, y } = point1;
+
+    let point2 = Point { x: 1, y: 1 };
+    // If you do not care about specific struct fields then use ".." at the end of your variable list
+    let Point { x, .. } = point2;
+
+    let line = Line {
+        p1: point1,
+        p2: point2,
+    };
+    // Destructure the values from the nested structs into variables
+    let Line {
+        p1: Point { x: x0, y: y0 },
+        p2: Point { x: x1, y: y1 },
+    } = line;
+    // You may also destructure tuples nested in structs and structs nested in tuples
+    let tuple_in_struct = TupleInStruct {
+        nested_tuple: (42u64, (42u32, (true, "ok"))),
+    };
+    let TupleInStruct {
+        nested_tuple: (a, (b, (c, d))),
+    } = tuple_in_struct;
+
+    let struct_in_tuple = (Point { x: 2, y: 4 }, Point { x: 3, y: 6 });
+    let (Point { x: x0, y: y0 }, Point { x: x1, y: y1 }) = struct_in_tuple;
+}
+
+
+

Note +You can mix and match all 3 ways to instantiate the struct at the same time. +Moreover, the order of the fields does not matter when instantiating however we encourage declaring the fields in alphabetical order and instantiating them in the same alphabetical order

+
+

Furthermore, multiple variables can be extracted from a struct using the destructuring syntax.

+

Struct Memory Layout

+
+

Note +This information is not vital if you are new to the language, or programming in general

+
+

Structs have zero memory overhead. What that means is that in memory, each struct field is laid out sequentially. No metadata regarding the struct's name or other properties is preserved at runtime. In other words, structs are compile-time constructs. This is the same in Rust, but different in other languages with runtimes like Java.

+

Tuples

+ + +

Tuples are a basic static-length type which contain multiple different types within themselves. The type of a tuple is defined by the types of the values within it, and a tuple can contain basic types as well as structs and enums.

+

You can access values directly by using the . syntax. Moreover, multiple variables can be extracted from a tuple using the destructuring syntax.

+ +
library;
+
+fn tuple() {
+    // You can declare the types youself
+    let tuple1: (u8, bool, u64) = (100, false, 10000);
+
+    // Or have the types be inferred
+    let mut tuple2 = (5, true, ("Sway", 8));
+
+    // Retrieve values from tuples
+    let number = tuple1.0;
+    let sway = tuple2.2.1;
+
+    // Destructure the values from the tuple into variables
+    let (n1, truthness, n2) = tuple1;
+
+    // If you do not care about specific values then use "_"
+    let (_, truthness, _) = tuple2;
+
+    // Internally mutate the tuple
+    tuple2.1 = false;
+
+    // Or change the values all at once (must keep the same data types)
+    tuple2 = (9, false, ("Fuel", 99));
+}
+
+

Enums

+ + +

Enumerations, or enums, are also known as sum types. An enum is a type that could be one of several variants. To declare an enum, you enumerate all potential variants.

+ +

Here, we have defined five potential colors. Each enum variant is just the color name. As there is no extra data associated with each variant, we say that each variant is of type (), or unit.

+
library;
+
+// Declare the enum
+enum Color {
+    Blue: (),
+    Green: (),
+    Red: (),
+    Silver: (),
+    Grey: (),
+}
+
+fn main() {
+    // To instantiate a variable with the value of an enum the syntax is
+    let blue = Color::Blue;
+    let silver = Color::Silver;
+}
+
+

Enums of Structs

+

It is also possible to have an enum variant contain extra data. Take a look at this more substantial example, which combines struct declarations with enum variants:

+
library;
+
+struct Item {
+    price: u64,
+    amount: u64,
+    id: u64,
+}
+
+enum MyEnum {
+    Item: Item,
+}
+
+fn main() {
+    let my_enum = MyEnum::Item(Item {
+        price: 5,
+        amount: 2,
+        id: 42,
+    });
+}
+
+

Enums of Enums

+

It is possible to define enums of enums:

+
library;
+
+pub enum Error {
+    StateError: StateError,
+    UserError: UserError,
+}
+
+pub enum StateError {
+    Void: (),
+    Pending: (),
+    Completed: (),
+}
+
+pub enum UserError {
+    InsufficientPermissions: (),
+    Unauthorized: (),
+}
+
+

Preferred usage

+

The preferred way to use enums is to use the individual (not nested) enums directly because they are easy to follow and the lines are short:

+
library;
+
+use ::enum_of_enums::{StateError, UserError};
+
+fn preferred() {
+    let error1 = StateError::Void;
+    let error2 = UserError::Unauthorized;
+}
+
+

Inadvisable

+

If you wish to use the nested form of enums via the Error enum from the example above, then you can instantiate them into variables using the following syntax:

+
library;
+
+use ::enum_of_enums::{Error, StateError, UserError};
+
+fn avoid() {
+    let error1 = Error::StateError(StateError::Void);
+    let error2 = Error::UserError(UserError::Unauthorized);
+}
+
+

Key points to note:

+
    +
  • You must import all of the enums you need instead of just the Error enum
  • +
  • The lines may get unnecessarily long (depending on the names)
  • +
  • The syntax is not the most ergonomic
  • +
+

Enum Memory Layout

+
+

Note +This information is not vital if you are new to the language, or programming in general.

+
+

Enums do have some memory overhead. To know which variant is being represented, Sway stores a one-word (8-byte) tag for the enum variant. The space reserved after the tag is equivalent to the size of the largest enum variant. So, to calculate the size of an enum in memory, add 8 bytes to the size of the largest variant. For example, in the case of Color above, where the variants are all (), the size would be 8 bytes since the size of the largest variant is 0 bytes.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/basics/variables.html b/docs/beta-4/builds/sway/master/book/basics/variables.html new file mode 100644 index 000000000..075dea567 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/basics/variables.html @@ -0,0 +1,235 @@ + + + + + + Variables - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Variables

+ + +

Variables in Sway are immutable by default. This means that, by default, once a variable is declared, its value cannot change. This is one of the ways how Sway encourages safe programming, and many modern languages have this same default.

+ +

Let's take a look at variables in detail.

+

Declaring a Variable

+

Let's look at a variable declaration:

+
let foo = 5;
+
+

Great! We have just declared a variable, foo. What do we know about foo?

+
    +
  1. It is immutable.
  2. +
  3. Its value is 5.
  4. +
  5. Its type is u64, a 64-bit unsigned integer.
  6. +
+

u64 is the default numeric type, and represents a 64-bit unsigned integer. See the section Built-in Types for more details.

+

We can also make a mutable variable. Let's take a look:

+
let mut foo = 5;
+foo = 6;
+
+

Now, foo is mutable, and the reassignment to the number 6 is valid. That is, we are allowed to mutate the variable foo to change its value.

+

Type Annotations

+ + +

A variable declaration can contain a type annotation. A type annotation serves the purpose of declaring the type, in addition to the value, of a variable.

+ +

Let's take a look:

+
let foo: u32 = 5;
+
+

We have just declared the type of the variable foo as a u32, which is an unsigned 32-bit integer. Let's take a look at a few other type annotations:

+
let bar: str[4] = __to_str_array("sway");
+let baz: bool = true;
+
+ + +

If the value declared cannot be assigned to the declared type, there will be an error generated by the compiler.

+ + +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/blockchain-development/access_control.html b/docs/beta-4/builds/sway/master/book/blockchain-development/access_control.html new file mode 100644 index 000000000..dbb108355 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/blockchain-development/access_control.html @@ -0,0 +1,281 @@ + + + + + + Access Control - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Access Control

+ + +

Smart contracts require the ability to restrict access to and identify certain users or contracts. Unlike account-based blockchains, transactions in UTXO-based blockchains (i.e. Fuel) do not necessarily have a unique transaction sender. Additional logic is needed to handle this difference, and is provided by the standard library.

+ +

msg_sender

+ + +

To deliver an experience akin to the EVM's access control, the std library provides a msg_sender function, which identifies a unique caller based upon the call and/or transaction input data.

+ +
contract;
+
+abi MyOwnedContract {
+    fn receive(field_1: u64) -> bool;
+}
+
+const OWNER = Address::from(0x9ae5b658754e096e4d681c548daf46354495a437cc61492599e33fc64dcdc30c);
+
+impl MyOwnedContract for Contract {
+    fn receive(field_1: u64) -> bool {
+        let sender = msg_sender().unwrap();
+        if let Identity::Address(addr) = sender {
+            assert(addr == OWNER);
+        } else {
+            revert(0);
+        }
+
+        true
+    }
+}
+
+ + +

The msg_sender function works as follows:

+
    +
  • If the caller is a contract, then Ok(Sender) is returned with the ContractId sender variant.
  • +
  • If the caller is external (i.e. from a script), then all coin input owners in the transaction are checked. If all owners are the same, then Ok(Sender) is returned with the Address sender variant.
  • +
  • If the caller is external and coin input owners are different, then the caller cannot be determined and a Err(AuthError) is returned.
  • +
+ +

Contract Ownership

+

Many contracts require some form of ownership for access control. The SRC-5 Ownership Standard has been defined to provide a interoperable interface for ownership within contracts.

+

To accomplish this, use the Ownerhsip Library to keep track of the owner. This allows setting and revoking ownership using the variants Some(..) and None respectively. This is better, safer, and more readable than using the Identity type directly where revoking ownership has to be done using some magic value such as std::constants::ZERO_B256 or otherwise.

+
    +
  • The following is an example of how to properly lock a function such that only the owner may call a function:
  • +
+
    #[storage(read)]
+    fn only_owner() {
+        storage.owner.only_owner();
+        // Do stuff here
+    }
+
+

Setting ownership can be done in one of two ways; During compile time or run time.

+
    +
  • The following is an example of how to properly set ownership of a contract during compile time:
  • +
+
storage {
+    owner: Ownership = Ownership::initialized(Identity::Address(Address::from(ZERO_B256))),
+}
+
+
    +
  • The following is an example of how to properly set ownership of a contract during run time:
  • +
+
    #[storage(write)]
+    fn set_owner(identity: Identity) {
+        storage.owner.set_ownership(identity);
+    }
+
+
    +
  • The following is an example of how to properly revoke ownership of a contract:
  • +
+
    #[storage(write)]
+    fn revoke_ownership() {
+        storage.owner.renounce_ownership();
+    }
+
+
    +
  • The following is an example of how to properly retrieve the state of ownership:
  • +
+
    #[storage(read)]
+    fn owner() -> State {
+        storage.owner.owner()
+    }
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/blockchain-development/calling_contracts.html b/docs/beta-4/builds/sway/master/book/blockchain-development/calling_contracts.html new file mode 100644 index 000000000..81ff613de --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/blockchain-development/calling_contracts.html @@ -0,0 +1,369 @@ + + + + + + Calling Contracts - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Calling Contracts

+

Smart contracts can be called by other contracts or scripts. In the FuelVM, this is done primarily with the call instruction.

+

Sway provides a nice way to manage callable interfaces with its abi system. The Fuel ABI specification can be found here.

+

Example

+

Here is an example of a contract calling another contract in Sway. A script can call a contract in the same way.

+
// ./contract_a.sw
+contract;
+
+abi ContractA {
+    fn receive(field_1: bool, field_2: u64) -> u64;
+}
+
+impl ContractA for Contract {
+    fn receive(field_1: bool, field_2: u64) -> u64 {
+        assert(field_1 == true);
+        assert(field_2 > 0);
+        return_45()
+    }
+}
+
+fn return_45() -> u64 {
+  45
+}
+
+
// ./contract_b.sw
+contract;
+
+use contract_a::ContractA;
+
+abi ContractB {
+    fn make_call();
+}
+
+const contract_id = 0x79fa8779bed2f36c3581d01c79df8da45eee09fac1fd76a5a656e16326317ef0;
+
+impl ContractB for Contract {
+    fn make_call() {
+      let x = abi(ContractA, contract_id);
+      let return_value = x.receive(true, 3); // will be 45
+    }
+}
+
+
+

Note: The ABI is for external calls only therefore you cannot define a method in the ABI and call it in the same contract. If you want to define a function for a contract, but keep it private so that only your contract can call it, you can define it outside of the impl and call it inside the contract, similar to the return_45() function above.

+
+

Advanced Calls

+

All calls forward a gas stipend, and may additionally forward one native asset with the call.

+

Here is an example of how to specify the amount of gas (gas), the asset ID of the native asset (asset_id), and the amount of the native asset (coins) to forward:

+
script;
+
+abi MyContract {
+    fn foo(field_1: bool, field_2: u64);
+}
+
+fn main() {
+    let x = abi(MyContract, 0x79fa8779bed2f36c3581d01c79df8da45eee09fac1fd76a5a656e16326317ef0);
+    let asset_id = 0x7777_7777_7777_7777_7777_7777_7777_7777_7777_7777_7777_7777_7777_7777_7777_7777;
+    x.foo {
+        gas: 5000, asset_id: asset_id, coins: 5000
+    }
+    (true, 3);
+}
+
+

Handling Re-entrancy

+

A common attack vector for smart contracts is re-entrancy. Similar to the EVM, the FuelVM allows for re-entrancy.

+

A stateless re-entrancy guard is included in the sway-libs library. The guard will panic (revert) at run time if re-entrancy is detected.

+
contract;
+
+use reentrancy::reentrancy_guard;
+
+abi MyContract {
+    fn some_method();
+}
+
+impl ContractB for Contract {
+    fn some_method() {
+        reentrancy_guard();
+        // do something
+    }
+}
+
+

CEI pattern violation static analysis

+

Another way of avoiding re-entrancy-related attacks is to follow the so-called +CEI pattern. CEI stands for "Checks, Effects, Interactions", meaning that the +contract code should first perform safety checks, also known as +"pre-conditions", then perform effects, i.e. modify or read the contract storage +and execute external contract calls (interaction) only at the very end of the +function/method.

+

Please see this blog post +for more detail on some vulnerabilities in case of storage modification after +interaction and this blog post for +more information on storage reads after interaction.

+

The Sway compiler implements a check that the CEI pattern is not violated in the +user contract and issues warnings if that's the case.

+

For example, in the following contract the CEI pattern is violated, because an +external contract call is executed before a storage write.

+
contract;
+
+mod other_contract;
+
+use other_contract::*;
+use std::hash::*;
+
+abi MyContract {
+    #[storage(read, write)]
+    fn withdraw(external_contract_id: ContractId);
+}
+
+storage {
+    balances: StorageMap<Identity, u64> = StorageMap::<Identity, u64> {},
+}
+
+impl MyContract for Contract {
+    #[storage(read, write)]
+    fn withdraw(external_contract_id: ContractId) {
+        let sender = msg_sender().unwrap();
+        let bal = storage.balances.get(sender).try_read().unwrap_or(0);
+
+        assert(bal > 0);
+
+        // External call
+        let caller = abi(OtherContract, external_contract_id.into());
+        caller.external_call { coins: bal }();
+
+        // Storage update _after_ external call
+        storage.balances.insert(sender, 0);
+    }
+}
+
+

Here, other_contract is defined as follows:

+
library;
+
+abi OtherContract {
+    #[payable]
+    fn external_call();
+}
+
+

The CEI pattern analyzer issues a warning as follows, pointing to the +interaction before a storage modification:

+
warning
+  --> /path/to/contract/main.sw:28:9
+   |
+26 |
+27 |           let caller = abi(OtherContract, external_contract_id.into());
+28 |           caller.external_call { coins: bal }();
+   |  _________-
+29 | |
+30 | |         // Storage update _after_ external call
+31 | |         storage.balances.insert(sender, 0);
+   | |__________________________________________- Storage write after external contract interaction in function or method "withdraw". Consider making all storage writes before calling another contract
+32 |       }
+33 |   }
+   |
+____
+
+

In case there is a storage read after an interaction, the CEI analyzer will issue a similar warning.

+

In addition to storage reads and writes after an interaction, the CEI analyzer reports analogous warnings about:

+
    +
  • balance tree updates, i.e. balance tree reads with subsequent writes, which may be produced by the tr and tro asm instructions or library functions using them under the hood;
  • +
  • balance trees reads with bal instruction;
  • +
  • changes to the output messages that can be produced by the __smo intrinsic function or the smo asm instruction.
  • +
+

Differences from the EVM

+

While the Fuel contract calling paradigm is similar to the EVM's (using an ABI, forwarding gas and data), it differs in two key ways:

+
    +
  1. +

    Native assets: FuelVM calls can forward any native asset not just base asset.

    +
  2. +
  3. +

    No data serialization: Contract calls in the FuelVM do not need to serialize data to pass it between contracts; instead they simply pass a pointer to the data. This is because the FuelVM has a shared global memory which all call frames can read from.

    +
  4. +
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/blockchain-development/hashing_and_cryptography.html b/docs/beta-4/builds/sway/master/book/blockchain-development/hashing_and_cryptography.html new file mode 100644 index 000000000..e1033930f --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/blockchain-development/hashing_and_cryptography.html @@ -0,0 +1,392 @@ + + + + + + Hashing and Cryptography - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Hashing and Cryptography

+

The Sway standard library provides easy access to a selection of cryptographic hash functions (sha256 and EVM-compatible keccak256), and EVM-compatible secp256k1-based signature recovery operations.

+

Hashing

+
script;
+
+use std::hash::*;
+
+impl Hash for Location {
+    fn hash(self, ref mut state: Hasher) {
+        match self {
+            Location::Earth => {
+                0_u8.hash(state);
+            }
+            Location::Mars => {
+                1_u8.hash(state);
+            }
+        }
+    }
+}
+
+impl Hash for Stats {
+    fn hash(self, ref mut state: Hasher) {
+        self.strength.hash(state);
+        self.agility.hash(state);
+    }
+}
+
+impl Hash for Person {
+    fn hash(self, ref mut state: Hasher) {
+        self.name.hash(state);
+        self.age.hash(state);
+        self.alive.hash(state);
+        self.location.hash(state);
+        self.stats.hash(state);
+        self.some_tuple.hash(state);
+        self.some_array.hash(state);
+        self.some_b256.hash(state);
+    }
+}
+
+const VALUE_A = 0x9280359a3b96819889d30614068715d634ad0cf9bba70c0f430a8c201138f79f;
+
+enum Location {
+    Earth: (),
+    Mars: (),
+}
+
+struct Person {
+    name: str,
+    age: u64,
+    alive: bool,
+    location: Location,
+    stats: Stats,
+    some_tuple: (bool, u64),
+    some_array: [u64; 2],
+    some_b256: b256,
+}
+
+struct Stats {
+    strength: u64,
+    agility: u64,
+}
+
+fn main() {
+    let zero = b256::min();
+    // Use the generic sha256 to hash some integers
+    let sha_hashed_u8 = sha256(u8::max());
+    let sha_hashed_u16 = sha256(u16::max());
+    let sha_hashed_u32 = sha256(u32::max());
+    let sha_hashed_u64 = sha256(u64::max());
+
+    // Or hash a b256
+    let sha_hashed_b256 = sha256(VALUE_A);
+
+    // You can hash booleans too
+    let sha_hashed_bool = sha256(true);
+
+    // Strings are not a problem either
+    let sha_hashed_str = sha256("Fastest Modular Execution Layer!");
+
+    // Tuples of any size work too
+    let sha_hashed_tuple = sha256((true, 7));
+
+    // As do arrays
+    let sha_hashed_array = sha256([4, 5, 6]);
+
+    // Enums work too
+    let sha_hashed_enum = sha256(Location::Earth);
+
+    // Complex structs are not a problem
+    let sha_hashed_struct = sha256(Person {
+        name: "John",
+        age: 9000,
+        alive: true,
+        location: Location::Mars,
+        stats: Stats {
+            strength: 10,
+            agility: 9,
+        },
+        some_tuple: (true, 8),
+        some_array: [17, 76],
+        some_b256: zero,
+    });
+
+    log(sha_hashed_u8);
+    log(sha_hashed_u16);
+    log(sha_hashed_u32);
+    log(sha_hashed_u64);
+    log(sha_hashed_b256);
+    log(sha_hashed_bool);
+    log(sha_hashed_str);
+    log(sha_hashed_tuple);
+    log(sha_hashed_array);
+    log(sha_hashed_enum);
+    log(sha_hashed_struct);
+
+    // Use the generic keccak256 to hash some integers
+    let keccak_hashed_u8 = keccak256(u8::max());
+    let keccak_hashed_u16 = keccak256(u16::max());
+    let keccak_hashed_u32 = keccak256(u32::max());
+    let keccak_hashed_u64 = keccak256(u64::max());
+
+    // Or hash a b256
+    let keccak_hashed_b256 = keccak256(VALUE_A);
+
+    // You can hash booleans too
+    let keccak_hashed_bool = keccak256(true);
+
+    // Strings are not a problem either
+    let keccak_hashed_str = keccak256("Fastest Modular Execution Layer!");
+
+    // Tuples of any size work too
+    let keccak_hashed_tuple = keccak256((true, 7));
+
+    // As do arrays
+    let keccak_hashed_array = keccak256([4, 5, 6]);
+
+    // Enums work too
+    let keccak_hashed_enum = keccak256(Location::Earth);
+
+    // Complex structs are not a problem
+    let keccak_hashed_struct = keccak256(Person {
+        name: "John",
+        age: 9000,
+        alive: true,
+        location: Location::Mars,
+        stats: Stats {
+            strength: 10,
+            agility: 9,
+        },
+        some_tuple: (true, 8),
+        some_array: [17, 76],
+        some_b256: zero,
+    });
+
+    log(keccak_hashed_u8);
+    log(keccak_hashed_u16);
+    log(keccak_hashed_u32);
+    log(keccak_hashed_u64);
+    log(keccak_hashed_b256);
+    log(keccak_hashed_bool);
+    log(keccak_hashed_str);
+    log(keccak_hashed_tuple);
+    log(keccak_hashed_array);
+    log(keccak_hashed_enum);
+    log(keccak_hashed_struct);
+}
+
+

Signature Recovery

+
script;
+
+use std::{b512::B512, ecr::{ec_recover, ec_recover_address, EcRecoverError}};
+
+const MSG_HASH = 0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323;
+
+fn main() {
+    let hi = 0xbd0c9b8792876713afa8bff383eebf31c43437823ed761cc3600d0016de5110c;
+    let lo = 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d;
+    let signature: B512 = B512::from((hi, lo));
+
+    // A recovered public key pair.
+    let public_key = ec_recover(signature, MSG_HASH);
+
+    // A recovered Fuel address.
+    let result_address: Result<Address, EcRecoverError> = ec_recover_address(signature, MSG_HASH);
+    if let Ok(address) = result_address {
+        log(address.value);
+    } else {
+        revert(0);
+    }
+}
+
+
+

Note: Recovery of EVM addresses is also supported via std::vm::evm.

+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/blockchain-development/identifiers.html b/docs/beta-4/builds/sway/master/book/blockchain-development/identifiers.html new file mode 100644 index 000000000..ab8101def --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/blockchain-development/identifiers.html @@ -0,0 +1,204 @@ + + + + + + Identifiers - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Identifiers

+

Addresses in Sway are similar to EVM addresses. The two major differences are:

+
    +
  1. Sway addresses are 32 bytes long (instead of 20)
  2. +
  3. Sway addresses are computed with the SHA-256 hash of the public key instead of the keccak-256 hash.
  4. +
+

Contracts, on the other hand, are uniquely identified with a contract ID rather than an address. A contract's ID is also 32 bytes long and is calculated here.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/blockchain-development/index.html b/docs/beta-4/builds/sway/master/book/blockchain-development/index.html new file mode 100644 index 000000000..ef30e90a3 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/blockchain-development/index.html @@ -0,0 +1,209 @@ + + + + + + Blockchain Development with Sway - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Blockchain Development with Sway

+

Sway is fundamentally a blockchain language. Because of this, it has some features and requirements that you may not have seen in general-purpose programming languages.

+

These are also some concepts related to the FuelVM and Fuel ecosystem that you may utilize when writing Sway.

+ + +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/blockchain-development/native_assets.html b/docs/beta-4/builds/sway/master/book/blockchain-development/native_assets.html new file mode 100644 index 000000000..0fba6866b --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/blockchain-development/native_assets.html @@ -0,0 +1,318 @@ + + + + + + Native Assets - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Native Support for Multiple Asset Types

+ + +

The FuelVM has built-in support for working with multiple assets.

+

What does this mean in practice?

+

As in the EVM, sending ETH to an address or contract is an operation built into the FuelVM, meaning it doesn't rely on the existence of some token smart contract to update balances to track ownership.

+

However, unlike the EVM, the process for sending any native asset is the same. This means that while you would still need a smart contract to handle the minting and burning of fungible tokens, the sending and receiving of these tokens can be done independently of the token contract.

+ +

Liquidity Pool Example

+

All contracts in Fuel can mint and burn their own native token. Contracts can also receive and transfer any native asset including their own. Internal balances of all native assets pushed through calls or minted by the contract are tracked by the FuelVM and can be queried at any point using the balance_of function from the std library. Therefore, there is no need for any manual accounting of the contract's balances using persistent storage.

+

The std library provides handy methods for accessing Fuel's native assset operations.

+

In this example, we show a basic liquidity pool contract minting its own native asset LP token.

+
contract;
+
+use std::{
+    call_frames::{
+        contract_id,
+        msg_asset_id,
+    },
+    constants::ZERO_B256,
+    context::msg_amount,
+    hash::*,
+    token::{
+        mint_to_address,
+        transfer_to_address,
+    },
+};
+
+abi LiquidityPool {
+    fn deposit(recipient: Address);
+    fn withdraw(recipient: Address);
+}
+
+const BASE_TOKEN: AssetId = AssetId {
+    value: 0x9ae5b658754e096e4d681c548daf46354495a437cc61492599e33fc64dcdc30c,
+};
+
+impl LiquidityPool for Contract {
+    fn deposit(recipient: Address) {
+        assert(msg_asset_id() == BASE_TOKEN);
+        assert(msg_amount() > 0);
+
+        // Mint two times the amount.
+        let amount_to_mint = msg_amount() * 2;
+
+        // Mint some LP token based upon the amount of the base token.
+        mint_to_address(recipient, ZERO_B256, amount_to_mint);
+    }
+
+    fn withdraw(recipient: Address) {
+        let asset_id = AssetId::default(contract_id());
+        assert(msg_asset_id() == asset_id);
+        assert(msg_amount() > 0);
+
+        // Amount to withdraw.
+        let amount_to_transfer = msg_amount() / 2;
+
+        // Transfer base token to recipient.
+        transfer_to_address(recipient, BASE_TOKEN, amount_to_transfer);
+    }
+}
+
+

Native Token Example

+

In this example, we show a native token contract with more minting, burning and transferring capabilities.

+
contract;
+
+use std::{constants::ZERO_B256, context::*, token::*};
+
+abi NativeAssetToken {
+    fn mint_coins(mint_amount: u64);
+    fn burn_coins(burn_amount: u64);
+    fn force_transfer_coins(coins: u64, asset_id: AssetId, target: ContractId);
+    fn transfer_coins_to_output(coins: u64, asset_id: AssetId, recipient: Address);
+    fn deposit();
+    fn get_balance(target: ContractId, asset_id: AssetId) -> u64;
+    fn mint_and_send_to_contract(amount: u64, destination: ContractId);
+    fn mint_and_send_to_address(amount: u64, recipient: Address);
+}
+
+impl NativeAssetToken for Contract {
+    /// Mint an amount of this contracts native asset to the contracts balance.
+    fn mint_coins(mint_amount: u64) {
+        mint(ZERO_B256, mint_amount);
+    }
+
+    /// Burn an amount of this contracts native asset.
+    fn burn_coins(burn_amount: u64) {
+        burn(ZERO_B256, burn_amount);
+    }
+
+    /// Transfer coins to a target contract.
+    fn force_transfer_coins(coins: u64, asset_id: AssetId, target: ContractId) {
+        force_transfer_to_contract(target, asset_id, coins);
+    }
+
+    /// Transfer coins to a transaction output to be spent later.
+    fn transfer_coins_to_output(coins: u64, asset_id: AssetId, recipient: Address) {
+        transfer_to_address(recipient, asset_id, coins);
+    }
+
+    /// Get the internal balance of a specific coin at a specific contract.
+    fn get_balance(target: ContractId, asset_id: AssetId) -> u64 {
+        balance_of(target, asset_id)
+    }
+
+    /// Deposit tokens back into the contract.
+    fn deposit() {
+        assert(msg_amount() > 0);
+    }
+
+    /// Mint and send this contracts native token to a destination contract.
+    fn mint_and_send_to_contract(amount: u64, destination: ContractId) {
+        mint_to_contract(destination, ZERO_B256, amount);
+    }
+
+    /// Mind and send this contracts native token to a destination address.
+    fn mint_and_send_to_address(amount: u64, recipient: Address) {
+        mint_to_address(recipient, ZERO_B256, amount);
+    }
+}
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/blockchain-development/purity.html b/docs/beta-4/builds/sway/master/book/blockchain-development/purity.html new file mode 100644 index 000000000..a868fac17 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/blockchain-development/purity.html @@ -0,0 +1,226 @@ + + + + + + Function Purity - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Purity

+ + +

A function is pure if it does not access any persistent storage. Conversely, the function is impure if it does access any storage. Naturally, as storage is only available in smart contracts, impure functions cannot be used in predicates, scripts, or libraries. A pure function cannot call an impure function.

+

In Sway, functions are pure by default but can be opted into impurity via the storage function attribute. The storage attribute may take read and/or write arguments indicating which type of access the function requires.

+ +
#[storage(read)]
+fn get_amount() -> u64 {
+    ...
+}
+
+#[storage(read, write)]
+fn increment_amount(increment: u64) -> u64 {
+    ...
+}
+
+
+

Note: the #[storage(write)] attribute also permits a function to read from storage. This is due to the fact that partially writing a storage slot requires first reading the slot.

+
+ + +

Impure functions which call other impure functions must have at least the same storage privileges or a superset of those for the function called. For example, to call a function with write access a caller must also have write access, or both read and write access. To call a function with read and write access the caller must also have both privileges.

+ +

The storage attribute may also be applied to methods and associated functions, trait and ABI declarations.

+ + +

A pure function gives you some guarantees: you will not incur excessive storage gas costs, the compiler can apply additional optimizations, and they are generally easy to reason about and audit.

+ +

A similar concept exists in Solidity. Note that Solidity refers to contract storage as contract state, and in the Sway/Fuel ecosystem, these two terms are largely interchangeable.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/blockchain-development/storage.html b/docs/beta-4/builds/sway/master/book/blockchain-development/storage.html new file mode 100644 index 000000000..a9dcafba7 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/blockchain-development/storage.html @@ -0,0 +1,279 @@ + + + + + + Contract Storage - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Storage

+ + +

When developing a smart contract, you will typically need some sort of persistent storage. In this case, persistent storage, often just called storage in this context, is a place where you can store values that are persisted inside the contract itself. This is in contrast to a regular value in memory, which disappears after the contract exits.

+

Put in conventional programming terms, contract storage is like saving data to a hard drive. That data is saved even after the program which saved it exits. That data is persistent. Using memory is like declaring a variable in a program: it exists for the duration of the program and is non-persistent.

+

Some basic use cases of storage include declaring an owner address for a contract and saving balances in a wallet.

+ +

Storage Accesses Via the storage Keyword

+

Declaring variables in storage requires a storage declaration that contains a list of all your variables, their types, and their initial values as follows:

+
struct Type1 {
+    x: u64,
+    y: u64,
+}
+
+struct Type2 {
+    w: b256,
+    z: bool,
+}
+
+storage {
+    var1: Type1 = Type1 { x: 0, y: 0 },
+    var2: Type2 = Type2 {
+        w: 0x0000000000000000000000000000000000000000000000000000000000000000,
+        z: false,
+    },
+}
+
+
+

To write into a storage variable, you need to use the storage keyword as follows:

+
    #[storage(write)]
+    fn store_something() {
+        storage.var1.x.write(42);
+        storage.var1.y.write(77);
+        storage.var2.w.write(0x1111111111111111111111111111111111111111111111111111111111111111);
+        storage.var2.z.write(true);
+    }
+
+

To read a storage variable, you also need to use the storage keyword as follows:

+
    #[storage(read)]
+    fn get_something() -> (u64, u64, b256, bool) {
+        (
+            storage.var1.x.try_read().unwrap_or(0),
+            storage.var1.y.try_read().unwrap_or(0),
+            storage.var2.w.try_read().unwrap_or(0x0000000000000000000000000000000000000000000000000000000000000000),
+            storage.var2.z.try_read().unwrap_or(false),
+        )
+    }
+
+

Storage Maps

+

Generic storage maps are available in the standard library as StorageMap<K, V> which have to be defined inside a storage block and allow you to call insert() and get() to insert values at specific keys and get those values respectively. Refer to Storage Maps for more information about StorageMap<K, V>.

+

Manual Storage Management

+

It is possible to leverage FuelVM storage operations directly using the std::storage::storage_api::write and std::storage::storage_api::read functions provided in the standard library. With this approach you will have to manually assign the internal key used for storage. An example is as follows:

+
contract;
+
+use std::storage::storage_api::{read, write};
+
+abi StorageExample {
+    #[storage(write)]
+    fn store_something(amount: u64);
+
+    #[storage(read)]
+    fn get_something() -> u64;
+}
+
+const STORAGE_KEY: b256 = 0x0000000000000000000000000000000000000000000000000000000000000000;
+
+impl StorageExample for Contract {
+    #[storage(write)]
+    fn store_something(amount: u64) {
+        write(STORAGE_KEY, 0, amount);
+    }
+
+    #[storage(read)]
+    fn get_something() -> u64 {
+        let value: Option<u64> = read::<u64>(STORAGE_KEY, 0);
+        value.unwrap_or(0)
+    }
+}
+
+
+

Note: Though these functions can be used for any data type, they should mostly be used for arrays because arrays are not yet supported in storage blocks. Note, however, that all data types can be used as types for keys and/or values in StorageMap<K, V> without any restrictions.

+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/common-collections/index.html b/docs/beta-4/builds/sway/master/book/common-collections/index.html new file mode 100644 index 000000000..0bd30f4d6 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/common-collections/index.html @@ -0,0 +1,208 @@ + + + + + + Common Collections - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Common Collections

+

Sway’s standard library includes a number of very useful data structures called collections. Most other data types represent one specific value, but collections can contain multiple values. Unlike the built-in array and tuple types which are allocated on the "stack" and cannot grow in size, the data these collections point to is stored either on the "heap" or in contract "storage", which means the amount of data does not need to be known at compile time and can grow as the program runs. Each kind of collection has different capabilities and costs, and choosing an appropriate one for your current situation is a skill you’ll develop over time. In this chapter, we’ll discuss three collections that are used very often in Sway programs:

+

A vector on the heap allows you to store a variable number of values next to each other.

+

A storage vector is similar to a vector on the heap but uses persistent storage.

+

A storage map allows you to associate a value with a particular key.

+

We’ll discuss how to create and update vectors, storage vectors, and storage maps, as well as what makes each special.

+ + +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/common-collections/storage_map.html b/docs/beta-4/builds/sway/master/book/common-collections/storage_map.html new file mode 100644 index 000000000..94ec1ef96 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/common-collections/storage_map.html @@ -0,0 +1,278 @@ + + + + + + Storage Maps - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Storage Maps

+

Another important common collection is the storage map.

+ + +

The type StorageMap<K, V> from the standard library stores a mapping of keys of type K to values of type V using a hashing function, which determines how it places these keys and values into storage slots. This is similar to Rust's HashMap<K, V> but with a few differences.

+

Storage maps are useful when you want to look up data not by using an index, as you can with vectors, but by using a key that can be of any type. For example, when building a ledger-based sub-currency smart contract, you could keep track of the balance of each wallet in a storage map in which each key is a wallet’s Address and the values are each wallet’s balance. Given an Address, you can retrieve its balance.

+

Similarly to StorageVec<T>, StorageMap<K, V> can only be used in a contract because only contracts are allowed to access persistent storage.

+

StorageMap<T> is included in the standard library prelude which means that there is no need to import it manually.

+ +

Creating a New Storage Map

+

To create a new empty storage map, we have to declare the map in a storage block as follows:

+
    map: StorageMap<Address, u64> = StorageMap::<Address, u64> {},
+
+ + +

Just like any other storage variable, two things are required when declaring a StorageMap: a type annotation and an initializer. The initializer is just an empty struct of type StorageMap because StorageMap<K, V> itself is an empty struct! Everything that is interesting about StorageMap<K, V> is implemented in its methods.

+

Storage maps, just like Vec<T> and StorageVec<T>, are implemented using generics which means that the StorageMap<K, V> type provided by the standard library can map keys of any type K to values of any type V. In the example above, we’ve told the Sway compiler that the StorageMap<K, V> in map will map keys of type Address to values of type u64.

+ +

Updating a Storage Map

+ + +

To insert key-value pairs into a storage map, we can use the insert method.

+ +

For example:

+
    #[storage(write)]
+    fn insert_into_storage_map() {
+        let addr1 = Address::from(0x0101010101010101010101010101010101010101010101010101010101010101);
+        let addr2 = Address::from(0x0202020202020202020202020202020202020202020202020202020202020202);
+
+        storage.map.insert(addr1, 42);
+        storage.map.insert(addr2, 77);
+    }
+
+

Note two details here. First, in order to use insert, we need to first access the storage map using the storage keyword. Second, because insert requires writing into storage, a #[storage(write)] annotation is required on the ABI function that calls insert.

+
+

Note +The storage annotation is also required for any private function defined in the contract that tries to insert into the map.

+
+ +
+

Note +There is no need to add the mut keyword when declaring a StorageMap<K, V>. All storage variables are mutable by default.

+
+

Accessing Values in a Storage Map

+ + +

We can get a value out of the storage map by providing its key to the get method.

+ +

For example:

+
    #[storage(read, write)]
+    fn get_from_storage_map() {
+        let addr1 = Address::from(0x0101010101010101010101010101010101010101010101010101010101010101);
+        let addr2 = Address::from(0x0202020202020202020202020202020202020202020202020202020202020202);
+
+        storage.map.insert(addr1, 42);
+        storage.map.insert(addr2, 77);
+
+        let value1 = storage.map.get(addr1).try_read().unwrap_or(0);
+    }
+
+

Here, value1 will have the value that's associated with the first address, and the result will be 42. The get method returns an Option<V>; if there’s no value for that key in the storage map, get will return None. This program handles the Option by calling unwrap_or to set value1 to zero if map doesn't have an entry for the key.

+

Storage Maps with Multiple Keys

+

Maps with multiple keys can be implemented using tuples as keys. For example:

+
    map_two_keys: StorageMap<(b256, bool), b256> = StorageMap::<(b256, bool), b256> {},
+
+

Nested Storage Maps

+

It is possible to nest storage maps as follows:

+
    nested_map: StorageMap<u64, StorageMap<u64, u64>> = StorageMap::<u64, StorageMap<u64, u64>> {},
+
+

The nested map can then be accessed as follows:

+
    #[storage(read, write)]
+    fn access_nested_map() {
+        storage.nested_map.get(0).insert(1, 42);
+        storage.nested_map.get(2).insert(3, 24);
+
+        assert(storage.nested_map.get(0).get(1).read() == 42);
+        assert(storage.nested_map.get(0).get(0).try_read().is_none()); // Nothing inserted here
+        assert(storage.nested_map.get(2).get(3).read() == 24);
+        assert(storage.nested_map.get(2).get(2).try_read().is_none()); // Nothing inserted here
+    }
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/common-collections/storage_vec.html b/docs/beta-4/builds/sway/master/book/common-collections/storage_vec.html new file mode 100644 index 000000000..2bbbb1fb8 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/common-collections/storage_vec.html @@ -0,0 +1,306 @@ + + + + + + Storage Vectors - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Storage Vectors

+

The second collection type we’ll look at is StorageVec<T>. Just like vectors on the heap (i.e. Vec<T>), storage vectors allow you to store more than one value in a single data structure where each value is assigned an index and can only store values of the same type. However, unlike Vec<T>, the elements of a StorageVec are stored in persistent storage, and consecutive elements are not necessarily stored in storage slots that have consecutive keys.

+

In order to use StorageVec<T>, you must first import StorageVec as follows:

+
use std::storage::storage_vec::*;
+
+

Another major difference between Vec<T> and StorageVec<T> is that StorageVec<T> can only be used in a contract because only contracts are allowed to access persistent storage.

+

Creating a New Storage Vector

+

To create a new empty storage vector, we have to declare the vector in a storage block as follows:

+
    v: StorageVec<u64> = StorageVec {},
+
+

Just like any other storage variable, two things are required when declaring a StorageVec: a type annotation and an initializer. The initializer is just an empty struct of type StorageVec because StorageVec<T> itself is an empty struct! Everything that is interesting about StorageVec<T> is implemented in its methods.

+

Storage vectors, just like Vec<T>, are implemented using generics which means that the StorageVec<T> type provided by the standard library can hold any type. When we create a storage vector to hold a specific type, we can specify the type within angle brackets. In the example above, we’ve told the Sway compiler that the StorageVec<T> in v will hold elements of the u64 type.

+

Updating a Storage Vector

+

To add elements to a storage vector, we can use the push method, as shown below:

+
    #[storage(read, write)]
+    fn push_to_storage_vec() {
+        storage.v.push(5);
+        storage.v.push(6);
+        storage.v.push(7);
+        storage.v.push(8);
+    }
+
+

Note two details here. First, in order to use push, we need to first access the vector using the storage keyword. Second, because push requires accessing storage, a storage annotation is required on the ABI function that calls push. While it may seem that #[storage(write)] should be enough here, the read annotation is also required because each call to push requires reading (and then updating) the length of the storage vector which is also stored in persistent storage.

+
+

Note +The storage annotation is also required for any private function defined in the contract that tries to push into the vector.

+
+ +
+

Note +There is no need to add the mut keyword when declaring a StorageVec<T>. All storage variables are mutable by default.

+
+

Reading Elements of Storage Vectors

+

To read a value stored in a vector at a particular index, you can use the get method as shown below:

+
    #[storage(read)]
+    fn read_from_storage_vec() {
+        let third = storage.v.get(2);
+        match third {
+            Some(third) => log(third.read()),
+            None => revert(42),
+        }
+    }
+
+

Note three details here. First, we use the index value of 2 to get the third element because vectors are indexed by number, starting at zero. Second, we get the third element by using the get method with the index passed as an argument, which gives us an Option<StorageKey<T>>. Third, the ABI function calling get only requires the annotation #[storage(read)] as one might expect because get does not write to storage.

+

When the get method is passed an index that is outside the vector, it returns None without panicking. This is particularly useful if accessing an element beyond the range of the vector may happen occasionally under normal circumstances. Your code will then have logic to handle having either Some(element) or None. For example, the index could be coming as a contract method argument. If the argument passed is too large, the method get will return a None value, and the contract method may then decide to revert when that happens or return a meaningful error that tells the user how many items are in the current vector and give them another chance to pass a valid value.

+

Iterating over the Values in a Vector

+

To access each element in a vector in turn, we would iterate through all of the valid indices using a while loop and the len method as shown below:

+
    #[storage(read)]
+    fn iterate_over_a_storage_vec() {
+        let mut i = 0;
+        while i < storage.v.len() {
+            log(storage.v.get(i).unwrap().read());
+            i += 1;
+        }
+    }
+
+

Again, this is quite similar to iterating over the elements of a Vec<T> where we use the method len to return the length of the vector. We also call the method unwrap to extract the Option returned by get followed by a call to read() to actually read the stored value. We know that unwrap will not fail (i.e. will not cause a revert) because each index i passed to get is known to be smaller than the length of the vector.

+

Using an Enum to store Multiple Types

+

Storage vectors, just like Vec<T>, can only store values that are the same type. Similarly to what we did for Vec<T> in the section Using an Enum to store Multiple Types, we can define an enum whose variants will hold the different value types, and all the enum variants will be considered the same type: that of the enum. This is shown below:

+
enum TableCell {
+    Int: u64,
+    B256: b256,
+    Boolean: bool,
+}
+
+

Then we can declare a storage vector in a storage block to hold that enum and so, ultimately, holds different types:

+
    row: StorageVec<TableCell> = StorageVec {},
+
+

We can now push different enum variants to the storage vector as follows:

+
    #[storage(read, write)]
+    fn push_to_multiple_types_storage_vec() {
+        storage.row.push(TableCell::Int(3));
+        storage.row.push(TableCell::B256(0x0101010101010101010101010101010101010101010101010101010101010101));
+        storage.row.push(TableCell::Boolean(true));
+    }
+
+

Now that we’ve discussed some of the most common ways to use storage vectors, be sure to review the API documentation for all the many useful methods defined on StorageVec<T> by the standard library. For now, these can be found in the source code for StorageVec<T>. For example, in addition to push, a pop method removes and returns the last element, a remove method removes and returns the element at some chosen index within the vector, an insert method inserts an element at some chosen index within the vector, etc.

+

Nested Storage Vecs

+

It is possible to nest storage vectors as follows:

+
    nested_vec: StorageVec<StorageVec<u64>> = StorageVec {},
+
+

The nested vector can then be accessed as follows:

+
    #[storage(read, write)]
+    fn access_nested_vec() {
+        storage.nested_vec.push(StorageVec {});
+        storage.nested_vec.push(StorageVec {});
+
+        let mut inner_vec0 = storage.nested_vec.get(0).unwrap();
+        let mut inner_vec1 = storage.nested_vec.get(1).unwrap();
+
+        inner_vec0.push(0);
+        inner_vec0.push(1);
+
+        inner_vec1.push(2);
+        inner_vec1.push(3);
+        inner_vec1.push(4);
+
+        assert(inner_vec0.len() == 2);
+        assert(inner_vec0.get(0).unwrap().read() == 0);
+        assert(inner_vec0.get(1).unwrap().read() == 1);
+        assert(inner_vec0.get(2).is_none());
+
+        assert(inner_vec1.len() == 3);
+        assert(inner_vec1.get(0).unwrap().read() == 2);
+        assert(inner_vec1.get(1).unwrap().read() == 3);
+        assert(inner_vec1.get(2).unwrap().read() == 4);
+        assert(inner_vec1.get(3).is_none());
+    }
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/common-collections/vec.html b/docs/beta-4/builds/sway/master/book/common-collections/vec.html new file mode 100644 index 000000000..d253b1142 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/common-collections/vec.html @@ -0,0 +1,249 @@ + + + + + + Vectors on the Heap - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Vectors on the Heap

+

The first collection type we’ll look at is Vec<T>, also known as a vector. Vectors allow you to store more than one value in a single data structure that puts all the values next to each other in memory. Vectors can only store values of the same type. They are useful when you have a list of items, such as the lines of text in a file or the prices of items in a shopping cart.

+

Vec<T> is included in the standard library prelude which means that there is no need to import it manually.

+

Creating a New Vector

+

To create a new empty vector, we call the Vec::new function, as shown below:

+
    let v: Vec<u64> = Vec::new();
+
+

Note that we added a type annotation here. Because we aren’t inserting any values into this vector, the Sway compiler doesn’t know what kind of elements we intend to store. Vectors are implemented using generics which means that the Vec<T> type provided by the standard library can hold any type. When we create a vector to hold a specific type, we can specify the type within angle brackets. In the example above, we’ve told the Sway compiler that the Vec<T> in v will hold elements of the u64 type.

+

Updating a Vector

+

To create a vector and then add elements to it, we can use the push method, as shown below:

+
    let mut v = Vec::new();
+
+    v.push(5);
+    v.push(6);
+    v.push(7);
+    v.push(8);
+
+

As with any variable, if we want to be able to change its value, we need to make it mutable using the mut keyword, as discussed in the section Declaring a Variable. The numbers we place inside are all of type u64, and the Sway compiler infers this from the data, so we don’t need the Vec<u64> annotation.

+

Reading Elements of Vectors

+

To read a value stored in a vector at a particular index, you can use the get method as shown below:

+
    let third = v.get(2);
+    match third {
+        Some(third) => log(third),
+        None => revert(42),
+    }
+
+

Note two details here. First, we use the index value of 2 to get the third element because vectors are indexed by number, starting at zero. Second, we get the third element by using the get method with the index passed as an argument, which gives us an Option<T>.

+

When the get method is passed an index that is outside the vector, it returns None without panicking. This is particularly useful if accessing an element beyond the range of the vector may happen occasionally under normal circumstances. Your code will then have logic to handle having either Some(element) or None. For example, the index could be coming as a contract method argument. If the argument passed is too large, the method get will return a None value, and the contract method may then decide to revert when that happens or return a meaningful error that tells the user how many items are in the current vector and give them another chance to pass a valid value.

+

Iterating over the Values in a Vector

+

To access each element in a vector in turn, we would iterate through all of the valid indices using a while loop and the len method as shown below:

+
    let mut i = 0;
+    while i < v.len() {
+        log(v.get(i).unwrap());
+        i += 1;
+    }
+
+

Note two details here. First, we use the method len which returns the length of the vector. Second, we call the method unwrap to extract the Option returned by get. We know that unwrap will not fail (i.e. will not cause a revert) because each index i passed to get is known to be smaller than the length of the vector.

+

Using an Enum to store Multiple Types

+

Vectors can only store values that are the same type. This can be inconvenient; there are definitely use cases for needing to store a list of items of different types. Fortunately, the variants of an enum are defined under the same enum type, so when we need one type to represent elements of different types, we can define and use an enum!

+

For example, say we want to get values from a row in a table in which some of the columns in the row contain integers, some b256 values, and some Booleans. We can define an enum whose variants will hold the different value types, and all the enum variants will be considered the same type: that of the enum. Then we can create a vector to hold that enum and so, ultimately, holds different types. We’ve demonstrated this below:

+
    enum TableCell {
+        Int: u64,
+        B256: b256,
+        Boolean: bool,
+    }
+
+    let mut row = Vec::new();
+    row.push(TableCell::Int(3));
+    row.push(TableCell::B256(0x0101010101010101010101010101010101010101010101010101010101010101));
+    row.push(TableCell::Boolean(true));
+
+

Now that we’ve discussed some of the most common ways to use vectors, be sure to review the API documentation for all the many useful methods defined on Vec<T> by the standard library. For now, these can be found in the source code for Vec<T>. For example, in addition to push, a pop method removes and returns the last element, a remove method removes and returns the element at some chosen index within the vector, an insert method inserts an element at some chosen index within the vector, etc.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/examples/counter.html b/docs/beta-4/builds/sway/master/book/examples/counter.html new file mode 100644 index 000000000..cf9017792 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/examples/counter.html @@ -0,0 +1,230 @@ + + + + + + Counter - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Counter

+

The following is a simple example of a contract which implements a counter. Both the initialize_counter() and increment_counter() ABI methods return the currently set value.

+
forc template --template-name counter my_counter_project
+
+
contract;
+
+abi TestContract {
+    #[storage(write)]
+    fn initialize_counter(value: u64) -> u64;
+
+    #[storage(read, write)]
+    fn increment_counter(amount: u64) -> u64;
+}
+
+storage {
+    counter: u64 = 0,
+}
+
+impl TestContract for Contract {
+    #[storage(write)]
+    fn initialize_counter(value: u64) -> u64 {
+        storage.counter.write(value);
+        value
+    }
+
+    #[storage(read, write)]
+    fn increment_counter(amount: u64) -> u64 {
+        let incremented = storage.counter.read() + amount;
+        storage.counter.write(incremented);
+        incremented
+    }
+}
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/examples/fizzbuzz.html b/docs/beta-4/builds/sway/master/book/examples/fizzbuzz.html new file mode 100644 index 000000000..3973f7e64 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/examples/fizzbuzz.html @@ -0,0 +1,227 @@ + + + + + + FizzBuzz - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

FizzBuzz

+

This example is not the traditional FizzBuzz; instead it is the smart contract version! A script can call the fizzbuzz ABI method of this contract with some u64 value and receive back its fizzbuzzability as an enum.

+

The format for custom structs and enums such as FizzBuzzResult will be automatically included in the ABI JSON so that off-chain code can handle the encoded form of the returned data.

+
contract;
+
+enum FizzBuzzResult {
+    Fizz: (),
+    Buzz: (),
+    FizzBuzz: (),
+    Other: u64,
+}
+
+abi FizzBuzz {
+    fn fizzbuzz(input: u64) -> FizzBuzzResult;
+}
+
+impl FizzBuzz for Contract {
+    fn fizzbuzz(input: u64) -> FizzBuzzResult {
+        if input % 15 == 0 {
+            FizzBuzzResult::FizzBuzz
+        } else if input % 3 == 0 {
+            FizzBuzzResult::Fizz
+        } else if input % 5 == 0 {
+            FizzBuzzResult::Buzz
+        } else {
+            FizzBuzzResult::Other(input)
+        }
+    }
+}
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/examples/index.html b/docs/beta-4/builds/sway/master/book/examples/index.html new file mode 100644 index 000000000..bcce8627b --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/examples/index.html @@ -0,0 +1,205 @@ + + + + + + Examples - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Example

+

Some basic example contracts to see how Sway and Forc work.

+ + +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/examples/subcurrency.html b/docs/beta-4/builds/sway/master/book/examples/subcurrency.html new file mode 100644 index 000000000..3ec54df0a --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/examples/subcurrency.html @@ -0,0 +1,292 @@ + + + + + + Subcurrency - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Subcurrency

+

The following is a simple example of a subcurrency which implements functionality to mint and send a token. It is a ledger-based token, i.e. the contract maintains a ledger of user account balances.

+

Being a ledger-based token, this example does not use Fuel's native asset system. It is not recommended to actually use ledger-based tokens in production; this example is here purely for illustrative purposes.

+
contract;
+
+use std::hash::*;
+
+////////////////////////////////////////
+// Event declarations
+////////////////////////////////////////
+//
+// Events allow clients to react to changes in the contract.
+// Unlike Solidity, events are simply structs.
+//
+/// Emitted when a token is sent.
+struct Sent {
+    from: Address,
+    to: Address,
+    amount: u64,
+}
+
+////////////////////////////////////////
+// ABI method declarations
+////////////////////////////////////////
+/// ABI for a subcurrency.
+abi Token {
+    // Mint new tokens and send to an address.
+    // Can only be called by the contract creator.
+    #[storage(read, write)]
+    fn mint(receiver: Address, amount: u64);
+
+    // Sends an amount of an existing token.
+    // Can be called from any address.
+    #[storage(read, write)]
+    fn send(receiver: Address, amount: u64);
+}
+
+////////////////////////////////////////
+// Constants
+////////////////////////////////////////
+/// Address of contract creator.
+const MINTER = Address::from(0x9299da6c73e6dc03eeabcce242bb347de3f5f56cd1c70926d76526d7ed199b8b);
+
+////////////////////////////////////////
+// Contract storage
+////////////////////////////////////////
+// Contract storage persists across transactions.
+storage {
+    balances: StorageMap<Address, u64> = StorageMap::<Address, u64> {},
+}
+
+////////////////////////////////////////
+// ABI definitions
+////////////////////////////////////////
+/// Contract implements the `Token` ABI.
+impl Token for Contract {
+    #[storage(read, write)]
+    fn mint(receiver: Address, amount: u64) {
+        let sender = msg_sender().unwrap();
+        let sender: Address = match sender {
+            Identity::Address(addr) => {
+                assert(addr == MINTER);
+                addr
+            },
+            _ => revert(0),
+        };
+
+        // Increase the balance of receiver
+        storage.balances.insert(receiver, storage.balances.get(receiver).try_read().unwrap_or(0) + amount);
+    }
+
+    #[storage(read, write)]
+    fn send(receiver: Address, amount: u64) {
+        let sender = msg_sender().unwrap();
+        let sender = match sender {
+            Identity::Address(addr) => addr,
+            _ => revert(0),
+        };
+
+        // Reduce the balance of sender
+        let sender_amount = storage.balances.get(sender).try_read().unwrap_or(0);
+        assert(sender_amount > amount);
+        storage.balances.insert(sender, sender_amount - amount);
+
+        // Increase the balance of receiver
+        storage.balances.insert(receiver, storage.balances.get(receiver).try_read().unwrap_or(0) + amount);
+
+        log(Sent {
+            from: sender,
+            to: receiver,
+            amount: amount,
+        });
+    }
+}
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/examples/wallet_smart_contract.html b/docs/beta-4/builds/sway/master/book/examples/wallet_smart_contract.html new file mode 100644 index 000000000..e684dc0e6 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/examples/wallet_smart_contract.html @@ -0,0 +1,257 @@ + + + + + + Wallet Smart Contract - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Wallet Smart Contract

+

ABI Declaration

+
library;
+
+abi Wallet {
+    #[storage(read, write), payable]
+    fn receive_funds();
+
+    #[storage(read, write)]
+    fn send_funds(amount_to_send: u64, recipient_address: Address);
+}
+
+

ABI Implementation

+
contract;
+
+use std::{
+    call_frames::msg_asset_id,
+    constants::BASE_ASSET_ID,
+    context::msg_amount,
+    token::transfer_to_address,
+};
+
+use wallet_abi::Wallet;
+const OWNER_ADDRESS = Address::from(0x8900c5bec4ca97d4febf9ceb4754a60d782abbf3cd815836c1872116f203f861);
+
+storage {
+    balance: u64 = 0,
+}
+
+impl Wallet for Contract {
+    #[storage(read, write), payable]
+    fn receive_funds() {
+        if msg_asset_id() == BASE_ASSET_ID {
+            // If we received `BASE_ASSET_ID` then keep track of the balance.
+            // Otherwise, we're receiving other native assets and don't care
+            // about our balance of tokens.
+            storage.balance.write(storage.balance.read() + msg_amount());
+        }
+    }
+
+    #[storage(read, write)]
+    fn send_funds(amount_to_send: u64, recipient_address: Address) {
+        let sender = msg_sender().unwrap();
+        match sender {
+            Identity::Address(addr) => assert(addr == OWNER_ADDRESS),
+            _ => revert(0),
+        };
+
+        let current_balance = storage.balance.read();
+        assert(current_balance >= amount_to_send);
+
+        storage.balance.write(current_balance - amount_to_send);
+
+        // Note: `transfer_to_address()` is not a call and thus not an
+        // interaction. Regardless, this code conforms to
+        // checks-effects-interactions to avoid re-entrancy.
+        transfer_to_address(recipient_address, BASE_ASSET_ID, amount_to_send);
+    }
+}
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/forc/commands/forc_addr2line.html b/docs/beta-4/builds/sway/master/book/forc/commands/forc_addr2line.html new file mode 100644 index 000000000..8ac674e86 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/forc/commands/forc_addr2line.html @@ -0,0 +1,218 @@ + + + + + + forc addr2line - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

forc-addr2line

+

Show location and context of an opcode address in its source file

+

USAGE:

+

forc addr2line [OPTIONS] --sourcemap-path <SOURCEMAP_PATH> --opcode-index <OPCODE_INDEX>

+

OPTIONS:

+

-c, --context <CONTEXT>

+

How many lines of context to show [default: 2]

+

-g, --sourcemap-path <SOURCEMAP_PATH>

+

Source file mapping in JSON format

+

-h, --help

+

Print help information

+

-i, --opcode-index <OPCODE_INDEX>

+

Opcode index

+

-L, --log-level <LOG_LEVEL>

+

Set the log level

+

-s, --silent

+

Silence all output

+

-S, --search-dir <SEARCH_DIR>

+

Where to search for the project root [default: .]

+

-v, --verbose

+

Use verbose output

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/forc/commands/forc_build.html b/docs/beta-4/builds/sway/master/book/forc/commands/forc_build.html new file mode 100644 index 000000000..c8827eefc --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/forc/commands/forc_build.html @@ -0,0 +1,308 @@ + + + + + + forc build - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

forc-build

+

Compile the current or target project.

+

The output produced will depend on the project's program type.

+
    +
  • +

    script, predicate and contract projects will produce their bytecode in binary format +<project-name>.bin.

    +
  • +
  • +

    script projects will also produce a file containing the hash of the bytecode binary +<project-name>-bin-hash (using fuel_cypto::Hasher).

    +
  • +
  • +

    predicate projects will also produce a file containing the root hash of the bytecode binary +<project-name>-bin-root (using fuel_tx::Contract::root_from_code).

    +
  • +
  • +

    contract and library projects will also produce the public ABI in JSON format +<project-name>-abi.json.

    +
  • +
+

USAGE:

+

forc build [OPTIONS]

+

OPTIONS:

+

--ast

+

Print the generated Sway AST (Abstract Syntax Tree)

+

--build-profile <BUILD_PROFILE>

+

Name of the build profile to use.

+

If unspecified, forc will use debug build profile.

+

--build-target <BUILD_TARGET>

+

Build target to use for code generation

+

[default: fuel] +[possible values: fuel, evm, midenvm]

+

--dca-graph <DCA_GRAPH>

+

Print the computed Sway DCA graph. DCA graph is printed to the specified path. If +specified '' graph is printed to stdout

+

--dca-graph-url-format <DCA_GRAPH_URL_FORMAT>

+

Specifies the url format to be used in the generated dot file. +Variables {path}, {line} {col} can be used in the provided format. +An example for vscode would be: +"vscode://file/{path}:{line}:{col}"

+

--error-on-warnings

+

Treat warnings as errors

+

--finalized-asm

+

Print the finalized ASM.

+

This is the state of the ASM with registers allocated and optimisations applied.

+

-g, --output-debug <DEBUG_FILE>

+

If set, outputs source file mapping in JSON format

+

-h, --help

+

Print help information

+

--intermediate-asm

+

Print the generated ASM.

+

This is the state of the ASM prior to performing register allocation and other ASM +optimisations.

+

--ipfs-node <IPFS_NODE>

+

The IPFS Node to use for fetching IPFS sources.

+

Possible values: PUBLIC, LOCAL, <GATEWAY_URL>

+

--ir

+

Print the generated Sway IR (Intermediate Representation)

+

--json-abi

+

By default the JSON for ABIs is formatted for human readability. By using this option +JSON output will be "minified", i.e. all on one line without whitespace

+

--json-abi-with-callpaths

+

Outputs json abi with callpaths instead of names for struct and enums

+

--json-storage-slots

+

By default the JSON for initial storage slots is formatted for human readability. By +using this option JSON output will be "minified", i.e. all on one line without +whitespace

+

-L, --log-level <LOG_LEVEL>

+

Set the log level

+

--locked

+

Requires that the Forc.lock file is up-to-date. If the lock file is missing, or it needs +to be updated, Forc will exit with an error

+

--metrics-outfile <METRICS_OUTFILE>

+

Output compilation metrics into file

+

-o, --output-bin <BIN_FILE>

+

If set, outputs a binary file representing the script bytes

+

--offline

+

Offline mode, prevents Forc from using the network when managing dependencies. Meaning +it will only try to use previously downloaded dependencies

+

--output-directory <OUTPUT_DIRECTORY>

+

The directory in which the sway compiler output artifacts are placed.

+

By default, this is <project-root>/out.

+

-p, --path <PATH>

+

Path to the project, if not specified, current working directory will be used

+

--release

+

Use release build plan. If a custom release plan is not specified, it is implicitly +added to the manifest file.

+

If --build-profile is also provided, forc omits this flag and uses provided +build-profile.

+

--reverse-order

+

Output build errors and warnings in reverse order

+

-s, --silent

+

Silence all output

+

-t, --terse

+

Terse mode. Limited warning and error output

+

--tests

+

Also build all tests within the project

+

--time-phases

+

Output the time elapsed over each part of the compilation process

+

-v, --verbose

+

Use verbose output

+

EXAMPLE

+

Compile the sway files of the current project.

+
$ forc build
+Compiled script "my-fuel-project".
+Bytecode size is 28 bytes.
+
+

The output produced will depend on the project's program type. Building script, predicate and contract projects will produce their bytecode in binary format <project-name>.bin. Building contracts and libraries will also produce the public ABI in JSON format <project-name>-abi.json.

+

By default, these artifacts are placed in the out/ directory.

+

If a Forc.lock file did not yet exist, it will be created in order to pin each of the dependencies listed in Forc.toml to a specific commit or version.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/forc/commands/forc_check.html b/docs/beta-4/builds/sway/master/book/forc/commands/forc_check.html new file mode 100644 index 000000000..af9463dd3 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/forc/commands/forc_check.html @@ -0,0 +1,232 @@ + + + + + + forc check - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

forc-check

+

Check the current or target project and all of its dependencies for errors.

+

This will essentially compile the packages without performing the final step of code generation, +which is faster than running forc build.

+

USAGE:

+

forc check [OPTIONS] [BUILD_TARGET]

+

ARGS:

+

<BUILD_TARGET> +Build target to use for code generation

+

[default: fuel] +[possible values: fuel, evm, midenvm]

+

OPTIONS:

+

--disable-tests

+

Disable checking unit tests

+

-h, --help

+

Print help information

+

--ipfs-node <IPFS_NODE>

+

The IPFS Node to use for fetching IPFS sources.

+

Possible values: PUBLIC, LOCAL, <GATEWAY_URL>

+

-L, --log-level <LOG_LEVEL>

+

Set the log level

+

--locked

+

Requires that the Forc.lock file is up-to-date. If the lock file is missing, or it needs +to be updated, Forc will exit with an error

+

--offline

+

Offline mode, prevents Forc from using the network when managing dependencies. Meaning +it will only try to use previously downloaded dependencies

+

-p, --path <PATH>

+

Path to the project, if not specified, current working directory will be used

+

-s, --silent

+

Silence all output

+

-t, --terse

+

Terse mode. Limited warning and error output

+

-v, --verbose

+

Use verbose output

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/forc/commands/forc_clean.html b/docs/beta-4/builds/sway/master/book/forc/commands/forc_clean.html new file mode 100644 index 000000000..6d4290c94 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/forc/commands/forc_clean.html @@ -0,0 +1,213 @@ + + + + + + forc clean - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

forc-clean

+

Removes the default forc compiler output artifact directory, i.e. <project-name>/out

+

USAGE:

+

forc clean [OPTIONS]

+

OPTIONS:

+

-h, --help

+

Print help information

+

-L, --log-level <LOG_LEVEL>

+

Set the log level

+

-p, --path <PATH>

+

Path to the project, if not specified, current working directory +will be used

+

-s, --silent

+

Silence all output

+

-v, --verbose

+

Use verbose output

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/forc/commands/forc_completions.html b/docs/beta-4/builds/sway/master/book/forc/commands/forc_completions.html new file mode 100644 index 000000000..c8c62df5a --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/forc/commands/forc_completions.html @@ -0,0 +1,295 @@ + + + + + + forc completions - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

forc-completions

+

Generate tab-completion scripts for your shell

+

USAGE:

+

forc completions [OPTIONS] --shell

+

OPTIONS:

+

-h, --help

+

Print help information

+

-L, --log-level <LOG_LEVEL>

+

Set the log level

+

-s, --silent

+

Silence all output

+

-S, --shell <SHELL>

+

Specify shell to enable tab-completion for

+

[possible values: zsh, bash, fish, powershell, elvish]

+

For more info: +https://fuellabs.github.io/sway/latest/forc/commands/forc_completions.html

+

-v, --verbose

+

Use verbose output

+

DISCUSSION

+

Enable tab completion for Bash, Fish, Zsh, or PowerShell +The script is output on stdout, allowing one to re-direct the +output to the file of their choosing. Where you place the file +will depend on which shell, and which operating system you are +using. Your particular configuration may also determine where +these scripts need to be placed.

+

Here are some common set ups for the three supported shells under +Unix and similar operating systems (such as GNU/Linux).

+

BASH

+

Completion files are commonly stored in /etc/bash_completion.d/ for +system-wide commands, but can be stored in +~/.local/share/bash-completion/completions for user-specific commands. +Run the command:

+
mkdir -p ~/.local/share/bash-completion/completions
+forc completions --shell=bash >> ~/.local/share/bash-completion/completions/forc
+
+

This installs the completion script. You may have to log out and +log back in to your shell session for the changes to take effect.

+

BASH (macOS/Homebrew)

+

Homebrew stores bash completion files within the Homebrew directory. +With the bash-completion brew formula installed, run the command:

+
mkdir -p $(brew --prefix)/etc/bash_completion.d
+forc completions --shell=bash > $(brew --prefix)/etc/bash_completion.d/forc.bash-completion
+
+

FISH

+

Fish completion files are commonly stored in +$HOME/.config/fish/completions. Run the command:

+
mkdir -p ~/.config/fish/completions
+forc completions --shell=fish > ~/.config/fish/completions/forc.fish
+
+

This installs the completion script. You may have to log out and +log back in to your shell session for the changes to take effect.

+

ZSH

+

ZSH completions are commonly stored in any directory listed in +your $fpath variable. To use these completions, you must either +add the generated script to one of those directories, or add your +own to this list.

+

Adding a custom directory is often the safest bet if you are +unsure of which directory to use. First create the directory; for +this example we'll create a hidden directory inside our $HOME +directory:

+
mkdir ~/.zfunc
+
+

Then add the following lines to your .zshrc just before +compinit:

+
fpath+=~/.zfunc
+
+

Now you can install the completions script using the following +command:

+
forc completions --shell=zsh > ~/.zfunc/_forc
+
+

You must then either log out and log back in, or simply run

+
exec zsh
+
+

for the new completions to take effect.

+

CUSTOM LOCATIONS

+

Alternatively, you could save these files to the place of your +choosing, such as a custom directory inside your $HOME. Doing so +will require you to add the proper directives, such as sourceing +inside your login script. Consult your shells documentation for +how to add such directives.

+

POWERSHELL

+

The powershell completion scripts require PowerShell v5.0+ (which +comes with Windows 10, but can be downloaded separately for windows 7 +or 8.1).

+

First, check if a profile has already been set

+
Test-Path $profile
+
+

If the above command returns False run the following

+
New-Item -path $profile -type file -force
+
+

Now open the file provided by $profile (if you used the +New-Item command it will be +${env:USERPROFILE}\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1

+

Next, we either save the completions file into our profile, or +into a separate file and source it inside our profile. To save the +completions into our profile simply use

+
forc completions --shell=powershell >> ${env:USERPROFILE}\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/forc/commands/forc_contract-id.html b/docs/beta-4/builds/sway/master/book/forc/commands/forc_contract-id.html new file mode 100644 index 000000000..6de967c0d --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/forc/commands/forc_contract-id.html @@ -0,0 +1,278 @@ + + + + + + forc contract-id - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

forc-contract-id

+

Determine contract-id for a contract. For workspaces outputs all contract ids in the workspace

+

USAGE:

+

forc contract-id [OPTIONS]

+

OPTIONS:

+

--ast

+

Print the generated Sway AST (Abstract Syntax Tree)

+

--build-profile <BUILD_PROFILE>

+

Name of the build profile to use.

+

If unspecified, forc will use debug build profile.

+

--dca-graph <DCA_GRAPH>

+

Print the computed Sway DCA graph. DCA graph is printed to the specified path. If +specified '' graph is printed to stdout

+

--dca-graph-url-format <DCA_GRAPH_URL_FORMAT>

+

Specifies the url format to be used in the generated dot file. +Variables {path}, {line} {col} can be used in the provided format. +An example for vscode would be: +"vscode://file/{path}:{line}:{col}"

+

--error-on-warnings

+

Treat warnings as errors

+

--finalized-asm

+

Print the finalized ASM.

+

This is the state of the ASM with registers allocated and optimisations applied.

+

-g, --output-debug <DEBUG_FILE>

+

If set, outputs source file mapping in JSON format

+

-h, --help

+

Print help information

+

--intermediate-asm

+

Print the generated ASM.

+

This is the state of the ASM prior to performing register allocation and other ASM +optimisations.

+

--ipfs-node <IPFS_NODE>

+

The IPFS Node to use for fetching IPFS sources.

+

Possible values: PUBLIC, LOCAL, <GATEWAY_URL>

+

--ir

+

Print the generated Sway IR (Intermediate Representation)

+

--json-abi

+

By default the JSON for ABIs is formatted for human readability. By using this option +JSON output will be "minified", i.e. all on one line without whitespace

+

--json-abi-with-callpaths

+

Outputs json abi with callpaths instead of names for struct and enums

+

--json-storage-slots

+

By default the JSON for initial storage slots is formatted for human readability. By +using this option JSON output will be "minified", i.e. all on one line without +whitespace

+

-L, --log-level <LOG_LEVEL>

+

Set the log level

+

--locked

+

Requires that the Forc.lock file is up-to-date. If the lock file is missing, or it needs +to be updated, Forc will exit with an error

+

--metrics-outfile <METRICS_OUTFILE>

+

Output compilation metrics into file

+

-o, --output-bin <BIN_FILE>

+

If set, outputs a binary file representing the script bytes

+

--offline

+

Offline mode, prevents Forc from using the network when managing dependencies. Meaning +it will only try to use previously downloaded dependencies

+

--output-directory <OUTPUT_DIRECTORY>

+

The directory in which the sway compiler output artifacts are placed.

+

By default, this is <project-root>/out.

+

-p, --path <PATH>

+

Path to the project, if not specified, current working directory will be used

+

--release

+

Use release build plan. If a custom release plan is not specified, it is implicitly +added to the manifest file.

+

If --build-profile is also provided, forc omits this flag and uses provided +build-profile.

+

--reverse-order

+

Output build errors and warnings in reverse order

+

-s, --silent

+

Silence all output

+

--salt <SALT>

+

Added salt used to derive the contract ID.

+

By default, this is +0x0000000000000000000000000000000000000000000000000000000000000000.

+

-t, --terse

+

Terse mode. Limited warning and error output

+

--time-phases

+

Output the time elapsed over each part of the compilation process

+

-v, --verbose

+

Use verbose output

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/forc/commands/forc_init.html b/docs/beta-4/builds/sway/master/book/forc/commands/forc_init.html new file mode 100644 index 000000000..be93f85a3 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/forc/commands/forc_init.html @@ -0,0 +1,237 @@ + + + + + + forc init - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

forc-init

+

Create a new Forc project in an existing directory

+

USAGE:

+

forc init [OPTIONS]

+

OPTIONS:

+

--contract

+

The default program type, excluding all flags or adding this flag +creates a basic contract program

+

-h, --help

+

Print help information

+

-L, --log-level <LOG_LEVEL>

+

Set the log level

+

--library

+

Create a package with a library target (src/lib.sw)

+

--name <NAME>

+

Set the package name. Defaults to the directory name

+

--path <PATH>

+

The directory in which the forc project will be initialized

+

--predicate

+

Create a package with a predicate target (src/predicate.rs)

+

-s, --silent

+

Silence all output

+

--script

+

Create a package with a script target (src/main.sw)

+

-v, --verbose

+

Use verbose output

+

--workspace

+

Adding this flag creates an empty workspace

+

EXAMPLE

+
$ mkdir my-fuel-project
+$ cd my-fuel-project
+$ forc init
+$ tree
+.
+├── Forc.toml
+└── src
+    └── main.sw
+
+

Forc.toml is the Forc manifest file, containing information about the project and dependencies.

+

A src/ directory is created, with a single main.sw Sway file in it.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/forc/commands/forc_new.html b/docs/beta-4/builds/sway/master/book/forc/commands/forc_new.html new file mode 100644 index 000000000..670383077 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/forc/commands/forc_new.html @@ -0,0 +1,237 @@ + + + + + + forc new - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

forc-new

+

Create a new Forc project at <path>

+

USAGE:

+

forc new [OPTIONS]

+

ARGS:

+

<PATH>

+

The path at which the project directory will be created

+

OPTIONS:

+

--contract

+

The default program type. Excluding all flags or adding this flag +creates a basic contract program

+

-h, --help

+

Print help information

+

-L, --log-level <LOG_LEVEL>

+

Set the log level

+

--library

+

Adding this flag creates an empty library program

+

--name <NAME>

+

Set the package name. Defaults to the directory name

+

--predicate

+

Adding this flag creates an empty predicate program

+

-s, --silent

+

Silence all output

+

--script

+

Adding this flag creates an empty script program

+

-v, --verbose

+

Use verbose output

+

--workspace

+

Adding this flag creates an empty workspace

+

EXAMPLE

+
$ forc new my-fuel-project
+$ cd my-fuel-project
+$ tree
+.
+├── Forc.toml
+└── src
+    └── main.sw
+
+

Forc.toml is the Forc manifest file, containing information about the project and dependencies.

+

A src/ directory is created, with a single main.sw Sway file in it.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/forc/commands/forc_parse-bytecode.html b/docs/beta-4/builds/sway/master/book/forc/commands/forc_parse-bytecode.html new file mode 100644 index 000000000..8de40e201 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/forc/commands/forc_parse-bytecode.html @@ -0,0 +1,235 @@ + + + + + + forc parse-bytecode - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

forc-parse-bytecode

+

Parse bytecode file into a debug format

+

USAGE:

+

forc parse-bytecode [OPTIONS] <FILE_PATH>

+

ARGS:

+

<FILE_PATH>

+

OPTIONS:

+

-h, --help

+

Print help information

+

-L, --log-level <LOG_LEVEL>

+

Set the log level

+

-s, --silent

+

Silence all output

+

-v, --verbose

+

Use verbose output

+

EXAMPLE

+

We can try this command with the initial project created using forc init, with the counter template:

+
forc new --template counter counter
+cd counter
+forc build -o obj
+
+
counter$ forc parse-bytecode obj
+
+  half-word   byte   op                   raw           notes
+          0   0      JI(4)                90 00 00 04   conditionally jumps to byte 16
+          1   4      NOOP                 47 00 00 00
+          2   8      Undefined            00 00 00 00   data section offset lo (0)
+          3   12     Undefined            00 00 00 c8   data section offset hi (200)
+          4   16     LW(63, 12, 1)        5d fc c0 01
+          5   20     ADD(63, 63, 12)      10 ff f3 00
+         ...
+         ...
+         ...
+         60   240    Undefined            00 00 00 00
+         61   244    Undefined            fa f9 0d d3
+         62   248    Undefined            00 00 00 00
+         63   252    Undefined            00 00 00 c8
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/forc/commands/forc_plugins.html b/docs/beta-4/builds/sway/master/book/forc/commands/forc_plugins.html new file mode 100644 index 000000000..101809ac0 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/forc/commands/forc_plugins.html @@ -0,0 +1,215 @@ + + + + + + forc plugins - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

forc-plugins

+

Find all forc plugins available via PATH.

+

Prints information about each discovered plugin.

+

USAGE:

+

forc plugins [OPTIONS]

+

OPTIONS:

+

-d, --describe

+

Prints the long description associated with each listed plugin

+

-h, --help

+

Print help information

+

-L, --log-level <LOG_LEVEL>

+

Set the log level

+

-p, --paths

+

Prints the absolute path to each discovered plugin

+

-s, --silent

+

Silence all output

+

-v, --verbose

+

Use verbose output

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/forc/commands/forc_predicate-root.html b/docs/beta-4/builds/sway/master/book/forc/commands/forc_predicate-root.html new file mode 100644 index 000000000..e4ef165be --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/forc/commands/forc_predicate-root.html @@ -0,0 +1,275 @@ + + + + + + forc predicate-root - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

forc-predicate-root

+

Determine predicate-root for a predicate. For workspaces outputs all predicate roots in the +workspace

+

USAGE:

+

forc predicate-root [OPTIONS]

+

OPTIONS:

+

--ast

+

Print the generated Sway AST (Abstract Syntax Tree)

+

--build-profile <BUILD_PROFILE>

+

Name of the build profile to use.

+

If unspecified, forc will use debug build profile.

+

--dca-graph <DCA_GRAPH>

+

Print the computed Sway DCA graph. DCA graph is printed to the specified path. If +specified '' graph is printed to stdout

+

--dca-graph-url-format <DCA_GRAPH_URL_FORMAT>

+

Specifies the url format to be used in the generated dot file. +Variables {path}, {line} {col} can be used in the provided format. +An example for vscode would be: +"vscode://file/{path}:{line}:{col}"

+

--error-on-warnings

+

Treat warnings as errors

+

--finalized-asm

+

Print the finalized ASM.

+

This is the state of the ASM with registers allocated and optimisations applied.

+

-g, --output-debug <DEBUG_FILE>

+

If set, outputs source file mapping in JSON format

+

-h, --help

+

Print help information

+

--intermediate-asm

+

Print the generated ASM.

+

This is the state of the ASM prior to performing register allocation and other ASM +optimisations.

+

--ipfs-node <IPFS_NODE>

+

The IPFS Node to use for fetching IPFS sources.

+

Possible values: PUBLIC, LOCAL, <GATEWAY_URL>

+

--ir

+

Print the generated Sway IR (Intermediate Representation)

+

--json-abi

+

By default the JSON for ABIs is formatted for human readability. By using this option +JSON output will be "minified", i.e. all on one line without whitespace

+

--json-abi-with-callpaths

+

Outputs json abi with callpaths instead of names for struct and enums

+

--json-storage-slots

+

By default the JSON for initial storage slots is formatted for human readability. By +using this option JSON output will be "minified", i.e. all on one line without +whitespace

+

-L, --log-level <LOG_LEVEL>

+

Set the log level

+

--locked

+

Requires that the Forc.lock file is up-to-date. If the lock file is missing, or it needs +to be updated, Forc will exit with an error

+

--metrics-outfile <METRICS_OUTFILE>

+

Output compilation metrics into file

+

-o, --output-bin <BIN_FILE>

+

If set, outputs a binary file representing the script bytes

+

--offline

+

Offline mode, prevents Forc from using the network when managing dependencies. Meaning +it will only try to use previously downloaded dependencies

+

--output-directory <OUTPUT_DIRECTORY>

+

The directory in which the sway compiler output artifacts are placed.

+

By default, this is <project-root>/out.

+

-p, --path <PATH>

+

Path to the project, if not specified, current working directory will be used

+

--release

+

Use release build plan. If a custom release plan is not specified, it is implicitly +added to the manifest file.

+

If --build-profile is also provided, forc omits this flag and uses provided +build-profile.

+

--reverse-order

+

Output build errors and warnings in reverse order

+

-s, --silent

+

Silence all output

+

-t, --terse

+

Terse mode. Limited warning and error output

+

--time-phases

+

Output the time elapsed over each part of the compilation process

+

-v, --verbose

+

Use verbose output

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/forc/commands/forc_template.html b/docs/beta-4/builds/sway/master/book/forc/commands/forc_template.html new file mode 100644 index 000000000..b85def53b --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/forc/commands/forc_template.html @@ -0,0 +1,224 @@ + + + + + + forc template - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

forc-template

+

Create a new Forc project from a git template

+

USAGE:

+

forc template [OPTIONS] <PROJECT_NAME>

+

ARGS:

+

<PROJECT_NAME>

+

The name of the project that will be created

+

OPTIONS:

+

-h, --help

+

Print help information

+

-L, --log-level <LOG_LEVEL>

+

Set the log level

+

-s, --silent

+

Silence all output

+

-t, --template-name <TEMPLATE_NAME>

+

The name of the template that needs to be fetched and used from git repo provided

+

-u, --url <URL>

+

The template url, should be a git repo [default: https://github.com/fuellabs/sway]

+

-v, --verbose

+

Use verbose output

+

EXAMPLE

+
forc template --url https://github.com/owner/template/ --project_name my_example_project
+
+

The command above fetches the HEAD of the template repo and searches for Forc.toml at the root of the fetched repo. It will fetch the repo and prepare a new Forc.toml with the new project name. Outputs everything to current_dir/project_name.

+
forc template --url https://github.com/FuelLabs/sway --template_name counter --project_name my_example_project
+
+

The command above fetches the HEAD of the sway repo and searches for counter example inside it (there is an example called counter under sway/examples). It will fetch the counter example and prepare a new Forc.toml with the new project name. Outputs everything to current_dir/project_name.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/forc/commands/forc_test.html b/docs/beta-4/builds/sway/master/book/forc/commands/forc_test.html new file mode 100644 index 000000000..e03790e05 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/forc/commands/forc_test.html @@ -0,0 +1,302 @@ + + + + + + forc test - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

forc-test

+

Run the Sway unit tests for the current project.

+

NOTE: Previously this command was used to support Rust integration testing, however the provided +behaviour served no benefit over running cargo test directly. The proposal to change the behaviour +to support unit testing can be found at the following link: +https://github.com/FuelLabs/sway/issues/1833

+

Sway unit tests are functions decorated with the #[test] attribute. Each test is compiled as a +unique entry point for a single program and has access to the namespace of the module in which it is +declared.

+

Unit tests decorated with the #[test(script)] attribute that are declared within contract +projects may also call directly into their associated contract's ABI.

+

Upon successful compilation, test scripts are executed to their completion. A test is considered a +failure in the case that a revert (rvrt) instruction is encountered during execution. Otherwise, +it is considered a success.

+

USAGE:

+

forc test [OPTIONS] [FILTER]

+

ARGS:

+

<FILTER> +When specified, only tests containing the given string will be executed

+

OPTIONS:

+

--ast

+

Print the generated Sway AST (Abstract Syntax Tree)

+

--build-profile <BUILD_PROFILE>

+

Name of the build profile to use.

+

If unspecified, forc will use debug build profile.

+

--build-target <BUILD_TARGET>

+

Build target to use for code generation

+

[default: fuel] +[possible values: fuel, evm, midenvm]

+

--dca-graph <DCA_GRAPH>

+

Print the computed Sway DCA graph. DCA graph is printed to the specified path. If +specified '' graph is printed to stdout

+

--dca-graph-url-format <DCA_GRAPH_URL_FORMAT>

+

Specifies the url format to be used in the generated dot file. +Variables {path}, {line} {col} can be used in the provided format. +An example for vscode would be: +"vscode://file/{path}:{line}:{col}"

+

--error-on-warnings

+

Treat warnings as errors

+

--filter-exact

+

When specified, only the test exactly matching the given string will be executed

+

--finalized-asm

+

Print the finalized ASM.

+

This is the state of the ASM with registers allocated and optimisations applied.

+

-g, --output-debug <DEBUG_FILE>

+

If set, outputs source file mapping in JSON format

+

-h, --help

+

Print help information

+

--intermediate-asm

+

Print the generated ASM.

+

This is the state of the ASM prior to performing register allocation and other ASM +optimisations.

+

--ipfs-node <IPFS_NODE>

+

The IPFS Node to use for fetching IPFS sources.

+

Possible values: PUBLIC, LOCAL, <GATEWAY_URL>

+

--ir

+

Print the generated Sway IR (Intermediate Representation)

+

--json-abi

+

By default the JSON for ABIs is formatted for human readability. By using this option +JSON output will be "minified", i.e. all on one line without whitespace

+

--json-abi-with-callpaths

+

Outputs json abi with callpaths instead of names for struct and enums

+

--json-storage-slots

+

By default the JSON for initial storage slots is formatted for human readability. By +using this option JSON output will be "minified", i.e. all on one line without +whitespace

+

-l, --logs

+

Print Log and LogData receipts for tests

+

-L, --log-level <LOG_LEVEL>

+

Set the log level

+

--locked

+

Requires that the Forc.lock file is up-to-date. If the lock file is missing, or it needs +to be updated, Forc will exit with an error

+

--metrics-outfile <METRICS_OUTFILE>

+

Output compilation metrics into file

+

-o, --output-bin <BIN_FILE>

+

If set, outputs a binary file representing the script bytes

+

--offline

+

Offline mode, prevents Forc from using the network when managing dependencies. Meaning +it will only try to use previously downloaded dependencies

+

--output-directory <OUTPUT_DIRECTORY>

+

The directory in which the sway compiler output artifacts are placed.

+

By default, this is <project-root>/out.

+

-p, --path <PATH>

+

Path to the project, if not specified, current working directory will be used

+

-r, --pretty-print

+

Pretty-print the logs emiited from tests

+

--release

+

Use release build plan. If a custom release plan is not specified, it is implicitly +added to the manifest file.

+

If --build-profile is also provided, forc omits this flag and uses provided +build-profile.

+

--reverse-order

+

Output build errors and warnings in reverse order

+

-s, --silent

+

Silence all output

+

-t, --terse

+

Terse mode. Limited warning and error output

+

--test-threads <TEST_THREADS>

+

Number of threads to utilize when running the tests. By default, this is the number of +threads available in your system

+

--time-phases

+

Output the time elapsed over each part of the compilation process

+

-v, --verbose

+

Use verbose output

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/forc/commands/forc_update.html b/docs/beta-4/builds/sway/master/book/forc/commands/forc_update.html new file mode 100644 index 000000000..fb2f12471 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/forc/commands/forc_update.html @@ -0,0 +1,220 @@ + + + + + + forc update - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

forc-update

+

Update dependencies in the Forc dependencies directory

+

USAGE:

+

forc update [OPTIONS]

+

OPTIONS:

+

-c, --check

+

Checks if the dependencies have newer versions. Won't actually perform the update, will +output which ones are up-to-date and outdated

+

-d <TARGET_DEPENDENCY>

+

Dependency to be updated. If not set, all dependencies will be updated

+

-h, --help

+

Print help information

+

--ipfs-node <IPFS_NODE>

+

The IPFS Node to use for fetching IPFS sources.

+

Possible values: PUBLIC, LOCAL, <GATEWAY_URL>

+

-L, --log-level <LOG_LEVEL>

+

Set the log level

+

-p, --path <PATH>

+

Path to the project, if not specified, current working directory will be used

+

-s, --silent

+

Silence all output

+

-v, --verbose

+

Use verbose output

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/forc/commands/index.html b/docs/beta-4/builds/sway/master/book/forc/commands/index.html new file mode 100644 index 000000000..0488eaa0c --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/forc/commands/index.html @@ -0,0 +1,215 @@ + + + + + + Commands - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + +
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/forc/dependencies.html b/docs/beta-4/builds/sway/master/book/forc/dependencies.html new file mode 100644 index 000000000..f71224cbf --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/forc/dependencies.html @@ -0,0 +1,220 @@ + + + + + + Dependencies - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Dependencies

+

Forc has a dependency management system which can pull packages using git and ipfs. This allows users to build and share Forc libraries.

+

Adding a dependency

+

If your Forc.toml doesn't already have a [dependencies] table, add one. Below, list the package name alongside its source. Currently, forc supports git, ipfs and path sources.

+

If a git source is specified, forc will fetch the git repository at the given URL and then search for a Forc.toml for a package with the given name anywhere inside the git repository.

+

The following example adds a library dependency named custom_lib. For git dependencies you may optionally specify a branch, tag, or rev (i.e. commit hash) reference.

+
[dependencies]
+custom_lib = { git = "https://github.com/FuelLabs/custom_lib", branch = "master" }
+# custom_lib = { git = "https://github.com/FuelLabs/custom_lib", tag = "v0.0.1" }
+# custom_lib = { git = "https://github.com/FuelLabs/custom_lib", rev = "87f80bdf323e2d64e213895d0a639ad468f4deff" }
+
+

Depending on a local library using path:

+
[dependencies]
+custom_lib = { path = "../custom_lib" }
+
+

For ipfs sources, forc will fetch the specified cid using either a local ipfs node or a public gateway. forc automatically tries to connect to local ipfs node and if it fails, fallbacks to using https://ipfs.io/, as a gateway.

+

The following example adds a dependency with an ipfs source.

+
[dependencies]
+custom_lib = { ipfs = "QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG" }
+
+

Once the package is added, running forc build will automatically download added dependencies.

+

Updating dependencies

+

To update dependencies in your Forc directory you can run forc update. For path and ipfs dependencies this will have no effect. For git dependencies with a branch reference, this will update the project to use the latest commit for the given branch.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/forc/index.html b/docs/beta-4/builds/sway/master/book/forc/index.html new file mode 100644 index 000000000..2c9e2aaa0 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/forc/index.html @@ -0,0 +1,201 @@ + + + + + + Forc Reference - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Forc Reference

+

Forc stands for Fuel Orchestrator. Forc provides a variety of tools and commands for developers working with the Fuel ecosystem, such as scaffolding a new project, formatting, running scripts, deploying contracts, testing contracts, and more. If you're coming from a Rust background, forc is similar to cargo.

+

If you are new to Forc, see the Forc Project introduction section.

+

For a comprehensive overview of the Forc CLI commands, see the Commands section.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/forc/manifest_reference.html b/docs/beta-4/builds/sway/master/book/forc/manifest_reference.html new file mode 100644 index 000000000..984d17827 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/forc/manifest_reference.html @@ -0,0 +1,378 @@ + + + + + + Manifest Reference - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Manifest Reference

+

The Forc.toml (the manifest file) is a compulsory file for each package and it is written in [TOML] format. Forc.toml consists of the following fields:

+
    +
  • +

    [project] — Defines a sway project.

    +
      +
    • name — The name of the project.
    • +
    • authors — The authors of the project.
    • +
    • organization — The organization of the project.
    • +
    • license— The project license.
    • +
    • entry — The entry point for the compiler to start parsing from. +
        +
      • For the recomended way of selecting an entry point of large libraries please take a look at: Libraries
      • +
      +
    • +
    • implicit-std - Controls whether provided std version (with the current forc version) will get added as a dependency implicitly. Unless you know what you are doing, leave this as default.
    • +
    • forc-version - The minimum forc version required for this project to work properly.
    • +
    +
  • +
  • +

    [dependencies] — Defines the dependencies.

    +
  • +
  • +

    [network] — Defines a network for forc to interact with.

    +
      +
    • url — URL of the network.
    • +
    +
  • +
  • +

    [build-profile] - Defines the build profiles.

    +
  • +
  • +

    [patch] - Defines the patches.

    +
  • +
  • +

    [contract-dependencies] - Defines the contract dependencies.

    +
  • +
+

The [project] section

+

An example Forc.toml is shown below. Under [project] the following fields are optional:

+
    +
  • authors
  • +
  • organization
  • +
+

Also for the following fields, a default value is provided so omitting them is allowed:

+
    +
  • entry - (default : main.sw)
  • +
  • implicit-std - (default : true)
  • +
+
[project]
+authors = ["user"]
+entry = "main.sw"
+organization = "Fuel_Labs"
+license = "Apache-2.0"
+name = "wallet_contract"
+
+

The [dependencies] section

+

The following fields can be provided with a dependency:

+
    +
  • version - Desired version of the dependency
  • +
  • path - The path of the dependency (if it is local)
  • +
  • git - The URL of the git repo hosting the dependency
  • +
  • branch - The desired branch to fetch from the git repo
  • +
  • tag - The desired tag to fetch from the git repo
  • +
  • rev - The desired rev (i.e. commit hash) reference
  • +
+

Please see dependencies for details

+

The [network] section

+

For the following fields, a default value is provided so omitting them is allowed:

+ +

The [build-profile.*] section

+

The [build-profile] tables provide a way to customize compiler settings such as debug options.

+

The following fields can be provided for a build-profile:

+
    +
  • print-ast - Whether to print out the generated AST or not, defaults to false.
  • +
  • print-dca-graph - Whether to print out the computed DCA graph (in GraphViz DOT format), defaults to false.
  • +
  • print-dca-graph-url-format - The URL format to be used in the generated DOT file, an example for vscode would be: "vscode://file/{path}:{line}:{col}"
  • +
  • print-ir - Whether to compile to bytecode (false) or to print out the generated IR (true), defaults to false.
  • +
  • print-finalized-asm - Whether to compile to bytecode (false) or to print out the generated ASM (true), defaults to false.
  • +
  • print-intermediate-asm - Whether to compile to bytecode (false) or to print out the generated ASM (true), defaults to false.
  • +
  • terse - Terse mode. Limited warning and error output, defaults to false.
  • +
  • time_phases - Whether to output the time elapsed over each part of the compilation process, defaults to false.
  • +
  • include_tests - Whether or not to include test functions in parsing, type-checking and codegen, this is set to true by invocations like forc test, defaults to false.
  • +
  • json_abi_with_callpaths - Whether to json abi with callpaths instead of names for struct and enums, defaults to false.
  • +
  • error_on_warnings - Whether to treat errors as warnings, defaults to false.
  • +
+

There are two default [build-profile] available with every manifest file. These are debug and release profiles. If you want to override these profiles, you can provide them explicitly in the manifest file like the following example:

+
[project]
+authors = ["user"]
+entry = "main.sw"
+organization = "Fuel_Labs"
+license = "Apache-2.0"
+name = "wallet_contract"
+
+[build-profile.debug]
+print-finalized-asm = false
+print-intermediate-asm = false
+print-ir = false
+terse = false
+
+[build-profile.release]
+print-finalized-asm = false 
+print-intermediate-asm = false
+print-ir = false
+terse = true
+
+

Since release and debug implicitly included in every manifest file, you can use them by just passing --release or by not passing anything (debug is default). For using a user defined build profile there is --build-profile <profile name> option available to the relevant commands. (For an example see forc-build)

+

Note that providing the corresponding cli options (like --finalized-asm) will override the selected build profile. For example if you pass both --release and --finalized-asm, release build profile is omitted and resulting build profile would have a structure like the following:

+
print-ast = false
+print-ir = false
+print-finalized-asm = false
+print-intermediate-asm = false
+terse = false
+time-phases = false
+include-tests = false
+json-abi-with-callpaths = false
+error-on-warnings = false
+experimental-private-modules = false
+
+

The [patch] section

+

The [patch] section of Forc.toml can be used to override dependencies with other copies. The example provided below patches https://github.com/fuellabs/sway source with master branch of the same repo.

+
[project]
+authors = ["user"]
+entry = "main.sw"
+organization = "Fuel_Labs"
+license = "Apache-2.0"
+name = "wallet_contract"
+
+[dependencies]
+
+[patch.'https://github.com/fuellabs/sway']
+std = { git = "https://github.com/fuellabs/sway", branch = "test" }
+
+

In the example above, std is patched with the test branch from std repo. You can also patch git dependencies with dependencies defined with a path.

+
[patch.'https://github.com/fuellabs/sway']
+std = { path = "/path/to/local_std_version" }
+
+

Just like std or core you can also patch dependencies you declared with a git repo.

+
[project]
+authors = ["user"]
+entry = "main.sw"
+organization = "Fuel_Labs"
+license = "Apache-2.0"
+name = "wallet_contract"
+
+[dependencies]
+foo = { git = "https://github.com/foo/foo", branch = "master" }
+
+[patch.'https://github.com/foo']
+foo = { git = "https://github.com/foo/foo", branch = "test" }
+
+

Note that each key after the [patch] is a URL of the source that is being patched.

+

The [contract-dependencies] section

+

The [contract-dependenices] table can be used to declare contract dependencies for a Sway contract or script. Contract dependencies are the set of contracts that our contract or script may interact with. Declaring [contract-dependencies] makes it easier to refer to contracts in your Sway source code without having to manually update IDs each time a new version is deployed. Instead, we can use forc to pin and update contract dependencies just like we do for regular library dependencies.

+

Contracts declared under [contract-dependencies] are built and pinned just like regular [dependencies] however rather than importing each contract dependency's entire public namespace we instead import their respective contract IDs as CONTRACT_ID constants available via each contract dependency's namespace root. This means you can use a contract dependency's ID as if it were declared as a pub const in the root of the contract dependency package as demonstrated in the example below.

+

Entries under [contract-dependencies] can be declared in the same way that [dependencies] can be declared. That is, they can refer to the path or git source of another contract. Note that entries under [contract-dependencies] must refer to contracts and will otherwise produce an error.

+

Example Forc.toml:

+
[project]
+authors = ["user"]
+entry = "main.sw"
+organization = "Fuel_Labs"
+license = "Apache-2.0"
+name = "wallet_contract"
+
+[contract-dependencies]
+foo = { path = "../foo" }
+
+

Example usage:

+
script;
+
+fn main() {
+  let foo_id = foo::CONTRACT_ID;
+}
+
+

Because the ID of a contract is computed deterministically, rebuilding the same contract would always result in the same contract ID. Since two contracts with same contract ID cannot be deployed on the blockchain, a "salt" factor is needed to modify the contract ID. For each contract dependency declared under [contract-dependencies], salt can be specified. An example is shown below:

+
[contract-dependencies]
+foo = { path = "../foo", salt = "0x1000000000000000000000000000000000000000000000000000000000000000" }
+
+

For contract dependencies that do not specify any value for salt, a default of all zeros for salt is implicitly applied.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/forc/plugins/forc_client/forc_deploy.html b/docs/beta-4/builds/sway/master/book/forc/plugins/forc_client/forc_deploy.html new file mode 100644 index 000000000..107fcc006 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/forc/plugins/forc_client/forc_deploy.html @@ -0,0 +1,316 @@ + + + + + + forc deploy - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

forc-deploy

+

Build profile options

+

USAGE:

+

forc deploy [OPTIONS] [SIGNING_KEY]

+

ARGS:

+

<SIGNING_KEY> +Set the key to be used for signing

+

OPTIONS:

+

--ast

+

Print the generated Sway AST (Abstract Syntax Tree)

+

--build-profile <BUILD_PROFILE>

+

Name of the build profile to use.

+

If unspecified, forc will use debug build profile.

+

--dca-graph <DCA_GRAPH>

+

Print the computed Sway DCA graph. DCA graph is printed to the specified path. If +specified '' graph is printed to stdout

+

--dca-graph-url-format <DCA_GRAPH_URL_FORMAT>

+

Specifies the url format to be used in the generated dot file. +Variables {path}, {line} {col} can be used in the provided format. +An example for vscode would be: +"vscode://file/{path}:{line}:{col}"

+

--default-salt

+

Generate a default salt +(0x0000000000000000000000000000000000000000000000000000000000000000) for the contract. +Useful for CI, to create reproducable deployments

+

--default-signer

+

Sign the transaction with default signer that is pre-funded by fuel-core. Useful for +testing against local node

+

--error-on-warnings

+

Treat warnings as errors

+

--finalized-asm

+

Print the finalized ASM.

+

This is the state of the ASM with registers allocated and optimisations applied.

+

-g, --output-debug <DEBUG_FILE>

+

If set, outputs source file mapping in JSON format

+

--gas-limit <LIMIT>

+

Gas limit for the transaction

+

--gas-price <PRICE>

+

Gas price for the transaction

+

-h, --help

+

Print help information

+

--intermediate-asm

+

Print the generated ASM.

+

This is the state of the ASM prior to performing register allocation and other ASM +optimisations.

+

--ipfs-node <IPFS_NODE>

+

The IPFS Node to use for fetching IPFS sources.

+

Possible values: PUBLIC, LOCAL, <GATEWAY_URL>

+

--ir

+

Print the generated Sway IR (Intermediate Representation)

+

--json-abi

+

By default the JSON for ABIs is formatted for human readability. By using this option +JSON output will be "minified", i.e. all on one line without whitespace

+

--json-abi-with-callpaths

+

Outputs json abi with callpaths instead of names for struct and enums

+

--json-storage-slots

+

By default the JSON for initial storage slots is formatted for human readability. By +using this option JSON output will be "minified", i.e. all on one line without +whitespace

+

--locked

+

Requires that the Forc.lock file is up-to-date. If the lock file is missing, or it needs +to be updated, Forc will exit with an error

+

--manual-signing

+

Sign the deployment transaction manually

+

--maturity <MATURITY>

+

Block height until which tx cannot be included

+

[default: 0]

+

--metrics-outfile <METRICS_OUTFILE>

+

Output compilation metrics into file

+

--node-url <NODE_URL>

+

The URL of the Fuel node to which we're submitting the transaction. If unspecified, +checks the manifest's network table, then falls back to http://127.0.0.1:4000

+

You can also use --target or --testnet to specify the Fuel node.

+

[env: FUEL_NODE_URL=]

+

-o, --output-bin <BIN_FILE>

+

If set, outputs a binary file representing the script bytes

+

--offline

+

Offline mode, prevents Forc from using the network when managing dependencies. Meaning +it will only try to use previously downloaded dependencies

+

--output-directory <OUTPUT_DIRECTORY>

+

The directory in which the sway compiler output artifacts are placed.

+

By default, this is <project-root>/out.

+

-p, --path <PATH>

+

Path to the project, if not specified, current working directory will be used

+

--release

+

Use release build plan. If a custom release plan is not specified, it is implicitly +added to the manifest file.

+

If --build-profile is also provided, forc omits this flag and uses provided +build-profile.

+

--reverse-order

+

Output build errors and warnings in reverse order

+

--salt <SALT>

+

Optional 256-bit hexadecimal literal(s) to redeploy contracts.

+

For a single contract, use --salt <SALT>, eg.: forc deploy --salt +0x0000000000000000000000000000000000000000000000000000000000000001

+

For a workspace with multiple contracts, use --salt <CONTRACT_NAME>:<SALT> to specify +a salt for each contract, eg.:

+

forc deploy --salt +contract_a:0x0000000000000000000000000000000000000000000000000000000000000001 --salt +contract_b:0x0000000000000000000000000000000000000000000000000000000000000002

+

-t, --terse

+

Terse mode. Limited warning and error output

+

--target <TARGET>

+

Use preset configurations for deploying to a specific target.

+

You can also use --node-url or --testnet to specify the Fuel node.

+

Possible values are: [beta-1, beta-2, beta-3, beta-4, local]

+

--testnet

+

Use preset configuration for the latest testnet.

+

You can also use --node-url or --target to specify the Fuel node.

+

--time-phases

+

Output the time elapsed over each part of the compilation process

+

--unsigned

+

Deprecated in favor of --default-signer

+

-V, --version

+

Print version information

+

EXAMPLE

+

You can use forc deploy, which triggers a contract deployment transaction and sends it to a running node.

+

Alternatively, you can deploy your Sway contract programmatically using fuels-rs, our Rust SDK.

+

You can find an example within our fuels-rs book.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/forc/plugins/forc_client/forc_run.html b/docs/beta-4/builds/sway/master/book/forc/plugins/forc_client/forc_run.html new file mode 100644 index 000000000..423b760f5 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/forc/plugins/forc_client/forc_run.html @@ -0,0 +1,313 @@ + + + + + + forc run - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

forc-run

+

Run script project. Crafts a script transaction then sends it to a running node

+

USAGE:

+

forc run [OPTIONS] [SIGNING_KEY]

+

ARGS:

+

<SIGNING_KEY> +Set the key to be used for signing

+

OPTIONS:

+

--args <ARGS>

+

Arguments to pass into main function with forc run

+

--ast

+

Print the generated Sway AST (Abstract Syntax Tree)

+

--build-profile <BUILD_PROFILE>

+

Name of the build profile to use.

+

If unspecified, forc will use debug build profile.

+

--contract <CONTRACT>

+

32-byte contract ID that will be called during the transaction

+

-d, --data <DATA>

+

Hex string of data to input to script

+

--dca-graph <DCA_GRAPH>

+

Print the computed Sway DCA graph. DCA graph is printed to the specified path. If +specified '' graph is printed to stdout

+

--dca-graph-url-format <DCA_GRAPH_URL_FORMAT>

+

Specifies the url format to be used in the generated dot file. +Variables {path}, {line} {col} can be used in the provided format. +An example for vscode would be: +"vscode://file/{path}:{line}:{col}"

+

--default-signer

+

Sign the transaction with default signer that is pre-funded by fuel-core. Useful for +testing against local node

+

--dry-run

+

Only craft transaction and print it out

+

--error-on-warnings

+

Treat warnings as errors

+

--finalized-asm

+

Print the finalized ASM.

+

This is the state of the ASM with registers allocated and optimisations applied.

+

-g, --output-debug <DEBUG_FILE>

+

If set, outputs source file mapping in JSON format

+

--gas-limit <LIMIT>

+

Gas limit for the transaction

+

--gas-price <PRICE>

+

Gas price for the transaction

+

-h, --help

+

Print help information

+

--intermediate-asm

+

Print the generated ASM.

+

This is the state of the ASM prior to performing register allocation and other ASM +optimisations.

+

--ipfs-node <IPFS_NODE>

+

The IPFS Node to use for fetching IPFS sources.

+

Possible values: PUBLIC, LOCAL, <GATEWAY_URL>

+

--ir

+

Print the generated Sway IR (Intermediate Representation)

+

--json-abi

+

By default the JSON for ABIs is formatted for human readability. By using this option +JSON output will be "minified", i.e. all on one line without whitespace

+

--json-abi-with-callpaths

+

Outputs json abi with callpaths instead of names for struct and enums

+

--json-storage-slots

+

By default the JSON for initial storage slots is formatted for human readability. By +using this option JSON output will be "minified", i.e. all on one line without +whitespace

+

--locked

+

Requires that the Forc.lock file is up-to-date. If the lock file is missing, or it needs +to be updated, Forc will exit with an error

+

--manual-signing

+

Sign the deployment transaction manually

+

--maturity <MATURITY>

+

Block height until which tx cannot be included

+

[default: 0]

+

--metrics-outfile <METRICS_OUTFILE>

+

Output compilation metrics into file

+

--node-url <NODE_URL>

+

The URL of the Fuel node to which we're submitting the transaction. If unspecified, +checks the manifest's network table, then falls back to http://127.0.0.1:4000

+

You can also use --target or --testnet to specify the Fuel node.

+

[env: FUEL_NODE_URL=]

+

-o, --output-bin <BIN_FILE>

+

If set, outputs a binary file representing the script bytes

+

--offline

+

Offline mode, prevents Forc from using the network when managing dependencies. Meaning +it will only try to use previously downloaded dependencies

+

--output-directory <OUTPUT_DIRECTORY>

+

The directory in which the sway compiler output artifacts are placed.

+

By default, this is <project-root>/out.

+

-p, --path <PATH>

+

Path to the project, if not specified, current working directory will be used

+

-r, --pretty-print

+

Pretty-print the outputs from the node

+

--release

+

Use release build plan. If a custom release plan is not specified, it is implicitly +added to the manifest file.

+

If --build-profile is also provided, forc omits this flag and uses provided +build-profile.

+

--reverse-order

+

Output build errors and warnings in reverse order

+

--simulate

+

Execute the transaction and return the final mutated transaction along with receipts +(which includes whether the transaction reverted or not). The transaction is not +inserted in the node's view of the blockchain, (i.e. it does not affect the chain state)

+

-t, --terse

+

Terse mode. Limited warning and error output

+

--target <TARGET>

+

Use preset configurations for deploying to a specific target.

+

You can also use --node-url or --testnet to specify the Fuel node.

+

Possible values are: [beta-1, beta-2, beta-3, beta-4, local]

+

--testnet

+

Use preset configuration for the latest testnet.

+

You can also use --node-url or --target to specify the Fuel node.

+

--time-phases

+

Output the time elapsed over each part of the compilation process

+

--unsigned

+

Deprecated in favor of --default-signer

+

-V, --version

+

Print version information

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/forc/plugins/forc_client/forc_submit.html b/docs/beta-4/builds/sway/master/book/forc/plugins/forc_client/forc_submit.html new file mode 100644 index 000000000..3b3fbd867 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/forc/plugins/forc_client/forc_submit.html @@ -0,0 +1,232 @@ + + + + + + forc submit - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

forc-client

+

A forc plugin for interacting with a Fuel node.

+

USAGE:

+

forc-submit [OPTIONS] <TX_PATH>

+

ARGS:

+

<TX_PATH> +Path to the Transaction that is to be submitted to the Fuel node.

+

Paths to files ending with .json will be deserialized from JSON. Paths to files ending +with .bin will be deserialized from bytes using the +fuel_tx::Transaction::try_from_bytes constructor.

+

OPTIONS:

+

--await <await>

+

Whether or not to await confirmation that the transaction has been committed.

+

When true, await commitment and output the transaction status. When false, do not +await confirmation and simply output the transaction ID.

+

[default: true]

+

-h, --help

+

Print help information

+

--node-url <NODE_URL>

+

The URL of the Fuel node to which we're submitting the transaction. If unspecified, +checks the manifest's network table, then falls back to http://127.0.0.1:4000

+

You can also use --target or --testnet to specify the Fuel node.

+

[env: FUEL_NODE_URL=]

+

--target <TARGET>

+

Use preset configurations for deploying to a specific target.

+

You can also use --node-url or --testnet to specify the Fuel node.

+

Possible values are: [beta-1, beta-2, beta-3, beta-4, local]

+

--testnet

+

Use preset configuration for the latest testnet.

+

You can also use --node-url or --target to specify the Fuel node.

+

--tx-status-json <json>

+

Output the resulting transaction status as JSON rather than the default output

+

[default: false]

+

-V, --version

+

Print version information

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/forc/plugins/forc_client/index.html b/docs/beta-4/builds/sway/master/book/forc/plugins/forc_client/index.html new file mode 100644 index 000000000..c5ce6e000 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/forc/plugins/forc_client/index.html @@ -0,0 +1,257 @@ + + + + + + forc client - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

forc-client

+

Forc plugin for interacting with a Fuel node.

+

Initializing the wallet and adding accounts

+

If you don't have an initialized wallet or any account for your wallet you won't be able to sign transactions.

+

To create a wallet you can use forc wallet new. It will ask you to choose a password to encrypt your wallet. After the initialization is done you will have your mnemonic phrase.

+

After you have created a wallet, you can derive a new account by running forc wallet account new. It will ask your password to decrypt the wallet before deriving an account.

+

Signing transactions using forc-wallet CLI

+

To submit the transactions created by forc deploy or forc run, you need to sign them first (unless you are using a client without UTXO validation). To sign a transaction you can use forc-wallet CLI. This section is going to walk you through the whole signing process.

+

By default fuel-core runs without UTXO validation, this allows you to send invalid inputs to emulate different conditions.

+

If you want to run fuel-core with UTXO validation, you can pass --utxo-validation to fuel-core run.

+

To install forc-wallet please refer to forc-wallet's github repo.

+
    +
  1. Construct the transaction by using either forc deploy or forc run. To do so simply run forc deploy or forc run with your desired parameters. For a list of parameters please refer to the forc-deploy or forc-run section of the book. Once you run either command you will be asked the address of the wallet you are going to be signing with. After the address is given the transaction will be generated and you will be given a transaction ID. At this point CLI will actively wait for you to insert the signature.
  2. +
  3. Take the transaction ID generated in the first step and sign it with forc wallet sign --account <account_index> tx-id <transaction_id>. This will generate a signature.
  4. +
  5. Take the signature generated in the second step and provide it to forc-deploy (or forc-run). Once the signature is provided, the signed transaction will be submitted.
  6. +
+

Other useful commands of forc-wallet

+
    +
  • You can see a list of existing accounts with accounts command.
  • +
+
forc wallet accounts
+
+
    +
  • If you want to retrieve the address for an account by its index you can use account command.
  • +
+
forc wallet account <account_index>
+
+
+

If you want to sign the transaction generated by forc-deploy or forc-run with an account funded by default once you start your local node, you can pass --default-signer to them. Please note that this will only work against your local node.

+
forc-deploy --default-signer
+
+
forc-run --default-signer
+
+
+

By default --default-signer flag would sign your transactions with the following private-key:

+
0xde97d8624a438121b86a1956544bd72ed68cd69f2c99555b08b1e8c51ffd511c
+
+

Interacting with the testnet

+

To interact with the latest testnet, use the --testnet flag. When this flag is passed, transactions created by forc-deploy will be sent to the beta-4 testnet.

+
forc-deploy --testnet
+
+

It is also possible to pass the exact node url while using forc-deploy or forc-run which can be done using --node-url flag.

+
forc-deploy --node-url https://beta-3.fuel.network
+
+

Another alternative is the --target option, which provides useful aliases to all targets. For example if you want to deploy to beta-3 you can use:

+
forc-deploy --target beta-3
+
+

Since deploying and running projects on the testnet cost gas, you will need coins to pay for them. You can get some using the testnet faucet.

+

Deployment Artifacts

+

forc-deploy saves the details of each deployment in the out/deployments folder within the project's root directory. Below is an example of a deployment artifact:

+
{
+  "transaction_id": "0xec27bb7a4c8a3b8af98070666cf4e6ea22ca4b9950a0862334a1830520012f5d",
+  "salt": "0x9e35d1d5ef5724f29e649a3465033f5397d3ebb973c40a1d76bb35c253f0dec7",
+  "network_endpoint": "http://127.0.0.1:4000",
+  "chain_id": 0,
+  "contract_id": "0x767eeaa7af2621e637f9785552620e175d4422b17d4cf0d76335c38808608a7b",
+  "deployment_size": 68,
+  "deployed_block_id": "0x915c6f372252be6bc54bd70df6362dae9bf750ba652bf5582d9b31c7023ca6cf"
+}
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/forc/plugins/forc_doc.html b/docs/beta-4/builds/sway/master/book/forc/plugins/forc_doc.html new file mode 100644 index 000000000..92916e859 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/forc/plugins/forc_doc.html @@ -0,0 +1,224 @@ + + + + + + forc doc - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Forc

+

Usage: forc-doc [OPTIONS]

+

Options:

+

--manifest-path <MANIFEST_PATH>

+

Path to the Forc.toml file. By default, forc-doc searches for the Forc.toml file in the +current directory or any parent directory

+

--document-private-items

+

Include non-public items in the documentation

+

--open

+

Open the docs in a browser after building them

+

--offline

+

Offline mode, prevents Forc from using the network when managing dependencies. Meaning it +will only try to use previously downloaded dependencies

+

-s, --silent

+

Silent mode. Don't output any warnings or errors to the command line

+

--locked

+

Requires that the Forc.lock file is up-to-date. If the lock file is missing, or it needs +to be updated, Forc will exit with an error

+

--no-deps

+

Do not build documentation for dependencies

+

--ipfs-node <IPFS_NODE>

+

The IPFS Node to use for fetching IPFS sources.

+

Possible values: PUBLIC, LOCAL, <GATEWAY_URL>

+

-h, --help

+

Print help (see a summary with '-h')

+

-V, --version

+

Print version

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/forc/plugins/forc_explore.html b/docs/beta-4/builds/sway/master/book/forc/plugins/forc_explore.html new file mode 100644 index 000000000..055b459fe --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/forc/plugins/forc_explore.html @@ -0,0 +1,213 @@ + + + + + + forc explore - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

forc-explore

+

Forc plugin for running the Fuel Block Explorer.

+

USAGE:

+

forc-explore [OPTIONS] [SUBCOMMAND]

+

OPTIONS:

+

-h, --help

+

Print help information

+

-p, --port <PORT>

+

The port number at which the explorer will run on localhost [default: 3030]

+

-V, --version

+

Print version information

+

SUBCOMMANDS:

+

clean

+

Cleans up any existing state associated with the fuel block explorer

+

help

+

Print this message or the help of the given subcommand(s)

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/forc/plugins/forc_fmt.html b/docs/beta-4/builds/sway/master/book/forc/plugins/forc_fmt.html new file mode 100644 index 000000000..355d2dcc6 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/forc/plugins/forc_fmt.html @@ -0,0 +1,218 @@ + + + + + + forc fmt - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

forc-fmt

+

Forc plugin for running the Sway code formatter.

+

USAGE:

+

forc-fmt [OPTIONS] [FILE]

+

ARGS:

+

<FILE> +Formats a single .sw file with the default settings. If not specified, current working +directory will be formatted using a Forc.toml configuration

+

OPTIONS:

+

-c, --check

+

Run in 'check' mode.

+
    +
  • Exits with 0 if input is formatted correctly. - Exits with 1 and prints a diff if +formatting is required.
  • +
+

-h, --help

+

Print help information

+

-p, --path <PATH>

+

Path to the project, if not specified, current working directory will be used

+

-V, --version

+

Print version information

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/forc/plugins/forc_lsp.html b/docs/beta-4/builds/sway/master/book/forc/plugins/forc_lsp.html new file mode 100644 index 000000000..6a94407fc --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/forc/plugins/forc_lsp.html @@ -0,0 +1,200 @@ + + + + + + forc lsp - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

forc-lsp

+

Forc plugin for the Sway LSP (Language Server Protocol) implementation.

+

USAGE:

+

forc-lsp

+

OPTIONS:

+

-h, --help

+

Print help information

+

-V, --version

+

Print version information

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/forc/plugins/index.html b/docs/beta-4/builds/sway/master/book/forc/plugins/index.html new file mode 100644 index 000000000..fec6302b2 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/forc/plugins/index.html @@ -0,0 +1,218 @@ + + + + + + Plugins - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Plugins

+

Plugins can be used to extend forc with new commands that go beyond the native commands mentioned in the previous chapter. While the Fuel ecosystem provides a few commonly useful plugins (forc-fmt, forc-client, forc-lsp, forc-explore), anyone can write their own!

+

Let's install a plugin, forc-explore, and see what's underneath the plugin:

+
cargo install forc-explore
+
+

Check that we have installed forc-explore:

+
$ forc plugins
+Installed Plugins:
+forc-explore
+
+

forc-explore runs the Fuel Network Explorer, which you can run and check out for yourself:

+
$ forc explore
+Fuel Network Explorer 0.1.1
+Running server on http://127.0.0.1:3030
+Server::run{addr=127.0.0.1:3030}: listening on http://127.0.0.1:3030
+
+

You can visit http://127.0.0.1:3030 to check out the network explorer!

+

Note that some plugin crates can also provide more than one command. For example, installing the forc-client plugin provides the forc deploy and forc run commands. This is achieved by specifying multiple [[bin]] targets within the forc-client manifest.

+

Writing your own plugin

+

We encourage anyone to write and publish their own forc plugin to enhance their development experience.

+

Your plugin must be named in the format forc-<MY_PLUGIN> and you may use the above template as a starting point. You can use clap and add more subcommands, options and configurations to suit your plugin's needs.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/forc/workspaces.html b/docs/beta-4/builds/sway/master/book/forc/workspaces.html new file mode 100644 index 000000000..0b64e2c2f --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/forc/workspaces.html @@ -0,0 +1,239 @@ + + + + + + Workspaces - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Workspaces

+

A workspace is a collection of one or more packages, namely workspace members, that are managed together.

+

The key points for workspaces are:

+
    +
  • Common forc commands available for a single package can also be used for a workspace, like forc build or forc deploy.
  • +
  • All packages share a common Forc.lock file which resides in the root directory of the workspace.
  • +
+

Workspace manifests are declared within Forc.toml files and support the following fields:

+
    +
  • members - Packages to include in the workspace.
  • +
  • [patch] - Defines the patches.
  • +
+

An empty workspace can be created with forc new --workspace or forc init --workspace.

+

The members field

+

The members field defines which packages are members of the workspace:

+
[workspace]
+members = ["member1", "path/to/member2"]
+
+

The members field accepts entries to be given in relative path with respect to the workspace root. +Packages that are located within a workspace directory but are not contained within the members set are ignored.

+

The [patch] section

+

The [patch] section can be used to override any dependency in the workspace dependency graph. The usage is the same with package level [patch] section and details can be seen here.

+

It is not allowed to declare patch table in member of a workspace if the workspace manifest file contains a patch table.

+

Example:

+
[workspace]
+members = ["member1", "path/to/member2"]
+
+
+[patch.'https://github.com/fuellabs/sway']
+std = { git = "https://github.com/fuellabs/sway", branch = "test" }
+
+

In the above example each occurance of std as a dependency in the workspace will be changed with std from test branch of sway repo.

+

Some forc commands that support workspaces

+
    +
  • forc build - Builds an entire workspace.
  • +
  • forc deploy - Builds and deploys all deployable members (i.e, contracts) of the workspace in the correct order.
  • +
  • forc run - Builds and runs all scripts of the workspace.
  • +
  • forc check - Checks all members of the workspace.
  • +
  • forc update - Checks and updates workspace level Forc.lock file that is shared between workspace members.
  • +
  • forc clean - Cleans all output artifacts for each member of the workspace.
  • +
  • forc fmt - Formats all members of a workspace.
  • +
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/frontend/index.html b/docs/beta-4/builds/sway/master/book/frontend/index.html new file mode 100644 index 000000000..0b6f83728 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/frontend/index.html @@ -0,0 +1,201 @@ + + + + + + Application Frontend - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + +
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/frontend/typescript_sdk.html b/docs/beta-4/builds/sway/master/book/frontend/typescript_sdk.html new file mode 100644 index 000000000..695b5e663 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/frontend/typescript_sdk.html @@ -0,0 +1,206 @@ + + + + + + TypeScript SDK - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

TypeScript SDK

+

The TypeScript SDK supports common tasks like:

+
    +
  • Deploying and calling contracts
  • +
  • Generating contract types with TypeChain
  • +
  • Building and sending transactions
  • +
  • Encoding and decoding contract ABI
  • +
+

Refer here for full documentation.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/introduction/forc_project.html b/docs/beta-4/builds/sway/master/book/introduction/forc_project.html new file mode 100644 index 000000000..4e03e1284 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/introduction/forc_project.html @@ -0,0 +1,261 @@ + + + + + + A Forc Project - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

A Forc Project

+

To initialize a new project with Forc, use forc new:

+
forc new my-fuel-project
+
+

Here is the project that Forc has initialized:

+ + +
$ cd my-fuel-project
+$ tree .
+├── Forc.toml
+└── src
+    └── main.sw
+
+ + + +

Forc.toml is the manifest file (similar to Cargo.toml for Cargo or package.json for Node), and defines project metadata such as the project name and dependencies.

+ +

For additional information on dependency management, see: here.

+
[project]
+authors = ["User"]
+entry = "main.sw"
+license = "Apache-2.0"
+name = "my-fuel-project"
+
+[dependencies]
+
+

Here are the contents of the only Sway file in the project, and the main entry point, src/main.sw:

+
contract;
+
+abi MyContract {
+    fn test_function() -> bool;
+}
+
+impl MyContract for Contract {
+    fn test_function() -> bool {
+        true
+    }
+}
+
+

The project is a contract, one of four different project types. For additional information on different project types, see here.

+

We now compile our project with forc build, passing the flag --finalized-asm to view the generated assembly:

+
$ forc build --finalized-asm
+...
+.program:
+ji   i4
+noop
+DATA_SECTION_OFFSET[0..32]
+DATA_SECTION_OFFSET[32..64]
+lw   $ds $is 1
+add  $$ds $$ds $is
+lw   $r0 $fp i73              ; load input function selector
+lw   $r1 data_0               ; load fn selector for comparison
+eq   $r2 $r0 $r1              ; function selector comparison
+jnzi $r2 i12                  ; jump to selected function
+movi $$tmp i123               ; special code for mismatched selector
+rvrt $$tmp                    ; revert if no selectors matched
+ret  $one
+.data:
+data_0 .word 559005003
+
+  Compiled contract "my-fuel-project".
+  Bytecode size is 60 bytes.
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/introduction/fuel_toolchain.html b/docs/beta-4/builds/sway/master/book/introduction/fuel_toolchain.html new file mode 100644 index 000000000..ce97ff907 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/introduction/fuel_toolchain.html @@ -0,0 +1,216 @@ + + + + + + The Fuel Toolchain - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

The Fuel Toolchain

+

The Fuel toolchain consists of several components.

+

Forc (forc)

+

The "Fuel Orchestrator" Forc is our equivalent of Rust's Cargo. It is the primary entry point for creating, building, testing, and deploying Sway projects.

+

Sway Language Server (forc-lsp)

+

The Sway Language Server forc-lsp is provided to expose features to IDEs. Installation instructions.

+

Sway Formatter (forc-fmt)

+

A canonical formatter is provided with forc-fmt. Installation instructions. It can be run manually with

+
forc fmt
+
+

The Visual Studio Code plugin will +automatically format Sway files with forc-fmt on save, though you might have to explicitly set the Sway plugin as the +default formatter, like this:

+
"[sway]": {
+  "editor.defaultFormatter": "FuelLabs.sway-vscode-plugin"
+}
+
+

Fuel Core (fuel-core)

+

An implementation of the Fuel protocol, Fuel Core, is provided together with the Sway toolchain to form the Fuel toolchain. The Rust SDK will automatically start and stop an instance of the node during tests, so there is no need to manually run a node unless using Forc directly without the SDK.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/introduction/index.html b/docs/beta-4/builds/sway/master/book/introduction/index.html new file mode 100644 index 000000000..7a1c406a4 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/introduction/index.html @@ -0,0 +1,206 @@ + + + + + + Introduction - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Introduction

+

To get started with Forc and Sway smart contract development, install the Fuel toolchain and Fuel full node and set up your first project.

+ + +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/introduction/installation.html b/docs/beta-4/builds/sway/master/book/introduction/installation.html new file mode 100644 index 000000000..268b6f8b3 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/introduction/installation.html @@ -0,0 +1,331 @@ + + + + + + Installation - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Installation

+

The Sway toolchain is sufficient to compile Sway smart contracts. Otherwise, note that if you want to run Sway smart contracts (e.g. for testing), a Fuel Core full node is required, which is packaged together with the Sway toolchain together as the Fuel toolchain.

+ +

Installing via pre-compiled release binaries is the recommended way to get up and running with the Sway toolchain. Pre-compiled binaries for Linux and macOS are available. Native Windows is currently unsupported (tracking issue for Windows support). Windows Subsystem for Linux should work but is not officially supported.

+

Dependencies

+

A prerequisite for installing and using Sway is the Rust toolchain. Platform-specific instructions for installing rustup can be found here. Then, install the Rust toolchain with:

+
# Install the latest stable Rust toolchain.
+rustup install stable
+
+

The Sway toolchain is built and tested against the stable Rust toolchain version (https://github.com/rust-lang/rust/releases/latest). There is no guarantee it will work with the nightly Rust toolchain, or with earlier stable versions, so ensure you are using stable with:

+
# Update installed Rust toolchain; can be used independently.
+rustup update
+# Set the stable Rust toolchain as default; can be used independently.
+rustup default stable
+
+

Now you're ready to install fuelup, the equivalent of Rust's rustup for the Fuel toolchain. It enables easily downloading binary releases of the Fuel toolchain.

+
    +
  1. +

    Start by installing fuelup with the following command:

    +
    curl --proto '=https' --tlsv1.2 -sSf \
    +https://install.fuel.network/fuelup-init.sh | sh
    +
    +

    This downloads the fuelup-init script to a temp directory on your machine, which installs fuelup. fuelup-init will ask for permission to add ~/.fuelup/bin to your PATH. Otherwise, you can also pass --no-modify-path so that fuelup-init does not modify your PATH:

    +
    curl --proto '=https' --tlsv1.2 -sSf \
    +https://install.fuel.network/fuelup-init.sh | sh -s -- --no-modify-path
    +
    +
  2. +
  3. +

    Once fuelup is installed, fuelup-init automatically runs fuelup toolchain install latest to install the latest toolchain

    +

    You can run fuelup update at anytime to get the most up-to-date toolchain.

    +
  4. +
  5. +

    (Optional) You can optionally install distributed toolchains optimized for different networks.

    +

    To configure the optimal toolchain for beta-3, run the following commands:

    +
    $ fuelup self update
    +Fetching binary from https://github.com/FuelLabs/fuelup/releases/download/v0.18.0/fuelup-0.18.0-aarch64-apple-darwin.tar.gz
    + Downloading component fuelup without verifying checksum
    + Unpacking and moving fuelup to /var/folders/tp/0l8zdx9j4s9_n609ykwxl0qw0000gn/T/.tmpP3HfvR
    + Moving /var/folders/tp/0l8zdx9j4s9_n609ykwxl0qw0000gn/T/.tmpP3HfvR/fuelup to /Users/user/.fuelup/bin/fuelup
    +
    +
    +$ fuelup toolchain install beta-3
    +Downloading: forc forc-explore forc-wallet fuel-core fuel-indexer
    +
    +Adding component forc v0.35.0 to 'beta-3-aarch64-apple-darwin'
    +Fetching binary from https://github.com/FuelLabs/sway/releases/download/v0.35.0/forc-binaries-darwin_arm64.tar.gz
    +npacking and moving forc-doc to /Users/user/.fuelup/toolchains/beta-3-aarch64-apple-darwin/bin
    +Unpacking and moving forc to /Users/user/.fuelup/toolchains/beta-3-aarch64-apple-darwin/bin
    +Unpacking and moving forc-deploy to /Users/user/.fuelup/toolchains/beta-3-aarch64-apple-darwin/bin
    +Unpacking and moving forc-run to /Users/user/.fuelup/toolchains/beta-3-aarch64-apple-darwin/bin
    +Unpacking and moving forc-lsp to /Users/user/.fuelup/toolchains/beta-3-aarch64-apple-darwin/bin
    +Unpacking and moving forc-fmt to /Users/user/.fuelup/toolchains/beta-3-aarch64-apple-darwin/bin
    +Fetching core forc dependencies
    +Installed forc v0.35.0 for toolchain 'beta-3-aarch64-apple-darwin'
    +
    +Adding component forc-explore v0.28.1 to 'beta-3-aarch64-apple-darwin'
    +Fetching binary from https://github.com/FuelLabs/forc-explorer/releases/download/v0.28.1/forc-explore-0.28.1-aarch64-apple-darwin.tar.gz
    +Unpacking and moving forc-explore to /Users/user/.fuelup/toolchains/beta-3-aarch64-apple-darwin/bin
    +Installed forc-explore v0.28.1 for toolchain 'beta-3-aarch64-apple-darwin'
    +
    +Adding component forc-wallet v0.1.3 to 'beta-3-aarch64-apple-darwin'
    +Fetching binary from https://github.com/FuelLabs/forc-wallet/releases/download/v0.1.3/forc-wallet-0.1.3-aarch64-apple-darwin.tar.gz
    +Unpacking and moving forc-wallet to /Users/user/.fuelup/toolchains/beta-3-aarch64-apple-darwin/bin
    +Installed forc-wallet v0.1.3 for toolchain 'beta-3-aarch64-apple-darwin'
    +
    +Adding component fuel-core v0.17.1 to 'beta-3-aarch64-apple-darwin'
    +Fetching binary from https://github.com/FuelLabs/fuel-core/releases/download/v0.17.1/fuel-core-0.17.1-aarch64-apple-darwin.tar.gz
    +Unpacking and moving fuel-core to /Users/user/.fuelup/toolchains/    beta-3-aarch64-apple-darwin/bin
    +Installed fuel-core v0.17.1 for toolchain 'beta-3-aarch64-apple-darwin'
    +
    +Adding component fuel-indexer v0.2.3 to 'beta-3-aarch64-apple-darwin'
    +Fetching binary from https://github.com/FuelLabs/fuel-indexer/releases/download/v0.2.3/fuel-indexer-0.2.3-aarch64-apple-darwin.tar.gz
    +Unpacking and moving fuel-indexer to /Users/user/.fuelup/toolchains/beta-3-aarch64-apple-darwin/bin
    +Installed fuel-indexer v0.2.3 for toolchain 'beta-3-aarch64-apple-darwin'
    +
    +Installed:
    +- forc 0.35.0
    +- forc-explore 0.28.1
    +- forc-wallet 0.1.3
    +- fuel-core 0.17.1
    +- fuel-indexer 0.2.3
    +
    +The Fuel toolchain is installed and up to date
    +
    +
  6. +
+

You're all set to start building!

+

Need Help?

+

You may refer to The Fuelup Book for an in-depth look into fuelup, or check out the tooling section in the Fuel forum if you're running into problems through the installation process. If you don't see your question, post the issue you're running into with as many details as possible and the team will get back to you asap!

+

Installing from Cargo

+

The Sway toolchain and Fuel Core full node can be installed from source with Cargo with:

+
cargo install forc fuel-core
+
+

Updating forc from Cargo

+

You can update the toolchain from source with Cargo with:

+
cargo update forc fuel-core
+
+

Installing forc Plugins from Cargo

+

The Fuel ecosystem has a few plugins which can be easily installed via Cargo.

+
+

Note: forc detects anything in your $PATH prefixed with forc- as a plugin. Use forc plugins to see what you currently have installed.

+
+
# Sway Formatter
+cargo install forc-fmt
+
+# Block Explorer
+cargo install forc-explore
+
+# Sway Language Server
+cargo install forc-lsp
+
+

Installing from Source

+

Rather than installing from cargo, the Sway toolchain can be built from a local source checkout by following instructions at https://github.com/FuelLabs/sway. The Fuel Core full node implementation can be built from source by following instructions at https://github.com/FuelLabs/fuel-core.

+

Enable tab completion for Bash, Fish, Zsh, or PowerShell

+

forc supports generating completion scripts for Bash, Fish, Zsh, and PowerShell. See forc completions --help for full details, but the gist is as simple as using one of the following:

+
# Bash
+forc completions --shell=bash > ~/.local/share/bash-completion/completions/forc
+
+# Bash (macOS/Homebrew)
+forc completions --shell=bash > $(brew --prefix)/etc/bash_completion.d/forc.bash-completion
+
+# Fish
+mkdir -p ~/.config/fish/completions
+forc completions --shell=fish > ~/.config/fish/completions/forc.fish
+
+# Zsh
+forc completions --shell=zsh > ~/.zfunc/_forc
+
+# PowerShell v5.0+
+forc completions --shell=powershell >> $PROFILE.CurrentUserCurrentHost
+# or
+forc completions --shell=powershell | Out-String | Invoke-Expression
+
+

Once the completions have been generated and properly installed, close and reopen your terminal for the new completions to take effect.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/introduction/standard_library.html b/docs/beta-4/builds/sway/master/book/introduction/standard_library.html new file mode 100644 index 000000000..80753c380 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/introduction/standard_library.html @@ -0,0 +1,233 @@ + + + + + + Standard Library - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Standard Library

+ + +

Similar to Rust, Sway comes with its own standard library.

+

The Sway Standard Library is the foundation of portable Sway software, a set of minimal shared abstractions for the broader Sway ecosystem. It offers core types, like Result<T, E> and Option<T>, library-defined operations on language primitives, native asset management, blockchain contextual operations, access control, storage management, and support for types from other VMs, among many other things.

+ +

The entire Sway standard library is a Forc project called std, and is available directly here: https://github.com/FuelLabs/sway/tree/master/sway-lib-std (navigate to the appropriate tagged release if the latest master is not compatible). For the latest std documentation see: https://fuellabs.github.io/sway/master/std/.

+

Using the Standard Library

+

The standard library is made implicitly available to all Forc projects created using forc new. In other words, it is not required to manually specify std as an explicit dependency. Forc will automatically use the version of std that matches its version.

+

Importing items from the standard library can be done using the use keyword, just as importing items from any Sway project. For example:

+
use std::storage::storage_vec::*;
+
+

This imports the StorageVec type into the current namespace.

+

Standard Library Prelude

+ + +

Sway comes with a variety of things in its standard library. However, if you had to manually import every single thing that you used, it would be very verbose. But importing a lot of things that a program never uses isn't good either. A balance needs to be struck.

+

The prelude is the list of things that Sway automatically imports into every Sway program. It's kept as small as possible, and is focused on things which are used in almost every single Sway program.

+

The current version of the prelude lives in std::prelude, and re-exports the following:

+ + + +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/introduction/sway_quickstart.html b/docs/beta-4/builds/sway/master/book/introduction/sway_quickstart.html new file mode 100644 index 000000000..1aa7ffb9a --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/introduction/sway_quickstart.html @@ -0,0 +1,199 @@ + + + + + + Sway Quickstart - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Sway Quickstart

+

Check out the Developer Quickstart Guide for a step-by-step guide on building a fullstack dapp on Fuel. The guide will walk you through writing a smart contract, setting up a wallet, and building a frontend to interact with your contract.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/lsp/features.html b/docs/beta-4/builds/sway/master/book/lsp/features.html new file mode 100644 index 000000000..19b21fdcf --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/lsp/features.html @@ -0,0 +1,222 @@ + + + + + + Features - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Features

+

Code Actions

+

Source: code_actions

+

Quickly generate boilerplate code and code comments for functions, structs, and ABIs.

+

Completion

+

Source: completion.rs

+

Suggests code to follow partially written statements for functions and variables.

+

Diagnostics

+

Source: diagnostic.rs

+

Displays compiler warnings and errors inline.

+

Syntax Highlighting

+

Source: highlight.rs

+

Highlights code based on type and context.

+

Hover

+

Source: hover

+

Provides documentation, compiler diagnostics, and reference links when hovering over functions and variables.

+

Inlay Hints

+

Source: inlay_hints.rs

+

Displays the implied type of a variable next to the variable name. Configurable in Settings.

+

Rename

+

Source: rename.rs

+

Renames a symbol everywhere in the workspace.

+

Run

+

Source: runnable.rs

+

Shows a button above a runnable function or test.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/lsp/index.html b/docs/beta-4/builds/sway/master/book/lsp/index.html new file mode 100644 index 000000000..714ef91ec --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/lsp/index.html @@ -0,0 +1,207 @@ + + + + + + Sway LSP - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Sway LSP

+

Welcome to the documentation for Sway LSP, the language server designed specifically for the Sway programming language. This documentation serves as a comprehensive guide to help you understand and utilize the powerful features provided by Sway LSP.

+

Sway LSP is built on the Language Server Protocol (LSP), a standardized protocol for enabling rich programming language support in editor and IDE environments. It acts as a bridge between your favorite code editor or integrated development environment and the Sway programming language, offering advanced semantic analysis and a wide range of features to enhance your development experience.

+

With Sway LSP, you can expect a seamless and efficient coding experience while working with the Sway programming language. It provides intelligent code completion, precise symbol navigation, type information, and other smart features that empower you to write clean and error-free code. By leveraging the power of Sway LSP, you can increase productivity, reduce debugging time, and write high-quality code with confidence.

+

In this documentation, you will find detailed information about how to set up Sway LSP in your preferred code editor or IDE, configure its settings to match your coding style, and take advantage of its various features. We will guide you through the installation process, provide examples of typical configuration setups, and walk you through the usage of each feature supported by Sway LSP.

+

Whether you are a beginner or an experienced Sway developer, this documentation aims to be your go-to resource for understanding and maximizing the capabilities of Sway LSP. So let's dive in and unlock the full potential of the Sway programming language with Sway LSP!

+ + +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/lsp/installation.html b/docs/beta-4/builds/sway/master/book/lsp/installation.html new file mode 100644 index 000000000..9438a5c84 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/lsp/installation.html @@ -0,0 +1,213 @@ + + + + + + Installation - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Installation

+

The Sway language server is contained in the forc-lsp binary, which is installed as part of the Fuel toolchain. Once installed, it can be used with a variety of IDEs. It must be installed for any of the IDE plugins to work.

+
+

Note: There is no need to manually run forc-lsp (the plugin will automatically start it), however both forc and forc-lsp must be in your $PATH. To check if forc is in your $PATH, type forc --help in your terminal.

+
+

VS Code

+

This is the best supported editor at the moment.

+

You can install the latest release of the plugin from the marketplace.

+

Note that we only support the most recent version of VS Code.

+

vim / neovim

+

Follow the documentation for sway.vim to install.

+

helix

+

Install helix and Sway LSP will work out of the box.

+

Sway support is built into helix using tree-sitter-sway.

+

Emacs

+

Coming soon! Feel free to contribute.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/reference/attributes.html b/docs/beta-4/builds/sway/master/book/reference/attributes.html new file mode 100644 index 000000000..2f1e06b58 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/reference/attributes.html @@ -0,0 +1,228 @@ + + + + + + Attributes - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Attributes

+

The Sway compiler supports a list of attributes that perform various operations that are useful for building, testing and documenting Sway programs. Below is a list of all available attributes:

+

Allow

+

The #[allow(dead_code)] attribute overrides the check for dead code so that violations will go unreported.

+

Doc

+

The #[doc(..)] attribute specifies documentation.

+

Line doc comments beginning with exactly three slashes ///, are interpreted as a special syntax for doc attributes. That is, they are equivalent to writing #[doc("...")] around the body of the comment, i.e., /// Foo turns into #[doc("Foo")]

+

Line comments beginning with //! are doc comments that apply to the module of the source file they are in. That is, they are equivalent to writing #![doc("...")] around the body of the comment. //! module level doc comments should be at the top of Sway files.

+

Documentation can be generated from doc attributes using forc doc.

+

Inline

+

The inline attribute suggests that a copy of the attributed function should be placed in the caller, rather than generating code to call the function where it is defined.

+
+

Note: The Sway compiler automatically inlines functions based on internal heuristics. Incorrectly inlining functions can make the program slower, so this attribute should be used with care.

+
+

The #[inline(never)] attribute suggests that an inline expansion should never be performed.

+

The #[inline(always)] attribute suggests that an inline expansion should always be performed.

+
+

Note: #[inline(..)] in every form is a hint, with no requirements +on the language to place a copy of the attributed function in the caller.

+
+

Payable

+

The lack of #[payable] implies the method is non-payable. When calling an ABI method that is non-payable, the compiler emits an error if the amount of coins forwarded with the call is not guaranteed to be zero. Note that this is strictly a compile-time check and does not incur any runtime cost.

+

Storage

+

In Sway, functions are pure by default but can be opted into impurity via the storage function attribute. The storage attribute may take read and/or write arguments indicating which type of access the function requires.

+

The #[storage(read)] attribute indicates that a function requires read access to the storage.

+

The #[storage(write)] attribute indicates that a function requires write access to the storage.

+

More details in Purity.

+

Test

+

The #[test] attribute marks a function to be executed as a test.

+

The #[test(should_revert)] attribute marks a function to be executed as a test that should revert.

+

More details in Unit Testing.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/reference/compiler_intrinsics.html b/docs/beta-4/builds/sway/master/book/reference/compiler_intrinsics.html new file mode 100644 index 000000000..9efa77b2e --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/reference/compiler_intrinsics.html @@ -0,0 +1,360 @@ + + + + + + Compiler Intrinsics - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Compiler Intrinsics

+

The Sway compiler supports a list of intrinsics that perform various low level operations that are useful for building libraries. Compiler intrinsics should rarely be used but are preferred over asm blocks because they are type-checked and are safer overall. Below is a list of all available compiler intrinsics:

+
+
__size_of_val<T>(val: T) -> u64
+
+

Description: Return the size of type T in bytes.

+

Constraints: None.

+
+
__size_of<T>() -> u64
+
+

Description: Return the size of type T in bytes.

+

Constraints: None.

+
+
__size_of_str_array<T>() -> u64
+
+

Description: Return the size of type T in bytes. This intrinsic differs from __size_of in the case of "string arrays" where the actual length in bytes of the string is returned without padding the byte size to the next word alignment. When T is not a string 0 is returned.

+

Constraints: None.

+
+
__assert_is_str_array<T>()
+
+

Description: Throws a compile error if type T is not a "string array".

+

Constraints: None.

+
+
__to_str_array(s: str) -> str[N]
+
+

Description: Converts a "string slice" to "string array" at compile time. Parameter "s" must be a string literal.

+

Constraints: None.

+
+
__is_reference_type<T>() -> bool
+
+

Description: Returns true if T is a reference type and false otherwise.

+

Constraints: None.

+
+
__is_str_array<T>() -> bool
+
+

Description: Returns true if T is a string array and false otherwise.

+

Constraints: None.

+
+
__eq<T>(lhs: T, rhs: T) -> bool
+
+

Description: Returns whether lhs and rhs are equal.

+

Constraints: T is bool, u8, u16, u32, u64, u256, b256 or raw_ptr.

+
+
__gt<T>(lhs: T, rhs: T) -> bool
+
+

Description: Returns whether lhs is greater than rhs.

+

Constraints: T is u8, u16, u32, u64, u256, b256.

+
+
__lt<T>(lhs: T, rhs: T) -> bool
+
+

Description: Returns whether lhs is less than rhs.

+

Constraints: T is u8, u16, u32, u64, u256, b256.

+
+
__gtf<T>(index: u64, tx_field_id: u64) -> T
+
+

Description: Returns transaction field with ID tx_field_id at index index, if applicable. This is a wrapper around FuelVM's gtf instruction. The resuting field is cast to T.

+

Constraints: None.

+
+
__addr_of<T>(val: T) -> raw_ptr
+
+

Description: Returns the address in memory where val is stored.

+

Constraints: T is a reference type.

+
+
__state_load_word(key: b256) -> u64
+
+

Description: Reads and returns a single word from storage at key key.

+

Constraints: None.

+
+
__state_load_quad(key: b256, ptr: raw_ptr, slots: u64) -> bool
+
+

Description: Reads slots number of slots (b256 each) from storage starting at key key and stores them in memory starting at address ptr. Returns a Boolean describing whether all the storage slots were previously set.

+

Constraints: None.

+
+
__state_store_word(key: b256, val: u64) -> bool
+
+

Description: Stores a single word val into storage at key key. Returns a Boolean describing whether the store slot was previously set.

+

Constraints: None.

+
+
__state_store_quad(key: b256, ptr: raw_ptr, slots: u64) -> bool
+
+

Description: Stores slots number of slots (b256 each) starting at address ptr in memory into storage starting at key key. Returns a Boolean describing whether the first storage slot was previously set.

+

Constraints: None.

+
+
__log<T>(val: T)
+
+

Description: Logs value val.

+

Constraints: None.

+
+
__add<T>(lhs: T, rhs: T) -> T
+
+

Description: Adds lhs and rhs and returns the result.

+

Constraints: T is an integer type, i.e. u8, u16, u32, u64, u256.

+
+
__sub<T>(lhs: T, rhs: T) -> T
+
+

Description: Subtracts rhs from lhs.

+

Constraints: T is an integer type, i.e. u8, u16, u32, u64, u256.

+
+
__mul<T>(lhs: T, rhs: T) -> T
+
+

Description: Multiplies lhs by rhs.

+

Constraints: T is an integer type, i.e. u8, u16, u32, u64, u256.

+
+
__div<T>(lhs: T, rhs: T) -> T
+
+

Description: Divides lhs by rhs.

+

Constraints: T is an integer type, i.e. u8, u16, u32, u64, u256.

+
+
__and<T>(lhs: T, rhs: T) -> T
+
+

Description: Bitwise AND lhs and rhs.

+

Constraints: T is an integer type, i.e. u8, u16, u32, u64, u256, b256.

+
+
__or<T>(lhs: T, rhs: T) -> T
+
+

Description: Bitwise OR lhs and rhs.

+

Constraints: T is an integer type, i.e. u8, u16, u32, u64, u256, b256.

+
+
__xor<T>(lhs: T, rhs: T) -> T
+
+

Description: Bitwise XOR lhs and rhs.

+

Constraints: T is an integer type, i.e. u8, u16, u32, u64, u256, b256.

+
+
__mod<T>(lhs: T, rhs: T) -> T
+
+

Description: Modulo of lhs by rhs.

+

Constraints: T is an integer type, i.e. u8, u16, u32, u64, u256.

+
+
__rsh<T>(lhs: T, rhs: u64) -> T
+
+

Description: Logical right shift of lhs by rhs.

+

Constraints: T is an integer type, i.e. u8, u16, u32, u64, u256, b256.

+
+
__lsh<T>(lhs: T, rhs: u64) -> T
+
+

Description: Logical left shift of lhs by rhs.

+

Constraints: T is an integer type, i.e. u8, u16, u32, u64, u256, b256.

+
+
__revert(code: u64)
+
+

Description: Reverts with error code code.

+

Constraints: None.

+
+
__ptr_add(ptr: raw_ptr, offset: u64)
+
+

Description: Adds offset to the raw value of pointer ptr.

+

Constraints: None.

+
+
__ptr_sub(ptr: raw_ptr, offset: u64)
+
+

Description: Subtracts offset to the raw value of pointer ptr.

+

Constraints: None.

+
+
__smo<T>(recipient: b256, data: T, coins: u64)
+
+

Description: Sends a message data of arbitrary type T and coins amount of the base asset to address recipient.

+

Constraints: None.

+
+
__not(op: T) -> T
+
+

Description: Bitwise NOT of op

+

Constraints: T is an integer type, i.e. u8, u16, u32, u64, u256, b256.

+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/reference/contributing_to_sway.html b/docs/beta-4/builds/sway/master/book/reference/contributing_to_sway.html new file mode 100644 index 000000000..2e2520a7d --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/reference/contributing_to_sway.html @@ -0,0 +1,273 @@ + + + + + + Contributing To Sway - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Contributing To Sway

+

Thanks for your interest in contributing to Sway! This document outlines the process for installing and setting up the Sway toolchain for development, as well as some conventions on contributing to Sway.

+

If you run into any difficulties getting started, you can always ask questions on our Discourse.

+

Building and setting up a development workspace

+

See the introduction section for instructions on installing and setting up the Sway toolchain.

+

Getting the repository

+
    +
  1. Visit the Sway repo and fork the project.
  2. +
  3. Then clone your forked copy to your local machine and get to work.
  4. +
+
git clone https://github.com/FuelLabs/sway
+cd sway
+
+

Building and testing

+

The following steps will run the sway test suite and ensure that everything is set up correctly.

+

First, open a new terminal and start fuel-core with:

+
fuel-core
+
+

Then open a second terminal, cd into the sway repo and run:

+
cargo run --bin test
+
+

After the test suite runs, you should see:

+
Tests passed.
+_n_ tests run (0 skipped)
+
+

Congratulations! You've now got everything setup and are ready to start making contributions.

+

Finding something to work on

+

There are many ways in which you may contribute to the Sway project, some of which involve coding knowledge and some which do not. A few examples include:

+
    +
  • Reporting bugs
  • +
  • Adding documentation to the Sway book
  • +
  • Adding new features or bugfixes for which there is already an open issue
  • +
  • Making feature requests
  • +
+

Check out our Help Wanted, Sway Book or Good First Issue issues to find a suitable task.

+

If you are planning something big, for example, related to multiple components or changes current behaviors, make sure to open an issue to discuss with us before starting on the implementation.

+

Contribution flow

+

This is a rough outline of what a contributor's workflow looks like:

+
    +
  • Make sure what you want to contribute is already tracked as an issue. +
      +
    • We may discuss the problem and solution in the issue.
    • +
    +
  • +
  • Create a Git branch from where you want to base your work. This is usually master.
  • +
  • Write code, add test cases, and commit your work.
  • +
  • Run tests and make sure all tests pass.
  • +
  • If the PR contains any breaking changes, add the breaking label to your PR.
  • +
  • Push your changes to a branch in your fork of the repository and submit a pull request. +
      +
    • Make sure mention the issue, which is created at step 1, in the commit message.
    • +
    +
  • +
  • Your PR will be reviewed and some changes may be requested. +
      +
    • Once you've made changes, your PR must be re-reviewed and approved.
    • +
    • If the PR becomes out of date, you can use GitHub's 'update branch' button.
    • +
    • If there are conflicts, you can merge and resolve them locally. Then push to your PR branch. +Any changes to the branch will require a re-review.
    • +
    +
  • +
  • Our CI system (Github Actions) automatically tests all authorized pull requests.
  • +
  • Use Github to merge the PR once approved.
  • +
+

Thanks for your contributions!

+

Linking issues

+

Pull requests should be linked to at least one issue in the same repo.

+

If the pull request resolves the relevant issues, and you want GitHub to close these issues automatically after it merged into the default branch, you can use the syntax (KEYWORD #ISSUE-NUMBER) like this:

+
close #123
+
+

If the pull request links an issue but does not close it, you can use the keyword ref like this:

+
ref #456
+
+

Multiple issues should use full syntax for each issue and separate by a comma, like:

+
close #123, ref #456
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/reference/index.html b/docs/beta-4/builds/sway/master/book/reference/index.html new file mode 100644 index 000000000..eadda7a82 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/reference/index.html @@ -0,0 +1,208 @@ + + + + + + Sway Reference - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + +
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/reference/keywords.html b/docs/beta-4/builds/sway/master/book/reference/keywords.html new file mode 100644 index 000000000..ed41d669e --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/reference/keywords.html @@ -0,0 +1,280 @@ + + + + + + Keywords - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Keywords

+

The following list contains keywords that are reserved for current or +future use by the Sway language. As such, they cannot be used as +identifiers. Identifiers are names of functions, variables, +parameters, modules, constants, attributes, types or +traits, ect.

+

Keywords Currently in Use

+

The following is a list of keywords currently in use, with their +functionality described.

+
    +
  • as - rename items in use statements, eg use type::a as alias_name
  • +
  • abi - defines a smart contract ABI in a syntactcally similar way to traits
  • +
  • break - exit a loop immediately
  • +
  • const - define constant items
  • +
  • continue - continue to the next loop iteration
  • +
  • else - used in conjunction with if conditions for control flow constructs
  • +
  • enum - define an enumeration
  • +
  • false - Boolean false literal
  • +
  • fn- define a function or the function pointer type
  • +
  • if - branch based on the result of a conditional expression
  • +
  • impl - implement inherent or trait functionality
  • +
  • let - bind a variable
  • +
  • match - exhaustfully match a value to patterns
  • +
  • mod - define a module
  • +
  • mut - denote mutability in references, or pattern bindings
  • +
  • pub - denote public visibility of Sway data structures, traits, or modules
  • +
  • ref - bind by reference
  • +
  • return - return early from a function
  • +
  • Self - a type alias for the type we are defining or implementing
  • +
  • self - method subject
  • +
  • struct - define a structure
  • +
  • trait - define a trait
  • +
  • true - Boolean true literal
  • +
  • type - define a type alias or associated type
  • +
  • use - bring symbols into scope
  • +
  • where - specifies traits for generic types
  • +
  • while - loop conditionally based on the result of an expression
  • +
+

Keywords Reserved for Possible Future Use

+
    +
  • abstract
  • +
  • async
  • +
  • await
  • +
  • become
  • +
  • box
  • +
  • do
  • +
  • dyn
  • +
  • extern
  • +
  • for
  • +
  • in
  • +
  • loop
  • +
  • macro
  • +
  • move
  • +
  • override
  • +
  • priv
  • +
  • static
  • +
  • super
  • +
  • try
  • +
  • typeof
  • +
  • unsafe
  • +
  • unsized
  • +
  • virtual
  • +
  • yield
  • +
+

Special Keywords

+

Program Keywords

+

Keywords associated with defining the type of Sway program to compile

+
    +
  • contract - analogous to a deployed API with some database state
  • +
  • library - Sway code that defines new common behavior
  • +
  • predicate - programs that return a Boolean value and which represent ownership of some resource upon execution to true
  • +
  • script - a runnable bytecode on the chain, which executes once to preform a task
  • +
+

Attribute Keywords

+

Keywords associated with defining the funcitonallity of attributes

+
    +
  • allow - overrides checks that would otherwise result in errors or warnings
  • +
  • doc - specifies documentation
  • +
  • inline - suggests that a copy of the attributed function should be placed in the caller, rather than generating code to call the function where it is defined
  • +
  • payable - implies method is payable for compile time
  • +
  • storage - declaration that contains a list of stored variables
  • +
  • test - marks a function to be executed as a test
  • +
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/reference/known_issues_and_workarounds.html b/docs/beta-4/builds/sway/master/book/reference/known_issues_and_workarounds.html new file mode 100644 index 000000000..88414a692 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/reference/known_issues_and_workarounds.html @@ -0,0 +1,210 @@ + + + + + + Known Issues and Workarounds - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Known Issues and Workarounds

+

Known Issues

+
    +
  • #870: All impl blocks need to be defined before any of the functions they define can be called. This includes sibling functions in the same impl declaration, i.e., functions in an impl can't call each other yet.
  • +
+

Missing Features

+
    +
  • #1182 Arrays in a storage block are not yet supported. See the Manual Storage Management section for details on how to use store and get from the standard library to manage storage slots directly. Note, however, that StorageMap<K, V> does support arbitrary types for K and V without any limitations.
  • +
+

General

+
    +
  • No compiler optimization passes have been implemented yet, therefore bytecode will be more expensive and larger than it would be in production. Note that eventually the optimizer will support zero-cost abstractions, avoiding the need for developers to go down to inline assembly to produce optimal code.
  • +
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/reference/rust_differences.html b/docs/beta-4/builds/sway/master/book/reference/rust_differences.html new file mode 100644 index 000000000..f99ec7ddd --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/reference/rust_differences.html @@ -0,0 +1,224 @@ + + + + + + Differences From Rust - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Differences From Rust

+

Sway shares a lot with Rust, especially its syntax. Because they are so similar, you may be surprised or caught off guard when they differ. This page serves to outline, from a high level, some of the syntactic gotchas that you may encounter.

+

Enum Variant Syntax

+

In Rust, enums generally take one of three forms: unit variants, which have no inner data, struct variants, which contain named fields, and tuple variants, which contain within them a tuple of data. If you are unfamiliar with these terms, this is what they look like:

+
// note to those skimming the docs: this is Rust syntax! Not Sway! Don't copy/paste this into a Sway program.
+
+enum Foo {
+    UnitVariant,
+    TupleVariant(u32, u64, bool),
+    StructVariant {
+        field_one: bool,
+        field_two: bool
+    }
+}
+

In Sway, enums are simplified. Enums variants must all specify exactly one type. This type represents their interior data. This is actually isomorphic to what Rust offers, just with a different syntax. I'll now rewrite the above enum but with Sway syntax:

+
// This is equivalent Sway syntax for the above Rust enum.
+enum Foo {
+    UnitVariant: (),
+    TupleVariant: (u32, u64, bool),
+    StructVariant: MyStruct,
+}
+
+struct MyStruct {
+    field_one: bool,
+    field_two: bool,
+}
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/reference/solidity_differences.html b/docs/beta-4/builds/sway/master/book/reference/solidity_differences.html new file mode 100644 index 000000000..1c5b3b044 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/reference/solidity_differences.html @@ -0,0 +1,216 @@ + + + + + + Differences From Solidity - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Differences From Solidity

+

This page outlines some of the critical differences between Sway and Solidity, and between the FuelVM and the EVM.

+

Underlying Virtual Machine

+

The underlying virtual machine targeted by Sway is the FuelVM, specified here. Solidity targets the Ethereum Virtual Machine (EVM), specified here.

+

Word Size

+

Words in the FuelVM are 64 bits (8 bytes), rather than the 256 bits (32 bytes) of the EVM. Therefore, all primitive integers smaller and including u64 are stored in registers; u256, being bigger than the registers, and hashes (the b256 type) are not stored in registers but rather in memory. They are therefore pointers to a 32-byte memory region containing the their data.

+

Unsigned Integers Only

+

Only unsigned integers are provided as primitives: u8, u16, u32, u64, and u256. Signed integer arithmetic is not available in the FuelVM. Signed integers and signed integer arithmetic can be implemented in high-level libraries if needed.

+

Global Revert

+

Panics in the FuelVM (called "reverts" in Solidity and the EVM) are global, i.e. they cannot be caught. A panic will completely and unconditionally revert the stateful effects of a transaction, minus gas used.

+

Default Safe Math

+ + +

Math in the FuelVM is by default safe (i.e. any overflow or exception is a panic). Safety checks are performed natively in the VM implementation, rather than at the bytecode level like Solidity's default safe math.

+ +

No* Code Size Limit

+

There is no practical code size limit to Sway contracts. The physical limit is governed by the VM_MAX_RAM VM parameter, which at the time of writing is 64 MiB.

+

Account Types

+

Account types in the FuelVM have type-safe wrappers around primitive b256 hashes to clearly distinguish their respective types. The wrapper Address mirrors that of an EOA (Externally Owned Account) and has the ability to hold UTXOs in the context of the EVM. The other wrapper, ContractId, reflects that of a deployed contract in the EVM but cannot hold UTXOs.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/reference/style_guide.html b/docs/beta-4/builds/sway/master/book/reference/style_guide.html new file mode 100644 index 000000000..2ad532079 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/reference/style_guide.html @@ -0,0 +1,203 @@ + + + + + + Style Guide - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Style Guide

+

Capitalization

+ + +

In Sway, structs, traits, and enums are CapitalCase. Modules, variables, and functions are snake_case, constants are SCREAMING_SNAKE_CASE. The compiler will warn you if your capitalization is ever unidiomatic.

+ + +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/sway-program-types/index.html b/docs/beta-4/builds/sway/master/book/sway-program-types/index.html new file mode 100644 index 000000000..14848283d --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/sway-program-types/index.html @@ -0,0 +1,212 @@ + + + + + + Program Types - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Sway Program Types

+ + +

A Sway program itself has a type: it is either a contract, a predicate, a script, or a library. The first three of these things are all deployable to the blockchain. A library is simply a project designed for code reuse and is never directly deployed to the chain.

+

Every Sway file must begin with a declaration of what type of program it is. A project can have many libraries within it, but only one contract, script, or predicate. Scripts and predicates require main functions to serve as entry points, while contracts instead publish an ABI. This chapter will go into detail about all of these various types of programs and what purposes they serve.

+ +

Contracts are used primarily for protocols or systems that operate within a fixed set of rules. A good example would be a staking contract or a decentralized exchange.

+

Scripts are used for complex on-chain interactions that won't persist. An example of this may be using a DEX and Lender to create a leveraged position (borrow, swap, re-collateralize, borrow) which is a complex transaction that would usually take multiple steps.

+

Libraries are for code that is reusable and useful for handling common situations. A good example of this would be a library to handle fixed-point math or big number math.

+ + +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/sway-program-types/libraries.html b/docs/beta-4/builds/sway/master/book/sway-program-types/libraries.html new file mode 100644 index 000000000..f22f49105 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/sway-program-types/libraries.html @@ -0,0 +1,359 @@ + + + + + + Libraries - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Libraries

+ + +

Libraries in Sway are files used to define new common behavior.

+ +

The most prominent example of this is the Sway Standard Library that is made implicitly available to all Forc projects created using forc new.

+

Writing Libraries

+ + +

Libraries are defined using the library keyword at the beginning of a file, followed by a name so that they can be imported.

+ +
library;
+
+// library code
+
+

A good reference library to use when learning library design is the Sway Standard Library. For example, the standard library offers an implementation of enum Option<T> which is a generic type that represents either the existence of a value using the variant Some(..) or a value's absence using the variant None. The Sway file implementing Option<T> has the following structure:

+
    +
  • The library keyword:
  • +
+
library;
+
+
    +
  • A use statement that imports revert from another library inside the standard library:
  • +
+
use ::revert::revert;
+
+
    +
  • The enum definition which starts with the keyword pub to indicate that this Option<T> is publically available outside the option library:
  • +
+
pub enum Option<T> {
+    // variants
+}
+
+
    +
  • An impl block that implements some methods for Option<T>:
  • +
+
impl<T> Option<T> {
+
+    fn is_some(self) -> bool {
+        // body of is_some
+    }
+
+    // other methods
+}
+
+

Now that the library option is fully written, and because Option<T> is defined with the pub keyword, we are now able to import Option<T> using use std::option::Option; from any Sway project and have access to all of its variants and methods. That being said, Option is automatically available in the standard library prelude so you never actually have to import it manually.

+

Libraries are composed of just a Forc.toml file and a src directory, unlike contracts which usually contain a tests directory and a Cargo.toml file as well. An example of a library's Forc.toml:

+
[project]
+authors = ["Fuel Labs <contact@fuel.sh>"]
+entry = "lib.sw"
+license = "Apache-2.0"
+name = "my_library"
+
+[dependencies]
+
+

which denotes the authors, an entry file, the name by which it can be imported, and any dependencies.

+

For large libraries, it is recommended to have a lib.sw entry point re-export all other sub-libraries.

+ + +

The mod keyword registers a submodule, making its items (such as functions and structs) accessible from the parent library. +If used at the top level it will refer to a file in the src folder and in other cases in a folder named after the library in which it is defined.

+ +

For example, the lib.sw of the standard library looks like:

+
library;
+
+mod block;
+mod storage;
+mod constants;
+mod vm;
+// .. Other deps
+
+

with other libraries contained in the src folder, like the vm library (inside of src/vm.sw):

+
library;
+
+mod evm;
+// ...
+
+

and it's own sub-library evm located in src/vm/evm.sw:

+
library;
+
+// ...
+
+

Using Libraries

+

There are two types of Sway libraries, based on their location and how they can be imported.

+

Internal Libraries

+

Internal libraries are located within the project's src directory alongside +main.sw or in the appropriate folders as shown below:

+
$ tree
+.
+├── Cargo.toml
+├── Forc.toml
+└── src
+    ├── internal_lib.sw
+    ├── main.sw
+    └── internal_lib
+        └── nested_lib.sw
+
+

As internal_lib is an internal library, it can be imported into main.sw as follows:

+
    +
  • Use the mod keyword followed by the library name to make the internal library a dependancy
  • +
  • Use the use keyword with a :: separating the name of the library and the imported item(s)
  • +
+
mod internal_lib; // Assuming the library name in `internal_lib.sw` is `internal_lib`
+
+use internal_lib::mint;
+
+// `mint` from `internal_library` is now available in this file
+
+

External Libraries

+

External libraries are located outside the main src directory as shown below:

+
$ tree
+.
+├── my_project
+│   ├── Cargo.toml
+│   ├── Forc.toml
+│   └─── src
+│       └── main.sw
+│
+└── external_lib
+    ├── Cargo.toml
+    ├── Forc.toml
+    └─── src
+        └── lib.sw
+
+

As external_lib is outside the src directory of my_project, it needs to be added as a dependency in the Forc.toml file of my_project, by adding the library path in the dependencies section as shown below, before it can be imported:

+
[dependencies]
+external_library = { path = "../external_library" }
+
+

Once the library dependency is added to the toml file, you can import items from it as follows:

+
    +
  • Make sure the item you want imported are declared with the pub keyword (if applicable, for instance: pub fn mint() {})
  • +
  • Use the use keyword to selectively import items from the library
  • +
+
use external_library::mint;
+
+// `mint` from `external_library` is now available in this file
+
+

Wildcard imports using * are supported, but it is generally recommended to use explicit imports where possible.

+
+

Note: the standard library is implicitly available to all Forc projects, that is, you are not required to manually specify std as an explicit dependency in Forc.toml.

+
+

Reference Sway Libraries

+

The repository sway-libs is a collection of external libraries that you can import and make use of in your Fuel applications. These libraries are meant to be implementations of common use-cases valuable for dapp development.

+

Some Sway Libraries to try out:

+ +

Example

+

You can import and use a Sway Library such as the Ownership library just like any other external library.

+
use ownership::Ownership;
+
+

Once imported, you can use the following basic functionality of the library in your smart contract:

+
    +
  • Declaring an owner
  • +
  • Changing ownership
  • +
  • Renouncing ownership
  • +
  • Ensuring a function may only be called by the owner
  • +
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/sway-program-types/predicates.html b/docs/beta-4/builds/sway/master/book/sway-program-types/predicates.html new file mode 100644 index 000000000..23264de6c --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/sway-program-types/predicates.html @@ -0,0 +1,209 @@ + + + + + + Predicates - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Predicates

+

From the perspective of Sway, predicates are programs that return a Boolean value and which represent ownership of some resource upon execution to true. They have no access to contract storage. Here is a trivial predicate, which always evaluates to true:

+
predicate;
+
+// All predicates require a main function which returns a Boolean value.
+fn main() -> bool {
+    true
+}
+
+

Debugging Predicates

+

Because they don't have any side effects (they are pure), predicates cannot create receipts. Therefore, they cannot have logging or create a stack backtrace. This means that there is no native way to debug them aside from using a single-stepping debugger (which is a work-in-progress).

+

As a workaround, the predicate can be written, tested, and debugged first as a script, and then changed back into a predicate.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/sway-program-types/scripts.html b/docs/beta-4/builds/sway/master/book/sway-program-types/scripts.html new file mode 100644 index 000000000..b99fade6d --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/sway-program-types/scripts.html @@ -0,0 +1,222 @@ + + + + + + Scripts - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Scripts

+

A script is runnable bytecode on the chain which executes once to perform some task. It does not represent ownership of any resources and it cannot be called by a contract. A script can return a single value of any type.

+

Scripts are state-aware in that while they have no persistent storage (because they only exist during the transaction) they can call contracts and act based upon the returned values and results.

+

This example script calls a contract:

+
script;
+
+use std::constants::ZERO_B256;
+use wallet_abi::Wallet;
+
+fn main() {
+    let contract_address = 0x9299da6c73e6dc03eeabcce242bb347de3f5f56cd1c70926d76526d7ed199b8b;
+    let caller = abi(Wallet, contract_address);
+    let amount_to_send = 200;
+    let recipient_address = Address::from(0x9299da6c73e6dc03eeabcce242bb347de3f5f56cd1c70926d76526d7ed199b8b);
+    caller.send_funds {
+        gas: 10000,
+        coins: 0,
+        asset_id: ZERO_B256,
+    }(amount_to_send, recipient_address);
+}
+
+

Scripts, similar to predicates, rely on a main() function as an entry point. You can call other functions defined in a script from the main() function or call another contract via an abi cast.

+

An example use case for a script would be a router that trades funds through multiple DEXes to get the price for the input asset, or a script to re-adjust a Collateralized Debt Position via a flashloan.

+

Scripts and the SDKs

+

Unlike EVM transactions which can call a contract directly (but can only call a single contract), Fuel transactions execute a script, which may call zero or more contracts. The Rust and TypeScript SDKs provide functions to call contract methods as if they were calling contracts directly. Under the hood, the SDKs wrap all contract calls with scripts that contain minimal code to simply make the call and forward script data as call parameters.

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/sway-program-types/smart_contracts.html b/docs/beta-4/builds/sway/master/book/sway-program-types/smart_contracts.html new file mode 100644 index 000000000..e27f7bd5a --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/sway-program-types/smart_contracts.html @@ -0,0 +1,319 @@ + + + + + + Contracts - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

What is a Smart Contract?

+ + +

A smart contract is no different than a script or predicate in that it is a piece of bytecode that is deployed to the blockchain via a transaction. The main features of a smart contract that differentiate it from scripts or predicates are that it is callable and stateful. Put another way, a smart contract is analogous to a deployed API with some database state.

+ +

The interface of a smart contract, also just called a contract, must be defined strictly with an ABI declaration. See this contract for an example.

+

Syntax of a Smart Contract

+

As with any Sway program, the program starts with a declaration of what program type it is. A contract must also either define or import an ABI declaration and implement it.

+ + +

It is considered good practice to define your ABI in a separate library and import it into your contract. This allows callers of your contract to simply import the ABI directly and use it in their scripts to call your contract.

+ +

Let's take a look at an ABI declaration in a library:

+
library;
+
+abi Wallet {
+    #[storage(read, write), payable]
+    fn receive_funds();
+
+    #[storage(read, write)]
+    fn send_funds(amount_to_send: u64, recipient_address: Address);
+}
+
+

Let's focus on the ABI declaration and inspect it line-by-line.

+

The ABI Declaration

+
abi Wallet {
+    #[storage(read, write), payable]
+    fn receive_funds();
+
+    #[storage(read, write)]
+    fn send_funds(amount_to_send: u64, recipient_address: Address);
+}
+
+
+

In the first line, abi Wallet {, we declare the name of this Application Binary Interface, or ABI. We are naming this ABI Wallet. To import this ABI into either a script for calling or a contract for implementing, you would use

+
use wallet_abi::Wallet;
+
+
+

In the second line,

+
    #[storage(read, write), payable]
+    fn receive_funds();
+
+

we are declaring an ABI method called receive_funds which, when called, should receive funds into this wallet. Note that we are simply defining an interface here, so there is no function body or implementation of the function. We only need to define the interface itself. In this way, ABI declarations are similar to trait declarations. This particular ABI method does not take any parameters.

+
+

In the third line,

+
    #[storage(read, write)]
+    fn send_funds(amount_to_send: u64, recipient_address: Address);
+
+

we are declaring another ABI method, this time called send_funds. It takes two parameters: the amount to send, and the address to send the funds to.

+
+

Note: The ABI methods receive_funds and send_funds also require the annotation #[storage(read, write)] because their implementations require reading and writing a storage variable that keeps track of the wallet balance, as we will see shortly. Refer to Purity for more information on storage annotations.

+
+

Implementing an ABI for a Smart Contract

+

Now that we've discussed how to define the interface, let's discuss how to use it. We will start by implementing the above ABI for a specific contract.

+

Implementing an ABI for a contract is accomplished with impl <ABI name> for Contract syntax. The for Contract syntax can only be used to implement an ABI for a contract; implementing methods for a struct should use impl Foo syntax.

+
impl Wallet for Contract {
+    #[storage(read, write), payable]
+    fn receive_funds() {
+        if msg_asset_id() == BASE_ASSET_ID {
+            // If we received `BASE_ASSET_ID` then keep track of the balance.
+            // Otherwise, we're receiving other native assets and don't care
+            // about our balance of tokens.
+            storage.balance.write(storage.balance.read() + msg_amount());
+        }
+    }
+
+    #[storage(read, write)]
+    fn send_funds(amount_to_send: u64, recipient_address: Address) {
+        let sender = msg_sender().unwrap();
+        match sender {
+            Identity::Address(addr) => assert(addr == OWNER_ADDRESS),
+            _ => revert(0),
+        };
+
+        let current_balance = storage.balance.read();
+        assert(current_balance >= amount_to_send);
+
+        storage.balance.write(current_balance - amount_to_send);
+
+        // Note: `transfer_to_address()` is not a call and thus not an
+        // interaction. Regardless, this code conforms to
+        // checks-effects-interactions to avoid re-entrancy.
+        transfer_to_address(recipient_address, BASE_ASSET_ID, amount_to_send);
+    }
+}
+
+

You may notice once again the similarities between traits and ABIs. And, indeed, as a bonus, you can define methods in addition to the interface surface of an ABI, just like a trait. These pre-implemented ABI methods automatically become available as part of the contract interface that implements the corresponding ABI.

+

Note that the above implementation of the ABI follows the Checks, Effects, Interactions pattern.

+

Calling a Smart Contract from a Script

+
+

Note: In most cases, calling a contract should be done from the Rust SDK or the TypeScript SDK which provide a more ergonomic UI for interacting with a contract. However, there are situations where manually writing a script to call a contract is required.

+
+

Now that we have defined our interface and implemented it for our contract, we need to know how to actually call our contract. Let's take a look at a contract call:

+
script;
+
+use std::constants::ZERO_B256;
+use wallet_abi::Wallet;
+
+fn main() {
+    let contract_address = 0x9299da6c73e6dc03eeabcce242bb347de3f5f56cd1c70926d76526d7ed199b8b;
+    let caller = abi(Wallet, contract_address);
+    let amount_to_send = 200;
+    let recipient_address = Address::from(0x9299da6c73e6dc03eeabcce242bb347de3f5f56cd1c70926d76526d7ed199b8b);
+    caller.send_funds {
+        gas: 10000,
+        coins: 0,
+        asset_id: ZERO_B256,
+    }(amount_to_send, recipient_address);
+}
+
+

The main new concept is the abi cast: abi(AbiName, contract_address). This returns a ContractCaller type which can be used to call contracts. The methods of the ABI become the methods available on this contract caller: send_funds and receive_funds. We then directly call the contract ABI method as if it was just a regular method. You also have the option of specifying the following special parameters inside curly braces right before the main list of parameters:

+
    +
  1. gas: a u64 that represents the gas being forwarded to the contract when it is called.
  2. +
  3. coins: a u64 that represents how many coins are being forwarded with this call.
  4. +
  5. asset_id: a b256 that represents the ID of the asset type of the coins being forwarded.
  6. +
+

Each special parameter is optional and assumes a default value when skipped:

+
    +
  1. The default value for gas is the context gas (i.e. the content of the special register $cgas). Refer to the FuelVM specifications for more information about context gas.
  2. +
  3. The default value for coins is 0.
  4. +
  5. The default value for asset_id is ZERO_B256.
  6. +
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/testing/index.html b/docs/beta-4/builds/sway/master/book/testing/index.html new file mode 100644 index 000000000..dd381d4f3 --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/testing/index.html @@ -0,0 +1,210 @@ + + + + + + Testing - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Testing

+

Sway aims to provide facilities for both unit testing and integration testing.

+

Unit testing refers to "in-language" testing which can be triggered via the +forc test command. Sway unit testing is currently a high-priority +work-in-progress, you can follow along at this +issue.

+

Integration testing refers to the testing of your Sway project's integration +within some wider application. You can add integration testing to your Sway+Rust +projects today using the cargo generate template and Rust SDK.

+ + +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/testing/testing-with-rust.html b/docs/beta-4/builds/sway/master/book/testing/testing-with-rust.html new file mode 100644 index 000000000..8efe9a74e --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/testing/testing-with-rust.html @@ -0,0 +1,435 @@ + + + + + + Testing with Rust - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Testing with Rust

+

A common use of Sway is for writing contracts or scripts that exist as part of a +wider Rust application. In order to test the interaction between our Sway code +and our Rust code we can add integration testing.

+

Adding Rust Integration Testing

+

To add Rust integration testing to a Forc project we can use the sway-test-rs +cargo generate +template. +This template makes it easy for Sway devs to add the boilerplate required when +setting up their Rust integration testing.

+

Let's add a Rust integration test to the fresh project we created in the +introduction.

+

1. Enter the project

+

To recap, here's what our empty project looks like:

+
$ cd my-fuel-project
+$ tree .
+├── Forc.toml
+└── src
+    └── main.sw
+
+

2. Install cargo generate

+

We're going to add a Rust integration test harness using a cargo generate +template. Let's make sure we have the cargo generate command installed!

+
cargo install cargo-generate
+
+
+

Note: You can learn more about cargo generate by visiting its +repository.

+
+

3. Generate the test harness

+

Let's generate the default test harness with the following:

+
cargo generate --init fuellabs/sway templates/sway-test-rs --name my-fuel-project --force
+
+

--force forces your --name input to retain your desired casing for the {{project-name}} +placeholder in the template. Otherwise, cargo-generate automatically converts it to kebab-case. +With --force, this means that both my_fuel_project and my-fuel-project are valid project names, +depending on your needs.

+

If all goes well, the output should look as follows:

+
⚠️   Favorite `fuellabs/sway` not found in config, using it as a git repository: https://github.com/fuellabs/sway
+🤷   Project Name : my-fuel-project
+🔧   Destination: /home/user/path/to/my-fuel-project ...
+🔧   Generating template ...
+[1/3]   Done: Cargo.toml
+[2/3]   Done: tests/harness.rs
+[3/3]   Done: tests
+🔧   Moving generated files into: `/home/user/path/to/my-fuel-project`...
+✨   Done! New project created /home/user/path/to/my-fuel-project
+
+

Let's have a look at the result:

+
$ tree .
+├── Cargo.toml
+├── Forc.toml
+├── src
+│   └── main.sw
+└── tests
+    └── harness.rs
+
+

We have two new files!

+
    +
  • The Cargo.toml is the manifest for our new test harness and specifies the +required dependencies including fuels the Fuel Rust SDK.
  • +
  • The tests/harness.rs contains some boilerplate test code to get us started, +though doesn't call any contract methods just yet.
  • +
+

4. Build the forc project

+

Before running the tests, we need to build our contract so that the necessary +ABI, storage and bytecode artifacts are available. We can do so with forc build:

+
$ forc build
+  Creating a new `Forc.lock` file. (Cause: lock file did not exist)
+    Adding core
+    Adding std git+https://github.com/fuellabs/sway?tag=v0.24.5#e695606d8884a18664f6231681333a784e623bc9
+   Created new lock file at /home/user/path/to/my-fuel-project/Forc.lock
+  Compiled library "core".
+  Compiled library "std".
+  Compiled contract "my-fuel-project".
+  Bytecode size is 60 bytes.
+
+

At this point, our project should look like the following:

+
$ tree
+├── Cargo.toml
+├── Forc.lock
+├── Forc.toml
+├── out
+│   └── debug
+│       ├── my-fuel-project-abi.json
+│       ├── my-fuel-project.bin
+│       └── my-fuel-project-storage_slots.json
+├── src
+│   └── main.sw
+└── tests
+    └── harness.rs
+
+

We now have an out directory with our required JSON files!

+
+

Note: This step may no longer be required in the future as we plan to +enable the integration testing to automatically build the artifacts as +necessary so that files like the ABI JSON are always up to date.

+
+

5. Build and run the tests

+

Now we're ready to build and run the default integration test.

+
$ cargo test
+    Updating crates.io index
+   Compiling version_check v0.9.4
+   Compiling proc-macro2 v1.0.46
+   Compiling quote v1.0.21
+   ...
+   Compiling fuels v0.24.0
+   Compiling my-fuel-project v0.1.0 (/home/user/path/to/my-fuel-project)
+    Finished test [unoptimized + debuginfo] target(s) in 1m 03s
+     Running tests/harness.rs (target/debug/deps/integration_tests-373971ac377845f7)
+
+running 1 test
+test can_get_contract_id ... ok
+
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.36s
+
+
+

Note: The first time we run cargo test, cargo will spend some time +fetching and building the dependencies for Fuel's Rust SDK. This might take a +while, but only the first time!

+
+

If all went well, we should see some output that looks like the above!

+

Writing Tests

+

Now that we've learned how to setup Rust integration testing in our project, +let's try to write some of our own tests!

+

First, let's update our contract code with a simple counter example:

+
contract;
+
+abi TestContract {
+    #[storage(write)]
+    fn initialize_counter(value: u64) -> u64;
+
+    #[storage(read, write)]
+    fn increment_counter(amount: u64) -> u64;
+}
+
+storage {
+    counter: u64 = 0,
+}
+
+impl TestContract for Contract {
+    #[storage(write)]
+    fn initialize_counter(value: u64) -> u64 {
+        storage.counter.write(value);
+        value
+    }
+
+    #[storage(read, write)]
+    fn increment_counter(amount: u64) -> u64 {
+        let incremented = storage.counter.read() + amount;
+        storage.counter.write(incremented);
+        incremented
+    }
+}
+
+

To test our initialize_counter and increment_counter contract methods from +the Rust test harness, we could update our tests/harness.rs file with the +following:

+ +
use fuels::{prelude::*, types::ContractId};
+
+// Load abi from json
+abigen!(TestContract, "out/debug/my-fuel-project-abi.json");
+
+async fn get_contract_instance() -> (TestContract, ContractId) {
+    // Launch a local network and deploy the contract
+    let mut wallets = launch_custom_provider_and_get_wallets(
+        WalletsConfig::new(
+            Some(1),             /* Single wallet */
+            Some(1),             /* Single coin (UTXO) */
+            Some(1_000_000_000), /* Amount per coin */
+        ),
+        None,
+    )
+    .await;
+    let wallet = wallets.pop().unwrap();
+
+    let id = Contract::load_from(
+        "./out/debug/my-fuel-project.bin",
+        LoadConfiguration::default().set_storage_configuration(
+            StorageConfiguration::load_from(
+                "./out/debug/my-fuel-project-storage_slots.json",
+            )
+            .unwrap(),
+        ),
+    )
+    .unwrap()
+    .deploy(&wallet, TxParameters::default())
+    .await
+    .unwrap();
+
+    let instance = TestContract::new(id.to_string(), wallet);
+
+    (instance, id.into())
+}
+
+#[tokio::test]
+async fn initialize_and_increment() {
+    let (contract_instance, _id) = get_contract_instance().await;
+    // Now you have an instance of your contract you can use to test each function
+
+    let result = contract_instance
+        .methods()
+        .initialize_counter(42)
+        .call()
+        .await
+        .unwrap();
+
+    assert_eq!(42, result.value);
+
+    // Call `increment_counter()` method in our deployed contract.
+    let result = contract_instance
+        .methods()
+        .increment_counter(10)
+        .call()
+        .await
+        .unwrap();
+
+    assert_eq!(52, result.value);
+}
+

Let's build our project once more and run the test:

+
forc build
+
+
$ cargo test
+   Compiling my-fuel-project v0.1.0 (/home/mindtree/programming/sway/my-fuel-project)
+    Finished test [unoptimized + debuginfo] target(s) in 11.61s
+     Running tests/harness.rs (target/debug/deps/integration_tests-373971ac377845f7)
+
+running 1 test
+test initialize_and_increment ... ok
+
+test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.25s
+
+

When cargo runs our test, our test uses the SDK to spin up a local in-memory +Fuel network, deploy our contract to it, and call the contract methods via the +ABI.

+

You can add as many functions decorated with #[tokio::test] as you like, and +cargo test will automatically test each of them!

+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/builds/sway/master/book/testing/unit-testing.html b/docs/beta-4/builds/sway/master/book/testing/unit-testing.html new file mode 100644 index 000000000..8d482787b --- /dev/null +++ b/docs/beta-4/builds/sway/master/book/testing/unit-testing.html @@ -0,0 +1,331 @@ + + + + + + Unit Testing - The Sway Programming Language + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + +
+
+

Unit Testing

+ + +

Forc provides built-in support for building and executing tests for a package.

+

Tests are written as free functions with the #[test] attribute.

+ +

For example:

+
#[test]
+fn test_meaning_of_life() {
+    assert(6 * 7 == 42);
+}
+
+

Each test function is ran as if it were the entry point for a +script. Tests "pass" if they return +successfully, and "fail" if they revert or vice versa while testing failure.

+

If the project has failing tests forc test will exit with exit status 101.

+

Building and Running Tests

+

We can build and execute all tests within a package with the following:

+
forc test
+
+

The output should look similar to this:

+
  Compiled library "core".
+  Compiled library "std".
+  Compiled library "lib_single_test".
+  Bytecode size is 92 bytes.
+   Running 1 tests
+      test test_meaning_of_life ... ok (170.652µs)
+   Result: OK. 1 passed. 0 failed. Finished in 1.564996ms.
+
+

Visit the forc test command reference to find +the options available for forc test.

+

Testing Failure

+ + +

Forc supports testing failing cases for test functions declared with #[test(should_revert)].

+ +

For example:

+
#[test(should_revert)]
+fn test_meaning_of_life() {
+    assert(6 * 6 == 42);
+}
+
+

It is also possible to specify an expected revert code, like the following example.

+
#[test(should_revert = "18446744073709486084")]
+fn test_meaning_of_life() {
+    assert(6 * 6 == 42);
+}
+
+

Tests with #[test(should_revert)] considered to be passing if they are reverting.

+

Calling Contracts

+

Unit tests can call contract functions an example for such calls can be seen below.

+
contract;
+
+abi MyContract {
+    fn test_function() -> bool;
+}
+
+impl MyContract for Contract {
+    fn test_function() -> bool {
+        true
+    }
+}
+
+

To test the test_function(), a unit test like the following can be written.

+
#[test]
+fn test_success() {
+    let caller = abi(MyContract, CONTRACT_ID);
+    let result = caller.test_function {}();
+    assert(result == true)
+}
+
+

It is also possible to test failure with contract calls as well.

+
#[test(should_revert)]
+fn test_fail() {
+    let caller = abi(MyContract, CONTRACT_ID);
+    let result = caller.test_function {}();
+    assert(result == false)
+}
+
+ + +
+

Note: When running forc test, your contract will be built twice: first without unit tests in order to determine the contract's ID, then a second time with unit tests with the CONTRACT_ID provided to their namespace. This CONTRACT_ID can be used with the abi cast to enable contract calls within unit tests.

+
+ +

Unit tests can call methods of external contracts if those contracts are added as contract dependencies, i.e. in the the contract-dependencies section of the manifest file. An example of such calls is shown below:

+
contract;
+
+abi CallerContract {
+    fn test_false() -> bool;
+}
+
+impl CallerContract for Contract {
+    fn test_false() -> bool {
+        false
+    }
+}
+
+abi CalleeContract {
+    fn test_true() -> bool;
+}
+
+#[test]
+fn test_multi_contract_calls() {
+    let caller = abi(CallerContract, CONTRACT_ID);
+    let callee = abi(CalleeContract, callee::CONTRACT_ID);
+
+    let should_be_false = caller.test_false();
+    let should_be_true = callee.test_true();
+    assert(!should_be_false);
+    assert(should_be_true);
+}
+
+

Example Forc.toml for contract above:

+
[project]
+authors = ["Fuel Labs <contact@fuel.sh>"]
+entry = "main.sw"
+license = "Apache-2.0"
+name = "caller"
+
+[dependencies]
+std = { path = "../../../sway-lib-std/" }
+
+[contract-dependencies]
+callee = { path = "../callee" }
+
+

Running Tests in Parallel or Serially

+ + +

By default, all unit tests in your project are run in parallel. Note that this does not lead to any data races in storage because each unit test has its own storage space that is not shared by any other unit test.

+ +

By default, forc test will use all the available threads in your system. To request that a specific number of threads be used, the flag --test-threads <val> can be provided to forc test.

+
forc test --test-threads 1
+
+ +
+ + +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + diff --git a/docs/beta-4/fuel-core/deployment/scripts/chainspec/beta_chainspec.json b/docs/beta-4/fuel-core/deployment/scripts/chainspec/beta_chainspec.json new file mode 100644 index 000000000..8decded77 --- /dev/null +++ b/docs/beta-4/fuel-core/deployment/scripts/chainspec/beta_chainspec.json @@ -0,0 +1,205 @@ +{ + "chain_name": "Testnet Beta 4", + "block_gas_limit": 30000000, + "initial_state": { + "coins": [ + { + "owner": "0xa1184d77d0d08a064e03b2bd9f50863e88faddea4693a05ca1ee9b1732ea99b7", + "amount": "0x1000000000000000", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0xb5566df884bee4e458151c2fe4082c8af38095cc442c61e0dc83a371d70d88fd", + "amount": "0x1000000000000000", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0x9da7247e1d63d30d69f136f0f8654ee8340362c785b50f0a60513c7edbf5bb7c", + "amount": "0x1000000000000000", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0x4b2ca966aad1a9d66994731db5138933cf61679107c3cde2a10d9594e47c084e", + "amount": "0x1000000000000000", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0x26183fbe7375045250865947695dfc12500dcc43efb9102b4e8c4d3c20009dcb", + "amount": "0x1000000000000000", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0x81f3a10b61828580d06cc4c7b0ed8f59b9fb618be856c55d33decd95489a1e23", + "amount": "0x1000000000000000", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + { + "owner": "0x587aa0482482efea0234752d1ad9a9c438d1f34d2859b8bef2d56a432cb68e33", + "amount": "0x1000000000000000", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + ] + }, + "transaction_parameters": { + "contract_max_size": 16777216, + "max_inputs": 255, + "max_outputs": 255, + "max_witnesses": 255, + "max_gas_per_tx": 10000000, + "max_script_length": 1048576, + "max_script_data_length": 1048576, + "max_storage_slots": 255, + "max_predicate_length": 1048576, + "max_predicate_data_length": 1048576, + "max_gas_per_predicate": 10000000, + "gas_price_factor": 92, + "gas_per_byte": 4, + "max_message_data_length": 1048576, + "chain_id": 0 + }, + "gas_costs": { + "add": 1, + "addi": 1, + "aloc": 1, + "and": 1, + "andi": 1, + "bal": 13, + "bhei": 1, + "bhsh": 1, + "burn": 132, + "cb": 1, + "cfei": 1, + "cfsi": 1, + "croo": 16, + "div": 1, + "divi": 1, + "eck1": 951, + "ecr1": 3000, + "ed19": 3000, + "eq": 1, + "exp": 1, + "expi": 1, + "flag": 1, + "gm": 1, + "gt": 1, + "gtf": 1, + "ji": 1, + "jmp": 1, + "jne": 1, + "jnei": 1, + "jnzi": 1, + "jmpf": 1, + "jmpb": 1, + "jnzf": 1, + "jnzb": 1, + "jnef": 1, + "jneb": 1, + "k256": 11, + "lb": 1, + "log": 9, + "lt": 1, + "lw": 1, + "mcpi": 33, + "mint": 135, + "mlog": 1, + "mod": 1, + "modi": 1, + "move": 1, + "movi": 1, + "mroo": 2, + "mul": 1, + "muli": 1, + "mldv": 1, + "noop": 1, + "not": 1, + "or": 1, + "ori": 1, + "ret_contract": 13, + "rvrt_contract": 13, + "s256": 2, + "sb": 1, + "scwq": 13, + "sll": 1, + "slli": 1, + "srl": 1, + "srli": 1, + "srw": 12, + "sub": 1, + "subi": 1, + "sw": 1, + "sww": 43, + "swwq": 44, + "time": 1, + "tr": 105, + "tro": 60, + "wdcm": 1, + "wqcm": 1, + "wdop": 1, + "wqop": 1, + "wdml": 1, + "wqml": 1, + "wddv": 1, + "wqdv": 2, + "wdmd": 3, + "wqmd": 4, + "wdam": 2, + "wqam": 3, + "wdmm": 3, + "wqmm": 3, + "xor": 1, + "xori": 1, + "call": { + "base": 144, + "dep_per_unit": 214 + }, + "ccp": { + "base": 15, + "dep_per_unit": 103 + }, + "csiz": { + "base": 17, + "dep_per_unit": 790 + }, + "ldc": { + "base": 15, + "dep_per_unit": 272 + }, + "logd": { + "base": 26, + "dep_per_unit": 64 + }, + "mcl": { + "base": 1, + "dep_per_unit": 3333 + }, + "mcli": { + "base": 1, + "dep_per_unit": 3333 + }, + "mcp": { + "base": 1, + "dep_per_unit": 2000 + }, + "meq": { + "base": 1, + "dep_per_unit": 2500 + }, + "retd_contract": { + "base": 29, + "dep_per_unit": 62 + }, + "smo": { + "base": 209, + "dep_per_unit": 55 + }, + "srwq": { + "base": 47, + "dep_per_unit": 5 + } + }, + "consensus": { + "PoA": { + "signing_key": "f65d6448a273b531ee942c133bb91a6f904c7d7f3104cdaf6b9f7f50d3518871" + } + } +} \ No newline at end of file diff --git a/docs/beta-4/fuel-core/deployment/scripts/chainspec/dev_chainspec.json b/docs/beta-4/fuel-core/deployment/scripts/chainspec/dev_chainspec.json new file mode 100644 index 000000000..689970283 --- /dev/null +++ b/docs/beta-4/fuel-core/deployment/scripts/chainspec/dev_chainspec.json @@ -0,0 +1,175 @@ +{ + "chain_name": "Testnet", + "block_gas_limit": 10000000, + "initial_state": { + "coins": [ + { + "owner": "0x53a9c6a74bee79c5e04115a007984f4bddaafed75f512f68766c6ed59d0aedec", + "amount": "0x0004000000000000", + "asset_id": "0x0000000000000000000000000000000000000000000000000000000000000000" + } + ] + }, + "transaction_parameters": { + "contract_max_size": 16777216, + "max_inputs": 255, + "max_outputs": 255, + "max_witnesses": 255, + "max_gas_per_tx": 10000000, + "max_script_length": 1048576, + "max_script_data_length": 1048576, + "max_storage_slots": 255, + "max_predicate_length": 1048576, + "max_predicate_data_length": 1048576, + "max_gas_per_predicate": 10000000, + "gas_price_factor": 1000000000, + "gas_per_byte": 4, + "max_message_data_length": 1048576, + "chain_id": 0 + }, + "gas_costs": { + "add": 1, + "addi": 1, + "aloc": 1, + "and": 1, + "andi": 1, + "bal": 13, + "bhei": 1, + "bhsh": 1, + "burn": 132, + "cb": 1, + "cfei": 1, + "cfsi": 1, + "croo": 16, + "div": 1, + "divi": 1, + "eck1": 951, + "ecr1": 3000, + "ed19": 3000, + "eq": 1, + "exp": 1, + "expi": 1, + "flag": 1, + "gm": 1, + "gt": 1, + "gtf": 1, + "ji": 1, + "jmp": 1, + "jne": 1, + "jnei": 1, + "jnzi": 1, + "jmpf": 1, + "jmpb": 1, + "jnzf": 1, + "jnzb": 1, + "jnef": 1, + "jneb": 1, + "k256": 11, + "lb": 1, + "log": 9, + "lt": 1, + "lw": 1, + "mcpi": 33, + "mint": 135, + "mlog": 1, + "mod": 1, + "modi": 1, + "move": 1, + "movi": 1, + "mroo": 2, + "mul": 1, + "muli": 1, + "mldv": 1, + "noop": 1, + "not": 1, + "or": 1, + "ori": 1, + "ret_contract": 13, + "rvrt_contract": 13, + "s256": 2, + "sb": 1, + "scwq": 13, + "sll": 1, + "slli": 1, + "srl": 1, + "srli": 1, + "srw": 12, + "sub": 1, + "subi": 1, + "sw": 1, + "sww": 43, + "swwq": 44, + "time": 1, + "tr": 105, + "tro": 60, + "wdcm": 1, + "wqcm": 1, + "wdop": 1, + "wqop": 1, + "wdml": 1, + "wqml": 1, + "wddv": 1, + "wqdv": 2, + "wdmd": 3, + "wqmd": 4, + "wdam": 2, + "wqam": 3, + "wdmm": 3, + "wqmm": 3, + "xor": 1, + "xori": 1, + "call": { + "base": 144, + "dep_per_unit": 214 + }, + "ccp": { + "base": 15, + "dep_per_unit": 103 + }, + "csiz": { + "base": 17, + "dep_per_unit": 790 + }, + "ldc": { + "base": 15, + "dep_per_unit": 272 + }, + "logd": { + "base": 26, + "dep_per_unit": 64 + }, + "mcl": { + "base": 1, + "dep_per_unit": 3333 + }, + "mcli": { + "base": 1, + "dep_per_unit": 3333 + }, + "mcp": { + "base": 1, + "dep_per_unit": 2000 + }, + "meq": { + "base": 1, + "dep_per_unit": 2500 + }, + "retd_contract": { + "base": 29, + "dep_per_unit": 62 + }, + "smo": { + "base": 209, + "dep_per_unit": 55 + }, + "srwq": { + "base": 47, + "dep_per_unit": 5 + } + }, + "consensus": { + "PoA": { + "signing_key": "f65d6448a273b531ee942c133bb91a6f904c7d7f3104cdaf6b9f7f50d3518871" + } + } +} \ No newline at end of file diff --git a/docs/beta-4/fuel-graphql-docs/.gitignore b/docs/beta-4/fuel-graphql-docs/.gitignore new file mode 100644 index 000000000..c87c9b392 --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/.gitignore @@ -0,0 +1,36 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/docs/beta-4/fuel-graphql-docs/docs/how-to-use-graphql.mdx b/docs/beta-4/fuel-graphql-docs/docs/how-to-use-graphql.mdx new file mode 100644 index 000000000..3a948c88e --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/docs/how-to-use-graphql.mdx @@ -0,0 +1,10 @@ +--- +title: How To Use GraphQL +category: How To Use GraphQL +--- + +# How To Use GraphQL + +This section covers the fundamentals for how to use a GraphQL API. + +For further documentation and resources about GraphQL, check out the offical GraphQL Documenation at [graphql.org](https://graphql.org/). diff --git a/docs/beta-4/fuel-graphql-docs/docs/how-to-use-graphql/apis-explained.mdx b/docs/beta-4/fuel-graphql-docs/docs/how-to-use-graphql/apis-explained.mdx new file mode 100644 index 000000000..043b5850c --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/docs/how-to-use-graphql/apis-explained.mdx @@ -0,0 +1,193 @@ +--- +title: Schema & Type System +category: How To Use GraphQL +--- + +# Schema & Type System + +Unlike traditional REST APIs, GraphQL comes with a strong type system to describe your API. A GraphQL schema describes the data you can query using the API endpoint by defining a set of types and fields that are mapped to those types. + +Read along to learn about various GraphQL types. + +## Object Types + +Object types in GraphQL describe an object with underlying fields that can be queried from your API endpoint. + +As an example, an object type can be defined as shown below: + +```graphql +type actors { + name: String! + appearsIn: [movie!]! +} +``` + +Here,`actors` is an object type and `name` and `appearsIn` are fields mapped to type `actors`. + +## Scalar Types + +> From The GraphQL Documentation: + +In the example for object types above, field `name` is of type `String`. String in GraphQL is by default a scalar type. This means that it resolves to a definite value and cannot have further sub-fields while querying. Scalar types represent the leaves of a query. + +GraphQL comes with a set of default scalar types out-of-the-box such as below: + +- `Int`: A signed 32‐bit integer. +- `Float`: A signed double-precision floating-point value. +- `String`: A UTF‐8 character sequence. +- `Boolean`: true or false. +- `ID`: The ID scalar type represents a unique identifier, often used to refetch an object or as the key for a cache. The ID type is serialized in the same way as a String; however, defining it as an ID signifies that it is not intended to be human‐readable. + +Fields can also be of types that are not scalar by default, but resolve to scalar values upon querying. For instance, in the following query, the `name` and `appearsIn` fields resolve to scalar types. + +```graphql +{ + hero { + name + appearsIn + } +} +``` + +This is because in the schema, `name` and `appearIn` do not have further queryable sub-fields as described below: + +```graphql +{ + "data": { + "hero": { + "name": "R2-D2", + "appearsIn": [ + "NEWHOPE", + "EMPIRE", + "JEDI" + ] + } + } +} +``` + +## Lists and Non-nulls + +> From the GraphQL documentation: + +Object types, scalars, and enums are the only kinds of types you can define in GraphQL. But when you use the types in other parts of the schema, or in your query variable declarations, you can apply additional type modifiers that affect validation of those values. + +Let's look at an example: + +```graphql +type Character { + name: String! + appearsIn: [Episode]! +} +``` + +Here, we're using a String type and marking it as Non-Null by adding an exclamation mark `!` after the type name. This means that our server always expects to return a non-null value for this field, and if it ends up getting a null value that will actually trigger a GraphQL execution error, letting the client know that something has gone wrong. + +The Non-Null type modifier can also be used when defining arguments for a field, causing the GraphQL server to return a validation error if a null value is passed either in the GraphQL string or the variables. + +```graphql +query DroidById($id: ID!) { + droid(id: $id) { + name + } +} +{ + "id": null +} +``` + +```graphql +{ + "errors": [ + { + "message": "Variable \"$id\" of non-null type \"ID!\" must not be null.", + "locations": [ + { + "line": 1, + "column": 17 + } + ] + } + ] +} +``` + +```graphql +myField: [String!] +``` + +This means that the list itself can be null, but it can't have any null members. For example, in JSON: + +```json +myField: null // valid +myField: [] // valid +myField: ['a', 'b'] // valid +myField: ['a', null, 'b'] // error + +``` + +## Union types + +When a query returns a union type, you can use `... on` to specify the query fields for a certain return type. These are also called inline fragments. For example, the `hero` query below returns a union type of either `Droid` or `Human`. + +```graphql +query HeroForEpisode($ep: Episode!) { + hero(episode: $ep) { + name + ... on Droid { + primaryFunction + } + ... on Human { + height + } + } +} +``` + +## Connections + +Connections are a type of response used whenever you are expecting multiple results that may require pagination. Each query return type that ends in "Connection" will include the following return fields: + +```graphql +pageInfo: PageInfo! +edges: [SomethingEdge!]! +nodes: [Something!]! +``` + +### PageInfo + +`pageInfo` returns an object that includes information about the returned page of results: + +`hasPreviousPage: Boolean!` +Whether or not the result has a previous page. + +`hasNextPage: Boolean!` +Whether or not the result has another page after it. + +`startCursor: String` +The starting cursor that identifies the first page. + +`endCursor: String` +The end cursor that identifies the last page. + +### Edges + +`edges` returns an array of edge objects, which includes the cursor and first node for that page. You can use this data to help with pagination. + +### Nodes + +`nodes` returns an array of whichever type you are expecting paginated results for. + +### Arguments + +Each of these queries also accepts the following arguments: +`first: Int` +`after: String` +`last: Int` +`before: String` + +`first` and `last` both accept an integer, which sets the number of results returned for each page. `first` will paginate the results starting at the beginning, while `last` will start from the end. It is required to pass an argument for either `first` or `last`. If no argument is given, the query will not return any results. + +`after` and `before` both accept a cursor, which you can use to request different pages. These are both optional arguments. + +You can learn more about the connection model and pagination in the official GraphQL docs here: https://graphql.org/learn/pagination/ diff --git a/docs/beta-4/fuel-graphql-docs/docs/how-to-use-graphql/what-is-graphql.mdx b/docs/beta-4/fuel-graphql-docs/docs/how-to-use-graphql/what-is-graphql.mdx new file mode 100644 index 000000000..48dc486d8 --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/docs/how-to-use-graphql/what-is-graphql.mdx @@ -0,0 +1,70 @@ +--- +title: What is GraphQL? +category: How To Use GraphQL +--- + +# What is GraphQL? + +## HTTP and APIs Explained + +HTTP is a protocol, or a definite set of rules, for accessing resources on the web. Resources could mean anything from HTML files to data from a database, photos, text, and so on. + +These resources are made available to us via an Application Programming Interface (API) and we make requests to these APIs via the HTTP protocol. It is the mechanism that allows developers to request resources. + +Read more about HTTP methods, client-server architecture, and why you need APIs [here](https://www.freecodecamp.org/news/http-request-methods-explained/). + +## How does GraphQL work? + +> Note: This section goes over how GraphQL works under the hood, but it is not necessary to know this as a developer building on Fuel. Schema definition, resolver logic, etc. are all written and maintained by the contributors at Fuel Labs. + +GraphQL is a query language and specification that describes how you can communicate with your API. GraphQL is not constrained by programming languages, backend frameworks, and databases. GraphQL uses the HTTP protocol under the hood, so you can map GraphQL operations back to simple `GET`, `POST`, `PUT`, or `DELETE` operations. You can view the GraphQL documentation here: https://graphql.org/. + +A GraphQL API works by defining types and the properties available on those types, also known as the schema, and defining functions that specify the logic for how to resolve those types. A resolver is a function that's responsible for populating the data for a single field in your schema. Whenever a client queries for a particular field, the resolver for that field fetches the requested data from the appropriate data source. + +For example, as an API developer you could define a type, `Car` and define the properties that will be query-able on that type such as below: + +```graphql +type Car { + id: ID + color: String + year: Int + isNew: Boolean +} +``` + +Fuel Labs created a GraphQL API endpoint for the Fuel Network, allowing developers to make complex queries for data on the blockchain. You can leverage these queries to populate a frontend application with details that your users might be interested in like the history of their transactions, their balance of a specific token, etc. + +### GraphQL Queries + +Queries in GraphQL allow you to read data. GraphQL lets you ask for specific data and returns exactly what you asked for. It also lets you request multiple resources in a single query instead of writing a separate 'GET' request for each resource as with REST APIs. + +GraphQL also facilitates more complex queries and operations such as pagination, sort, filter, full-text search, and more. + +Sample query: + +```graphql +query Actor { + actor { + name { + appearIn + } + } +} +``` + +The above query gives you a response with the name of the actor along with the name of the movie(s) they appear in. + +### GraphQL Mutations + +Mutations in GraphQL are write operations that update the chain's state. In addition to being able to traverse objects and their fields, GraphQL gives developers the ability to pass arguments to fields in order to filter out responses. Every field and nested object can have its own set of arguments. + +Sample mutation: + +```graphql +mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) { + createReview(episode: $ep, review: $review) { + stars + commentary + } +} +``` diff --git a/docs/beta-4/fuel-graphql-docs/docs/overview.mdx b/docs/beta-4/fuel-graphql-docs/docs/overview.mdx new file mode 100644 index 000000000..4ba77f2ff --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/docs/overview.mdx @@ -0,0 +1,23 @@ +--- +title: Overview +--- + +# Overview + +## Introduction to the Fuel GraphQL API + +The Fuel GraphQL API allows you to query the Fuel blockchain for a wide range of on-chain data. It can be used to query transactions, balances, block information, and more. You can also use it to simulate and submit transactions on the Fuel network. + +## Playground + +The playground is an interactive and graphical IDE that includes a reference for queries, mutations, and types. It also provides query validation and context for the underlying GraphQL schema. + +You can test out the Fuel GraphQL API playground here: + +Beta-4: +https://beta-4.fuel.network/playground + +## API Endpoint + +Beta-4: +https://beta-4.fuel.network/graphql diff --git a/docs/beta-4/fuel-graphql-docs/docs/querying-from-a-dapp.mdx b/docs/beta-4/fuel-graphql-docs/docs/querying-from-a-dapp.mdx new file mode 100644 index 000000000..895483907 --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/docs/querying-from-a-dapp.mdx @@ -0,0 +1,85 @@ +--- +title: Querying From A Dapp +--- + +# Querying From A Dapp + +There are several ways to interact with the Fuel GraphQL API from a frontend application. +This section covers just a few options available to get you started. + +## JavaScript + +```javascript +export async function getHealth() { + let response = await fetch('https://beta-4.fuel.network/graphql', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Accept: 'application/json', + }, + body: JSON.stringify({ query: '{ health }' }), + }); + let data = await response.json(); + console.log('DATA:', data); +} +``` + +## Apollo Client + +Read the official Apollo Client docs [here](https://www.apollographql.com/apollo-client/). + +```bash +npm install @apollo/client graphql +``` + +```javascript +import { ApolloClient, InMemoryCache, gql } from '@apollo/client'; + +const apolloClient = new ApolloClient({ + uri: 'https://beta-4.fuel.network/graphql', + cache: new InMemoryCache(), +}); + +const HEALTH_QUERY = ` + query { + health + } +`; + +export const checkHealth = async () => { + const response = await apolloClient.query({ + query: gql(HEALTH_QUERY), + }); + console.log('RESPONSE:', response); +}; +``` + +## urql + +Read the official urql docs [here](https://formidable.com/open-source/urql/). + +```bash +npm install urql graphql +``` + +```javascript +import { Client, cacheExchange, fetchExchange } from 'urql'; + +const urqlClient = new Client({ + url: 'https://beta-4.fuel.network/graphql', + exchanges: [cacheExchange, fetchExchange], +}); + +const HEALTH_QUERY = ` + query { + health + } +`; + +export const checkHealth = async () => { + const response = await urqlClient.query(HEALTH_QUERY).toPromise(); + console.log('RESPONSE:', response); +}; +``` + +You can see more examples in the next section. diff --git a/docs/beta-4/fuel-graphql-docs/docs/recipes.mdx b/docs/beta-4/fuel-graphql-docs/docs/recipes.mdx new file mode 100644 index 000000000..ad0fcf33d --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/docs/recipes.mdx @@ -0,0 +1,497 @@ +--- +title: Recipes +--- + +# Recipes + +You can see and test the example queries and mutations below. +Click the "Run" button to run the query above it and see the response. +Click the "TypeScript", "Apollo Client", or "urql" buttons to see code examples. + +- [Get an asset balance of an address](#get-an-asset-balance-of-an-address) +- [List all asset balances of an address](#list-all-asset-balances-of-an-address) +- [List all transactions from an address](#list-all-transactions-from-an-address) +- [List the latest transactions](#list-the-latest-transactions) +- [Get an asset balance of a contract](#get-an-asset-balance-of-a-contract) +- [List all asset balances of a contract](#list-all-asset-balances-of-a-contract) +- [List the latest blocks](#list-the-latest-blocks) +- [Get block information by height](#get-block-information-by-height) +- [List all messages owned by address](#list-all-messages-owned-by-address) +- [Dry run a transaction](#dry-run-a-transaction) +- [Submit a transaction](#submit-a-transaction) +- [More Examples](#more-examples) + +## Get an asset balance of an address + +```graphql +query Balance($address: Address, $assetId: AssetId) { + balance(owner: $address, assetId: $assetId) { + owner + amount + assetId + } +} +``` + +Variables: + +```json +{ + "address": "0xf65d6448a273b531ee942c133bb91a6f904c7d7f3104cdaf6b9f7f50d3518871", + "assetId": "0x0000000000000000000000000000000000000000000000000000000000000000" +} +``` + + + +{' '} + + +## List all asset balances of an address + +```graphql +query Balances($filter: BalanceFilterInput) { + balances(filter: $filter, first: 5) { + nodes { + amount + assetId + } + } +} +``` + +Variables: + +```json +{ + "filter": { + "owner": "0xf65d6448a273b531ee942c133bb91a6f904c7d7f3104cdaf6b9f7f50d3518871" + } +} +``` + + + + + +## List all transactions from an address + +```graphql +query Transactions($address: Address) { + transactionsByOwner(owner: $address, first: 5) { + nodes { + id + inputs { + __typename + ... on InputCoin { + owner + utxoId + amount + assetId + } + ... on InputContract { + utxoId + contract { + id + } + } + ... on InputMessage { + messageId + sender + recipient + amount + data + } + } + outputs { + __typename + ... on CoinOutput { + to + amount + assetId + } + ... on ContractOutput { + inputIndex + balanceRoot + stateRoot + } + ... on MessageOutput { + recipient + amount + } + ... on ChangeOutput { + to + amount + assetId + } + ... on VariableOutput { + to + amount + assetId + } + ... on ContractCreated { + contract { + id + } + stateRoot + } + } + status { + __typename + ... on FailureStatus { + reason + programState { + returnType + } + } + } + } + } +} +``` + +Variables: + +```json +{ + "address": "0xf65d6448a273b531ee942c133bb91a6f904c7d7f3104cdaf6b9f7f50d3518871" +} +``` + + + + + +## List the latest transactions + +```graphql +query LatestTransactions { + transactions(last: 5) { + nodes { + id + inputs { + __typename + ... on InputCoin { + owner + utxoId + amount + assetId + } + ... on InputContract { + utxoId + contract { + id + } + } + ... on InputMessage { + messageId + sender + recipient + amount + data + } + } + outputs { + __typename + ... on CoinOutput { + to + amount + assetId + } + ... on ContractOutput { + inputIndex + balanceRoot + stateRoot + } + ... on MessageOutput { + recipient + amount + } + ... on ChangeOutput { + to + amount + assetId + } + ... on VariableOutput { + to + amount + assetId + } + ... on ContractCreated { + contract { + id + } + stateRoot + } + } + status { + __typename + ... on FailureStatus { + reason + programState { + returnType + } + } + } + } + } +} +``` + + + + + +## Get an asset balance of a contract + +```graphql +query ContractBalance($contract: ContractId, $asset: AssetId) { + contractBalance(contract: $contract, asset: $asset) { + contract + amount + assetId + } +} +``` + +Variables: + +```json +{ + "contract": "0xc9a5366c269438d294ef942bc962dd2e6c86121e3bca00192723eb7eb58fa87d", + "asset": "0x0000000000000000000000000000000000000000000000000000000000000000" +} +``` + + + + + +## List all asset balances of a contract + +```graphql +query ContractBalances($filter: ContractBalanceFilterInput!) { + contractBalances(filter: $filter, first: 5) { + nodes { + amount + assetId + } + } +} +``` + +Variables: + +```json +{ + "filter": { + "contract": "0x0a98320d39c03337401a4e46263972a9af6ce69ec2f35a5420b1bd35784c74b1" + } +} +``` + + + + + +## List the latest blocks + +```graphql +query LatestBlocks { + blocks(last: 5) { + nodes { + id + transactions { + id + inputAssetIds + inputs { + __typename + ... on InputCoin { + owner + utxoId + amount + assetId + } + ... on InputContract { + utxoId + contract { + id + } + } + ... on InputMessage { + messageId + sender + recipient + amount + data + } + } + outputs { + __typename + ... on CoinOutput { + to + amount + assetId + } + ... on ContractOutput { + inputIndex + balanceRoot + stateRoot + } + ... on MessageOutput { + recipient + amount + } + ... on ChangeOutput { + to + amount + assetId + } + ... on VariableOutput { + to + amount + assetId + } + ... on ContractCreated { + contract { + id + } + stateRoot + } + } + gasPrice + } + } + } +} +``` + + + + + +## Get block information by height + +```graphql +query Block($height: U64) { + block(height: $height) { + id + } +} +``` + +Variables: + +```json +{ + "height": "378485" +} +``` + + + + + +## List all messages owned by address + +```graphql +query MessageInfo($address: Address) { + messages(owner: $address, first: 5) { + nodes { + amount + sender + recipient + nonce + data + daHeight + } + } +} +``` + +Variables: + +```json +{ + "address": "0xf65d6448a273b531ee942c133bb91a6f904c7d7f3104cdaf6b9f7f50d3518871" +} +``` + + + + + +## Dry run a transaction + +```graphql +mutation DryRun($encodedTransaction: HexString!, $utxoValidation: Boolean) { + dryRun(tx: $encodedTransaction, utxoValidation: $utxoValidation) { + receiptType + data + rawPayload + } +} +``` + +## Submit a transaction + +```graphql +mutation submit($encodedTransaction: HexString!) { + submit(tx: $encodedTransaction) { + id + } +} +``` + +## More Examples + +You can find more examples of how we use this API in our GitHub: + +[Block Explorer](https://github.com/FuelLabs/block-explorer-v2/) + +[Fuels Typescript SDK](https://github.com/FuelLabs/fuels-ts/) diff --git a/docs/beta-4/fuel-graphql-docs/docs/reference.mdx b/docs/beta-4/fuel-graphql-docs/docs/reference.mdx new file mode 100644 index 000000000..d9cbd4a98 --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/docs/reference.mdx @@ -0,0 +1,22 @@ +--- +title: Reference +category: Reference +--- + +# Reference + +The reference provides more information about the types, queries, and mutations used in the Fuel GraphQL API. + +- [Scalars](/docs/reference/scalars/) + +- [Enums](/docs/reference/enums/) + +- [Unions](/docs/reference/unions/) + +- [Objects](/docs/reference/objects/) + +- [Queries](/docs/reference/queries/) + +- [Mutations](/docs/reference/mutations/) + +- [Subscriptions](/docs/reference/subscriptions/) diff --git a/docs/beta-4/fuel-graphql-docs/docs/reference/enums.mdx b/docs/beta-4/fuel-graphql-docs/docs/reference/enums.mdx new file mode 100644 index 000000000..6f4aa27da --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/docs/reference/enums.mdx @@ -0,0 +1,62 @@ +--- +title: Enums +category: Reference +--- + +# Enums + +## `ReceiptType` + +The receipt type inidicating what kind of transaction generated the receipt. + +`CALL`: +The receipt was generated from a contract call. + +`RETURN`: +The receipt was generated from a transaction that returned without data. + +`RETURN_DATA`: +The receipt was generated from a transaction that returned data. + +`PANIC`: +The receipt was generated from a failed contract call that panicked. + +`REVERT`: +The receipt was generated from a failed contract call that reverted. + +`LOG`: +The receipt was generated from a log in the contract. The Log receipt is generated for non-reference types, namely bool, u8, u16, u32, and u64. + +`LOG_DATA`: +The receipt was generated from a log in the contract. LogData is generated for reference types which include all types except for the non_reference types mentioned above. + +`TRANSFER`: +The receipt was generated from a transaction that transferred coins to a contract. + +`TRANSFER_OUT`: +The receipt was generated from a transaction that transferred coins to an address (rather than a contract). + +`SCRIPT_RESULT`: +The receipt was generated from a script. + +`MESSAGE_OUT`: +The receipt was generated from a message. + +`MINT`: +The receipt was generated from a mint. + +`BURN`: +The receipt was generated from a burn. + +## `ReturnType` + +The type of return response for a transaction + +`RETURN`: +Indicates the transaction returned without any data. + +`RETURN_DATA`: +Indicates the transaction returned some data. + +`REVERT`: +Indicates the transaction reverted. diff --git a/docs/beta-4/fuel-graphql-docs/docs/reference/mutations.mdx b/docs/beta-4/fuel-graphql-docs/docs/reference/mutations.mdx new file mode 100644 index 000000000..609e1bb48 --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/docs/reference/mutations.mdx @@ -0,0 +1,45 @@ +--- +title: Mutations +category: Reference +--- + +# Mutations + +## `dryRun` + +A mutation that spins up a new temporary node from the current state and emulates a given transaction. +It returns a [`[Receipt!]!`](/docs/reference/objects/#receipt) for the emulated transaction. +You can optionally use UTXO validation. + +### `dryRun` `args` + +`tx`: [`HexString!`](/docs/reference/scalars/#hexstring) + +The transaction hex string. + +`utxoValidation: Boolean`: +Whether or not to use UTXO validation. + +## `produceBlocks` + +A mutation that produces blocks, that can be used for testing that requires block advancement. Returns a [`U32!`](/docs/reference/scalars/#u32). + +### `produceBlocks` `args` + +`startTimestamp`: [`Tai64Timestamp!`](/docs/reference/scalars/#tai64timestamp) + +The start time of the produced block. + +`blocksToProduce`: [`U64!`](/docs/reference/scalars/#u64) + +The number of blocks to produce. + +## `submit` + +A mutation that submits transaction to the transaction pool and returns a [`Transaction!`](/docs/reference/objects/#transaction). + +### `submit` `args` + +`tx:` [`HexString!`](/docs/reference/scalars/#hexstring) + +The transaction hex string. diff --git a/docs/beta-4/fuel-graphql-docs/docs/reference/objects.mdx b/docs/beta-4/fuel-graphql-docs/docs/reference/objects.mdx new file mode 100644 index 000000000..f2e0be094 --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/docs/reference/objects.mdx @@ -0,0 +1,1434 @@ +--- +title: Objects +category: Reference +--- + +# Objects + +## `Balance` + +The balance of a particular asset for a wallet address. + +**fields:** + +`owner`: [`Address!`](/docs/reference/scalars/#address) + +An EOA account represented by 32 bytes. + +`amount`: [`U64!`](/docs/reference/scalars/#u64) + +The amount of the selected asset id as an unsigned 64 bit number. + +`assetId`: [`AssetId!`](/docs/reference/scalars/#assetid) + +A 32 byte representation of the asset. + +## `BalanceFilterInput` + +The filter input type used to filter the `balances` query. + +**fields:** + +`owner`: [`Address!`(/docs/reference/scalars/#address) + +The owner address of the balances. + +## `Block` + +Information about a block in the network. + +**fields:** + +`id`: [`BlockId!`](/docs/reference/scalars/#blockid) + +A unique identifier for the block. + +`header`: [`Header!`](#header) + +Metadata about a block. + +`consensus`: [`Consensus!`](/docs/reference/unions/#consensus) + +The type of consensus used. + +`transactions`: [`[Transaction!]!`](#transaction) + +An array of transactions included in the block. + +## `ChainInfo` + +Information about the base chain. At a very high level `chainInfo` helps you understand what Fuel chain you're connected to and the different parameters of this chain. + +**fields:** + +`name: String!` + +The human-readable string name of the chain. i.e. beta-4 + +`latestBlock`: [`Block!`](#block) + +The most recently created block. + +`baseChainHeight`: [`U32!`](/docs/reference/scalars/#u32) + +Returns 0 (in development mode, this will change). This should return the height of the chain at start. + +`peerCount: Int!` + +The number of nodes that node is peered with. + +`consensusParameters`: [`ConsensusParameters!`](#consensusparameters) + +The consensus parameters used to validate blocks. + +`gasCosts`: [`GasCosts!`](#gascosts) + +The gas cost of each opcode. + +## `ChangeOutput` + +A transaction output that changes the unspent coins in a UTXO. + +**fields:** + +`to`: [`Address!`](/docs/reference/scalars/#address) + +The recipient address of the coins. + +`amount`: [`U64!`](/docs/reference/scalars/#u64) + +The amount of coins. + +`assetId`: [`AssetId!`](/docs/reference/scalars/#assetid) + +The asset id for the coins. + +## `Coin` + +Information about a coin. + +**fields:** + +`utxoId`: [`UtxoId!`](/docs/reference/scalars/#utxoid) + +A unique 32 byte identifier for a UTXO. + +`owner`: [`Address!`](/docs/reference/scalars/#address) + +The owner address of the coins. + +`amount`: [`U64!`](/docs/reference/scalars/#u64) + +The amount of coins. + +`assetId`: [`AssetId!`](/docs/reference/scalars/#assetid) + +The asset id of the coin. + +`maturity`: [`U32!`](/docs/reference/scalars/#u32) + +The UTXO being spent must have been created at least this many blocks ago. + +`blockCreated`: [`U32!`](/docs/reference/scalars/#u32) + +The block when the coins were created. + +`txCreatedIdx`: [`U64!`](/docs/reference/scalars/#u64) + +The index of the transaction that created this coin. + +## `CoinFilterInput` + +The filter input type for the `coins` query. + +**fields:** + +`owner`: [`Address!`](/docs/reference/scalars/#address) + +The owner of the coins. + +`assetId`: [`AssetId`](/docs/reference/scalars/#assetid) + +The asset id of the coins. + +## `CoinOutput` + +A type representing a coin output. + +**fields:** + +`to`: [`Address!`](/docs/reference/scalars/#address) + +The receiver address of the output coins. + +`amount`: [`U64!`](/docs/reference/scalars/#u64) + +The amount of coins in the output. + +`assetId`: [`AssetId!`](/docs/reference/scalars/#assetid) + +The asset id for the output coins. + +## `ConsensusParameters` + +The consensus parameters used for validating blocks. + +**fields:** + +`contractMaxSize`: [`U64!`](/docs/reference/scalars/#u64) + +The maximum contract size, in bytes. + +`maxInputs`: [`U64!`](/docs/reference/scalars/#u64) + +The maximum number of inputs. + +`maxOutputs`: [`U64!`](/docs/reference/scalars/#u64) + +The maximum number of outputs. + +`maxWitnesses`: [`U64!`](/docs/reference/scalars/#u64) + +The maximum number of witnesses. + +`maxGasPerTx`: [`U64!`](/docs/reference/scalars/#u64) + +The maximum gas per transaction. + +`maxScriptLength`: [`U64!`](/docs/reference/scalars/#u64) + +The maximum length of a script, in instructions. + +`maxGasPerPredicate`: [`U64!`](/docs/reference/scalars/#u64) + +The maximum gas per predicate transaction. + +`maxScriptDataLength`: [`U64!`](/docs/reference/scalars/#u64) + +The maximum length of script data, in bytes. + +`maxStorageSlots`: [`U64!`](/docs/reference/scalars/#u64) + +The maximum number of initial storage slots. + +`maxPredicateLength`: [`U64!`](/docs/reference/scalars/#u64) + +The maximum length of a predicate, in instructions. + +`maxPredicateDataLength`: [`U64!`](/docs/reference/scalars/#u64) + +The maximum length of predicate data, in bytes. + +`gasPriceFactor`: [`U64!`](/docs/reference/scalars/#u64) + +A factor to convert between gas and the transaction assets value. + +`gasPerByte`: [`U64!`](/docs/reference/scalars/#u64) + +A fixed ratio linking metered bytes to a gas price. + +`maxMessageDataLength`: [`U64!`](/docs/reference/scalars/#u64) + +The maximum length of message data, in bytes. + +`chainId`: [`U64!`](/docs/reference/scalars/#u64) + +A unique identifier for the chain. + +## `Contract` + +An object representing a deployed contract. + +**fields:** + +`id`: [`ContractId!`](/docs/reference/scalars/#contractid) + +The contract address. + +`bytecode`: [`HexString!`](/docs/reference/scalars/#hexstring) + +The contract bytecode. + +`salt`: [`Salt!`](/docs/reference/scalars/#salt) + +A unique identifier for the contract. + +## `ContractBalance` + +An object representing the balance of a deployed contract for a certain asset. + +**fields:** + +`contract`: [`ContractId!`](/docs/reference/scalars/#contractid) + +The contract address. + +`amount`: [`U64!`](/docs/reference/scalars/#u64) + +The contract balance for the given asset. + +`assetId`: [`AssetId!`](/docs/reference/scalars/#assetid) + +The asset id for the coins. + +## `ContractBalanceFilterInput` + +The filter input type for the `contractBalances` query. + +**fields:** + +`contract`: [`ContractId!`](/docs/reference/scalars/#contractid) + +The contract id that the query will return balances for. + +## `ContractCreated` + +The output type from deploying a contract. + +**fields:** + +`contract`: [`Contract!`](#contract) + +The contract that was created. + +`stateRoot`: [`Bytes32!`](/docs/reference/scalars/#bytes32) + +The initial state root of contract. + +## `ContractOutput` + +The output type from a transaction that changed the state of a contract. + +**fields:** + +`inputIndex: Int!` + +The index of the input. + +`balanceRoot`: [`Bytes32!`](/docs/reference/scalars/#bytes32) + +The root of amount of coins owned by contract after transaction execution. + +`stateRoot`: [`Bytes32!`](/docs/reference/scalars/#bytes32) + +The state root of contract after transaction execution. + +## `DependentCost` + +Contains the dependent cost of opcodes. + +**fields:** + +`base`: [`U64!`](/docs/reference/scalars/#u64) + +The base gas cost. + +`depPerUnit`: [`U64!`](/docs/reference/scalars/#u64) + +The dependent gas cost per unit. + +## `ExcludeInput` + +The input type for the `resourcesToSpend` query that defines what utxos and messages to exclude. + +**fields:** + +`utxos`: [`[UtxoId!]!`](/docs/reference/scalars/#utxoid) + +An array of utxo IDs to exclude. + +`messages`: [`[Nonce!]!`](/docs/reference/scalars/#nonce) + +An array of message IDs to exclude. + +## `FailureStatus` + +The status type of a transaction that has failed. + +**fields:** + +`block`: [`Block!`](#block) + +The block number for the failed transaction. + +`time`: [`Tai64Timestamp!`](/docs/reference/scalars/#tai64timestamp) + +The time the transaction failed. + +`reason: String!` + +The reason why the transaction failed. + +`programState`: [`ProgramState`](#programstate) + +The state of the program execution. + +## `GasCosts` + +The breakdown of the gas costs of each opcode. + +**fields:** + +`add`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$add` ALU opcode. + +`addi`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$addi` ALU opcode. + +`aloc`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$aloc` memory opcode. + +`and`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$and` ALU opcode. + +`andi`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$andi` ALU opcode. + +`bal`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$bal` contract opcode. + +`bhei`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$bhei` contract opcode. + +`bhsh`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$bhsh` contract opcode. + +`burn`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$burn` contract opcode. + +`cb`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$cb` contract opcode. + +`cfei`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$cfei` memory opcode. + +`cfsi`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$cfsi` memory opcode. + +`croo`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$croo` contract opcode. + +`div`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$div` ALU opcode. + +`divi`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$divi` ALU opcode. + +`ecr1`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$ecr1` cryptographic opcode. + +`eck1`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$eck1` cryptographic opcode. + +`ed19`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$ed19` cryptographic opcode. + +`eq`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$eq` ALU opcode. + +`exp`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$exp` ALU opcode. + +`expi`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$expi` ALU opcode. + +`flag`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$flag` opcode. + +`gm`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$gm` opcode. + +`gt`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$gt` opcode. + +`gtf`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$gtf` ALU opcode. + +`ji`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$ji` control flow opcode. + +`jmp`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$jmp` control flow opcode. + +`jne`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$jne` control flow opcode. + +`jnei`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$jnei` control flow opcode. + +`jnzi`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$jnzi` control flow opcode. + +`jmpf`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$jmpf` control flow opcode. + +`jmpb`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$jmpb` control flow opcode. + +`jnzf`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$jnzf` control flow opcode. + +`jnzb`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$jnzb` control flow opcode. + +`jnef`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$jnef` control flow opcode. + +`jneb`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$jneb` control flow opcode. + +`k256`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$k256` cryptographic opcode. + +`lb`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$lb` memory opcode. + +`log`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$log` contract opcode. + +`lt`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$lt` ALU opcode. + +`lw`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$lw` memory opcode. + +`mcpi`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$mcpi` memory opcode. + +`mint`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$mint` contract opcode. + +`mlog`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$mlog` ALU opcode. + +`modOp`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$modOp` opcode. + +`modi`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$modi` ALU opcode. + +`moveOp`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$moveOp` ALU opcode. + +`movi`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$movi` ALU opcode. + +`mroo`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$mroo` ALU opcode. + +`mul`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$mul` ALU opcode. + +`muli`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$muli` ALU opcode. + +`mldv`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$mldv` ALU opcode. + +`noop`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$noop` ALU opcode. + +`not`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$not` ALU opcode. + +`or`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$or` ALU opcode. + +`ori`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$ori` ALU opcode. + +`ret`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$ret` opcode. + +`rvrt`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$rvrt` contract opcode. + +`s256`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$s256` cryptographic opcode. + +`sb`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$sb` memory opcode. + +`scwq`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$scwq` contract opcode. + +`sll`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$sll` ALU opcode. + +`slli`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$slli` ALU opcode. + +`srl`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$srl` ALU opcode. + +`srli`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$srli` ALU opcode. + +`srw`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$srw` contract opcode. + +`sub`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$sub` ALU opcode. + +`subi`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$subi` ALU opcode. + +`sw`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$sw` memory opcode. + +`sww`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$sww` contract opcode. + +`swwq`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$swwq` contract opcode. + +`time`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$time` contract opcode. + +`tr`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$tr` contract opcode. + +`tro`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$tro` contract opcode. + +`wdcm`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$wdcm` ALU opcode. + +`wqcm`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$wqcm` ALU opcode. + +`wdop`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$wdop` ALU opcode. + +`wqop`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$wqop` ALU opcode. + +`wdml`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$wdml` ALU opcode. + +`wqml`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$wqml` ALU opcode. + +`wddv`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$wddv` ALU opcode. + +`wqdv`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$wqdv` ALU opcode. + +`wdmd`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$wdmd` ALU opcode. + +`wqmd`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$wqmd` ALU opcode. + +`wdam`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$wdam` ALU opcode. + +`wqam`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$wqam` ALU opcode. + +`wdmm`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$wdmm` ALU opcode. + +`wqmm`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$wqmm` ALU opcode. + +`xor`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$xor` ALU opcode. + +`xori`: [`U64!`](/docs/reference/scalars/#u64) + +The gas cost of using the `$xori` ALU opcode. + +`call`: [`DependentCost!`](#dependentcost) + +The `dependent` gas cost of using the `$call` contract opcode. + +`ccp`: [`DependentCost!`](#dependentcost) + +The `dependent` gas cost of using the `$ccp` contract opcode. + +`csiz`: [`DependentCost!`](#dependentcost) + +The `dependent` gas cost of using the `$csiz` contract opcode. + +`ldc`: [`DependentCost!`](#dependentcost) + +The `dependent` gas cost of using the `$ldc` contract opcode. + +`logd`: [`DependentCost!`](#dependentcost) + +The `dependent` gas cost of using the `$logd` contract opcode. + +`mcl`: [`DependentCost!`](#dependentcost) + +The `dependent` gas cost of using the `$mcl` memory opcode. + +`mcli`: [`DependentCost!`](#dependentcost) + +The `dependent` gas cost of using the `$mcli` memory opcode. + +`mcp`: [`DependentCost!`](#dependentcost) + +The `dependent` gas cost of using the `$mcp` memory opcode. + +`meq`: [`DependentCost!`](#dependentcost) + +The `dependent` gas cost of using the `$meq` memory opcode. + +`retd`: [`DependentCost!`](#dependentcost) + +The `dependent` gas cost of using the `$retd` contract opcode. + +`smo`: [`DependentCost!`](#dependentcost) + +The `dependent` gas cost of using the `$smo` contract opcode. + +`srwq`: [`DependentCost!`](#dependentcost) + +The `dependent` gas cost of using the `$srwq` contract opcode. + +## `Genesis` + +The genesis consensus type. + +**fields:** + +`chainConfigHash`: [`Bytes32!`](/docs/reference/scalars/#bytes32) + +The chain configuration hash. The chain configuration defines what consensus type to use, what settlement layer to use, and the rules of block validity. + +`coinsRoot`: [`Bytes32!`](/docs/reference/scalars/#bytes32) + +The binary Merkle tree root of all genesis coins. + +`contractsRoot`: [`Bytes32!`](/docs/reference/scalars/#bytes32) + +The binary Merkle tree root of state, balances, and the contracts code hash of each contract. + +`messagesRoot`: [`Bytes32!`](/docs/reference/scalars/#bytes32) + +The binary merkle tree root of all genesis messages. + +## `Header` + +The header contains metadata about a certain block. + +**fields:** + +`id`: [`BlockId!`](/docs/reference/scalars/#blockid) + +The current block id. + +`daHeight`: [`U64!`](/docs/reference/scalars/#u64) + +The block height for the data availability layer up to which (inclusive) input messages are processed. + +`transactionsCount`: [`U64!`](/docs/reference/scalars/#u64) + +The number of transactions in the block. + +`messageReceiptCount`: [`U64!`](/docs/reference/scalars/#u64) + +The number of receipt messages in the block. + +`messageReceiptRoot`: [`Bytes32!`](/docs/reference/scalars/#bytes32) + +The merkle root of the receipt messages in the block. + +`height`: [`U32!`](/docs/reference/scalars/#u32) + +The block height. + +`prevRoot`: [`Bytes32!`](/docs/reference/scalars/#bytes32) + +The merkle root of all previous consensus header hashes (not including this block). + +`time`: [`Tai64Timestamp!`](/docs/reference/scalars/#tai64timestamp) + +The timestamp for the block. + +`applicationHash`: [`Bytes32!`](/docs/reference/scalars/#bytes32) + +The hash of the serialized application header for this block. + +## `InputCoin` + +Information about a coin input. + +**fields:** + +`utxoId`: [`UtxoId!`](/docs/reference/scalars/#utxoid) + +A unique 32 byte identifier for the UTXO. + +`owner`: [`Address!`](/docs/reference/scalars/#address) + +The owning address or predicate root. + +`amount`: [`U64!`](/docs/reference/scalars/#u64) + +The amount of coins. + +`assetId`: [`AssetId!`](/docs/reference/scalars/#assetid) + +The asset ID of the coins. + +`txPointer`: [`TxPointer!`](/docs/reference/scalars/#txpointer) + +A pointer to the transaction whose output is being spent. + +`witnessIndex: Int!` + +The index of the witness that authorizes spending the coin. + +`maturity`: [`U32!`](/docs/reference/scalars/#u32) + +The UTXO being spent must have been created at least this many blocks ago. + +`predicateGasUsed`: [`U64!`](/docs/reference/scalars/#u64) + +The amount of gas used in the predicate transaction. + +`predicate`: [`HexString!`](/docs/reference/scalars/#hexstring) + +The predicate bytecode. + +`predicateData`: [`HexString!`](/docs/reference/scalars/#hexstring) + +The predicate input parameters. + +## `InputContract` + +Information about a contract input. + +**fields:** + +`utxoId`: [`UtxoId!`](/docs/reference/scalars/#utxoid) + +A unique 32 byte identifier for the UTXO. + +`balanceRoot`: [`Bytes32!`](/docs/reference/scalars/#bytes32) + +The root of amount of coins owned by contract before transaction execution. + +`stateRoot`: [`Bytes32!`](/docs/reference/scalars/#bytes32) + +The state root of contract before transaction execution. + +`txPointer`: [`TxPointer!`](/docs/reference/scalars/#txpointer) + +A pointer to the TX whose output is being spent. + +`contract`: [`Contract!`](#contract) + +The input contract. + +## `InputMessage` + +Information about a message input. + +**fields:** + +`sender`: [`Address!`](/docs/reference/scalars/#address) + +The sender address of the message. + +`recipient`: [`Address!`](/docs/reference/scalars/#address) + +The recipient address of the message. + +`amount`: [`U64!`](/docs/reference/scalars/#u64) + +The amount sent in the message. + +`nonce`: [`Nonce!`](/docs/reference/scalars/#nonce) + +A nonce value for the message input, which is determined by the sending system and is published at the time the message is sent. + +`witnessIndex: Int!` + +The index of witness that authorizes spending the coin. + +`predicateGasUsed`: [`U64!`](/docs/reference/scalars/#u64) + +The amount of gas used in the predicate transaction. + +`data`: [`HexString!`](/docs/reference/scalars/#hexstring) + +The message data. + +`predicate`: [`HexString!`](/docs/reference/scalars/#hexstring) + +The predicate bytecode. + +`predicateData`: [`HexString!`](/docs/reference/scalars/#hexstring) + +The predicate input parameters. + +## `MerkleProof` + +Information about a merkelproof. + +**fields:** + +`proofSet`: [`[Bytes32!]!`](/docs/reference/scalars/#bytes32) + +The proof set of the message proof. + +`proofIndex`: [`U64!`](/docs/reference/scalars/#u64) + +The index used to generate this proof. + +## `Message` + +Contains information about a message. + +**fields:** + +`messageId`: [`MessageId!`](/docs/reference/scalars/#messageid) + +A unique id for the message. + +`amount`: [`U64!`](/docs/reference/scalars/#u64) + +The amount of base asset coins sent with the message. + +`sender`: [`Address!`](/docs/reference/scalars/#address) + +The address of the message sender. + +`recipient`: [`Address!`](/docs/reference/scalars/#address) + +The recipient of the message. + +`nonce`: [`Nonce!`](/docs/reference/scalars/#nonce) + +The nonce value for the message. + +`data: [Int!]!` + +The vector with the message data. + +`daHeight`: [`U64!`](/docs/reference/scalars/#u64) + +The block height of the data availability layer up to which (inclusive) input messages are processed. + +## `MessageCoin` + +Information about message coin + +**fields:** + +`sender`: [`Address!`](/docs/reference/scalars/#address) + +The address of the message sender. + +`recipient`: [`Address!`](/docs/reference/scalars/#address) + +The recipient of the message. + +`nonce`: [`Nonce!`](/docs/reference/scalars/#nonce) + +The nonce value for the message. + +`amount`: [`U64!`](/docs/reference/scalars/#u64) + +The amount of base asset coins sent with the message. + +`assetId`: [`AssetId`](/docs/reference/scalars/#assetid) + +The asset id of the coins transferred. + +`daHeight`: [`U64!`](/docs/reference/scalars/#u64) + +The block height of the data availability layer up to which (inclusive) input messages are processed. + +## `MessageProof` + +Information about the message proof. + +**fields:** + +`messageProof`: [`MerkleProof!`](#merkleproof) + +The merkle proof of the message. + +`blockProof`: [`MerkleProof!`](#merkleproof) + +The merkle proof of the block. + +`messageBlockHeader`: [`Header!`](#header) + +The merkle proof of the message. + +`commitBlockHeader`: [`Header!`](#header) + +The merkle proof of the block. + +`sender`: [`Address!`](/docs/reference/scalars/#address) + +The message sender. + +`recipient`: [`Address!`](/docs/reference/scalars/#address) + +The message recipient. + +`nonce`: [`Nonce!`](/docs/reference/scalars/#nonce) + +The message nonce. + +`amount`: [`U64!`](/docs/reference/scalars/#u64) + +The amount sent in the message. + +`data`: [`HexString!`](/docs/reference/scalars/#hexstring) + +The data from the message. + +## `NodeInfo` + +Information about a node. + +**fields:** + +`utxoValidation: Boolean!` + +Whether or not the node is using UTXO validation. + +`vmBacktrace: Boolean!` + +Whether or not logging of backtraces from VM errors is enabled. + +`minGasPrice`: [`U64!`](/docs/reference/scalars/#u64) + +The minimum gas price for the node. + +`maxTx`: [`U64!`](/docs/reference/scalars/#u64) + +The maximum number of transactions. + +`maxDepth`: [`U64!`](/docs/reference/scalars/#u64) + +The maximum number of connected UTXOs allowed, excluding contracts. + +`nodeVersion: String!` + +The node version. + +## `PoAConsensus` + +The proof-of-authority (PoA) consensus type. + +**fields:** + +`signature`: [`Signature!`](/docs/reference/scalars/#signature) + +The signature of the block produced by PoA consensus. + +## `ProgramState` + +An object representing the state of execution of a transaction. + +**fields:** + +`returnType`: [`ReturnType!`](/docs/reference/enums/#returntype) + +The type of return response for the transaction. + +`data`: [`HexString!`](/docs/reference/scalars/#hexstring) + +The data returned from the transaction. + +## `Receipt` + +An object representing all possible types of receipts. + +**fields:** + +`contract`: [`Contract`](#contract) + +The contract that produced the receipt. + +`pc`: [`U64`](/docs/reference/scalars/#u64) + +The value of the program counter register `$pc`, which is the memory address of the current instruction. + +`is`: [`U64`](/docs/reference/scalars/#u64) + +The value of register `$is`, which is the pointer to the start of the currently-executing code. + +`to`: [`Contract`](#contract) + +The recipient contract. + +`toAddress`: [`Address`](/docs/reference/scalars/#address) + +The recipient address. + +`amount`: [`U64`](/docs/reference/scalars/#u64) + +The amount of coins transferred. + +`assetId`: [`AssetId`](/docs/reference/scalars/#assetid) + +The asset id of the coins transferred. + +`gas`: [`U64`](/docs/reference/scalars/#u64) + +The gas used for the transaction. + +`param1`: [`U64`](/docs/reference/scalars/#u64) + +The first parameter for a `CALL` receipt type, holds the function selector. + +`param2`: [`U64`](/docs/reference/scalars/#u64) + +The second parameter for a `CALL` receipt type, typically used for the user-specified input to the ABI function being selected. + +`val`: [`U64`](/docs/reference/scalars/#u64) + +The value of registers at the end of execution, used for debugging. + +`ptr`: [`U64`](/docs/reference/scalars/#u64) + +The value of the pointer register, used for debugging. + +`digest`: [`Bytes32`](/docs/reference/scalars/#bytes32) + +A 32-byte hash of `MEM[$rC, $rD]`. The syntax `MEM[x, y]` means the memory range starting at byte `x`, of length `y` bytes. + +`reason`: [`U64`](/docs/reference/scalars/#u64) + +The decimal string representation of an 8-bit unsigned integer for the panic reason. Only returned if the receipt type is `PANIC`. + +`ra`: [`U64`](/docs/reference/scalars/#u64) + +The value of register `$rA`. + +`rb`: [`U64`](/docs/reference/scalars/#u64) + +The value of register `$rB`. + +`rc`: [`U64`](/docs/reference/scalars/#u64) + +The value of register `$rC`. + +`rd`: [`U64`](/docs/reference/scalars/#u64) + +The value of register `$rD`. + +`len`: [`U64`](/docs/reference/scalars/#u64) + +The length of the receipt. + +`receiptType`: [`ReceiptType!`](/docs/reference/enums/#receipttype) + +The type of receipt. + +`result`: [`U64`](/docs/reference/scalars/#u64) + +`0` if script exited successfully, `any` otherwise. + +`gasUsed`: [`U64`](/docs/reference/scalars/#u64) + +The amount of gas consumed by the script. + +`data`: [`HexString`](/docs/reference/scalars/#hexstring) + +The receipt data. + +`sender`: [`Address`](/docs/reference/scalars/#address) + +The address of the message sender. + +`recipient`: [`Address`](/docs/reference/scalars/#address) + +The address of the message recipient. + +`nonce`: [`Nonce`](/docs/reference/scalars/#nonce) + +The nonce value for a message. + +`contractId`: [`ContractId`](/docs/reference/scalars/#contractid) + +The contract id. + +`subId`: [`Bytes32`](/docs/reference/scalars/#bytes32) + +The sub id. + +## `SpendQueryElementInput` + +A type used in the `queryPerAsset` argument for the `resourcesToSpend` query. + +**fields:** + +`assetId`: [`AssetId!`](/docs/reference/scalars/#assetid) + +The asset id for the asset. + +`amount`: [`U64!`](/docs/reference/scalars/#u64) + +The amount of coins to send. + +`max`: [`U64`](/docs/reference/scalars/#u64) + +The max number of resources in the selection. + +## `SqueezedOutStatus` + +The status for a transaction that was squeezed out of the transaction pool. + +**fields:** + +`reason: String!` + +The reason why the transaction was squeezed out. + +## `SuccessStatus` + +The status of a successful transaction. + +**fields:** + +`block`: [`Block!`](#block) + +The block of the transaction. + +`time`: [`Tai64Timestamp!`](/docs/reference/scalars/#tai64timestamp) + +The time of the transaction. + +`programState`: [`ProgramState`](#programstate) + +The state of the program execution. + +## `SubmittedStatus` + +The status for a submitted transaction. + +**fields:** + +`time`: [`Tai64Timestamp!`](/docs/reference/scalars/#tai64timestamp) + +The time a transaction was submitted + +## TimeParameters + +An object containing information about block times + +**fields:** + +`startTime`: [`U64`](/docs/reference/scalars/#u64) + +The time to set on the first block. + +`blockTimeInterval`: [`U64`](/docs/reference/scalars/#u64) + +The time interval between subsequent blocks. + +## `Transaction` + +An object containing information about a transaction. + +**fields:** + +`id`: [`TransactionId!`](/docs/reference/scalars/#transactionid) + +A unique transaction id. + +`inputAssetIds`: [`[AssetId!]`](/docs/reference/scalars/#assetid) + +An array of asset ids used for the transaction inputs. + +`inputContracts`: [`[Contract!]`](#contract) + +An array of contracts used for the transaction inputs. + +`gasPrice`: [`U64`](/docs/reference/scalars/#u64) + +The gas price for the transaction. + +`gasLimit`: [`U64`](/docs/reference/scalars/#u64) + +The gas limit for the transaction. + +`maturity`: [`U32`](/docs/reference/scalars/#u32) + +The minimum block height that the transaction can be included at. + +`txPointer`: [`TxPointer`](/docs/reference/scalars/#txpointer) + +The location of the transaction in the block. + +`isScript: Boolean!` + +Whether or not the transaction is a script. + +`isCreate: Boolean!` + +Whether or not the transaction is creating a new contract. + +`isMint: Boolean!` + +Whether or not the transaction is minting new coins. + +`inputs`: [`[Input!]`](/docs/reference/unions/#input) + +An array of inputs for the transaction. + +`outputs`: [`[Output!]!`](/docs/reference/unions/#output) + +An array of outputs for the transaction. + +`witnesses`: [`[HexString!]`](/docs/reference/scalars/#hexstring) + +An array of witnesses. + +`receiptsRoot`: [`Bytes32`](/docs/reference/scalars/#bytes32) + +The root of the receipts. + +`status`: [`TransactionStatus`](/docs/reference/unions/#transactionstatus) + +The status of the transaction. + +`receipts`: [`[Receipt!]`](#receipt) + +An array of the receipts produced by the transaction. + +`script`: [`HexString`](/docs/reference/scalars/#hexstring) + +The script to execute. + +`scriptData`: [`HexString`](/docs/reference/scalars/#hexstring) + +The script input parameters. + +`bytecodeWitnessIndex: Int` + +The witness index of contract bytecode. + +`bytecodeLength`: [`U64`](/docs/reference/scalars/#u64) + +The length of the transaction bytecode. + +`salt`: [`Salt`](/docs/reference/scalars/#salt) + +The salt value for the transaction. + +`storageSlots`: [`[HexString!]`](/docs/reference/scalars/#hexstring) + +An array of storage slot. + +`rawPayload`: [`HexString!`](/docs/reference/scalars/#hexstring) + +A hex string of the raw transaction payload. + +## `VariableOutput` + +The output type for a transaction that outputs an amount that may vary based on transaction execution. + +**fields:** + +`to`: [`Address`](/docs/reference/scalars/#address) + +The address the coins were sent to. + +`amount`: [`U64`](/docs/reference/scalars/#u64) + +The amount of coins in the output. + +`assetId`: [`AssetId`](/docs/reference/scalars/#assetid) + +The asset id for the coins sent. diff --git a/docs/beta-4/fuel-graphql-docs/docs/reference/queries.mdx b/docs/beta-4/fuel-graphql-docs/docs/reference/queries.mdx new file mode 100644 index 000000000..43325442b --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/docs/reference/queries.mdx @@ -0,0 +1,196 @@ +--- +title: Queries +category: Reference +--- + +# Queries + +## `balance` + +Returns the [`Balance!`](/docs/reference/objects/#balance) of a specific address for a given asset id. + +**args:** + +`owner`: [`Address!`](/docs/reference/scalars/#address) + +The owner address. + +`assetId`: [`AssetId!`](/docs/reference/scalars/#assetid) + +The asset id. + +## `balances` + +Returns a [`BalanceConnection!`](/docs/reference/objects/#balance) for an array of balances for each asset owned by a given address. + +**args:** + +`filter`: [`BalanceFilterInput!`](/docs/reference/objects/#balancefilterinput) + +A filter to specify the wallet owner address. + +## `block` + +Returns information about a certain [`Block`](/docs/reference/objects/#block). Accepts either the block id or block height as an argument. + +**args:** + +`id`: [`BlockId`](/docs/reference/scalars/#blockid) + +The block id. + +`height`: [`U64`](/docs/reference/scalars/#u64) + +The block height. + +## `blocks` + +Returns a [`BlockConnection!`](/docs/reference/objects/#block) for an array of all blocks produced. + +## `chain` + +Returns [`ChainInfo!`](/docs/reference/objects/#chaininfo) about the target Fuel network used for the API. + +## `coin` + +Returns details about a specific [`Coin`](/docs/reference/objects/#coin). + +**args:** + +`utxoId`: [`UtxoId!`](/docs/reference/scalars/#utxoid) + +A unique 32 byte identifier for the UTXO. + +## `coins` + +Returns a [`CoinConnection!`](/docs/reference/objects/#coin) for an array of coins based on a given owner and/or asset id + +**args:** + +`filter`: [`CoinFilterInput!`](/docs/reference/objects/#coinfilterinput) + +A filter with the owner address and optionally the asset id. + +## `coinsToSpend` + +Returns an array of spendable [`[[CoinType!]!]!`](/docs/reference/unions/#cointype) per asset. + +**args:** + +`owner`: [`Address`](/docs/reference/scalars/#address) + +The owner address of the coins. + +`queryPerAsset`: [`[SpendQueryElementInput!]!`](/docs/reference/objects/#spendqueryelementinput) + +The list of requested asset resources. Several entries with the same asset id are not allowed. + +`excludedIds`: [`ExcludeInput`](/docs/reference/objects/#excludeinput) + +The resources to exclude. + +## `contract` + +Returns the [`Contract`](/docs/reference/objects/#contract) information for a given contract id. + +**args:** + +`id`: [`ContractId!`](/docs/reference/scalars/#contractid) + +The contract id of the requested contract. + +## `contractBalance` + +Returns the [`ContractBalance!`](/docs/reference/objects/#contractbalance) for a given contract and asset id. + +**args:** + +`contract`: [`ContractId!`](/docs/reference/scalars/#contractid) + +The contract that owns the balance. + +`asset`: [`AssetId!`](/docs/reference/scalars/#assetid) + +The asset id for the balance. + +## `contractBalances` + +Returns a [`ContractBalanceConnection!`](/docs/reference/objects/#contractbalance) for an arrray of balances for all assets owned by a given contract + +**args:** + +`filter`: [`ContractBalanceFilterInput!`](/docs/reference/objects/#contractbalancefilterinput) + +A filter for the contract balances. + +## `estimatePredicates` + +Estimate the predicate gas and returns a [`Transaction!`](/docs/reference/objects/#transaction). + +`tx:` [`HexString!`](/docs/reference/scalars/#hexstring) + +The transaction hex string. + +## `health` + +Returns `true` if the API is running or `false` if the API is down. + +## `messageProof` + +Returns the [`MessageProof`](/docs/reference/objects/#messageproof) for a given message id or transaction. + +**args:** + +`transactionId`: [`TransactionId!`](/docs/reference/scalars/#transactionid) + +The transaction id for the message. + +`messageId`: [`MessageId!`](/docs/reference/scalars/#messageid) + +The id of the message. + +`id`: [`BlockId`](/docs/reference/scalars/#blockid) + +The block id. + +`height`: [`U64`](/docs/reference/scalars/#u64) + +The block height. + +## `messages` + +Returns a [`MessageConnection!`](/docs/reference/objects/#message) for an array of messages for a given owner. + +**args:** + +`owner`: [`Address`](/docs/reference/scalars/#address) + +The owner address of the messages. + +## `nodeInfo` + +Returns [`NodeInfo!`](/docs/reference/objects/#nodeinfo) about the current node. + +## `transaction` + +Returns [`Transaction`](/docs/reference/objects/#transaction) details for a given transaction id. + +**args:** + +`id`: [`TransactionId!`](/docs/reference/scalars/#transactionid) + +The id for the transaction. + +## `transactions` + +Returns a [`TransactionConnection!`](/docs/reference/objects/#transaction) for an array of all transactions. + +## `transactionsByOwner` + +Returns a [`TransactionConnection!`](/docs/reference/objects/#transaction) for an array of all transactions from a given address. + +**args:** + +`owner`: [`Address!`](/docs/reference/scalars/#address) + +The owner address of the transactions. diff --git a/docs/beta-4/fuel-graphql-docs/docs/reference/scalars.mdx b/docs/beta-4/fuel-graphql-docs/docs/reference/scalars.mdx new file mode 100644 index 000000000..69810590a --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/docs/reference/scalars.mdx @@ -0,0 +1,70 @@ +--- +title: Scalars +category: Reference +--- + +# Scalars + +## `Address` + +An address of an externally owned account identified by a 32 byte string prefixed by `0x`. + +## `AssetId` + +A 32 byte unique ID used to identify a coin. On the testnet, the assetId is `0x0000000000000000000000000000000000000000000000000000000000000000`. + +## `BlockId` + +A unique hash identifier for a block. + +## `Bytes32` + +32 bytes to hold arbitrary data, usually as a hex string. `Bytes32` is the base type for cryptographic primitives like `Address` or `Message`. + +## `ContractId` + +A wrapped 32byte hash that is used to uniquely identify a contract. + +## `HexString` + +A way to pass in bytes as hex data. This is used for variable byte length types. Predicates and predicate data are always a hex string. + +## `MessageId` + +A 32 byte identifier for cross-network messages, like messages from Ethereum to Fuel. + +## `Nonce` + +A random or pseudo-random number generated for a single use to ensure data freshness and prevent replay attacks. + +## `Salt` + +Sometimes referred to as a nonce. A unique, random value used to distinguish two things that are otherwise identical. This is used in contract deployments so you can deploy contracts that are otherwise exactly the same. + +## `Signature` + +A cryptographic signature used to authorize messages and transactions. + +## `Tai64Timestamp` + +A TAI 64 timestamp. + +## `TransactionId` + +A unique 32 byte hash identifier for a transaction. + +## `TxPointer` + +The location of the transaction in the block. It can be used by UTXOs as a reference to the transaction or by the transaction itself to make it unique. + +## `U32` + +Unsigned 32 bit number. + +## `U64` + +Unsigned 64 bit number. The default GraphQL `int` scalar does not cover the range of values needed because the FuelVM word size is 64bit. + +## `UtxoId` + +A unique 32 byte identifier for a UTXO. diff --git a/docs/beta-4/fuel-graphql-docs/docs/reference/subscriptions.mdx b/docs/beta-4/fuel-graphql-docs/docs/reference/subscriptions.mdx new file mode 100644 index 000000000..23584d8bd --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/docs/reference/subscriptions.mdx @@ -0,0 +1,28 @@ +--- +title: Subscriptions +category: Reference +--- + +# Subscriptions + +## `statusChange` + +Returns a stream of [`TransactionStatus!`](/docs/reference/unions/#transactionstatus) updates for the given transaction id if the current status is `[TransactionStatus::Submitted]`. + +This stream will wait forever so it's advised to use within a timeout. It is possible for the stream to miss an update if it is polled slower then the updates arrive. In such a case the stream will close without a status. If this occurs the stream can simply be restarted to return the latest status. + +**args:** + +`id`: [`TransactionId!`](/docs/reference/scalars/#transactionid) + +The id of the transaction to stream status updates for. + +## `submitAndAwait` + +Submits transaction to the `TxPool` and await returns [`TransactionStatus!`](/docs/reference/unions/#transactionstatus). + +**args:** + +`tx:` [`HexString!`](/docs/reference/scalars/#hexstring) + +The transaction hex string. diff --git a/docs/beta-4/fuel-graphql-docs/docs/reference/unions.mdx b/docs/beta-4/fuel-graphql-docs/docs/reference/unions.mdx new file mode 100644 index 000000000..ad01d8683 --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/docs/reference/unions.mdx @@ -0,0 +1,80 @@ +--- +title: Unions +category: Reference +--- + +# Union Types + +## `CoinType` + +The type of coin being used. + +**Types:** + +[`Coin`](/docs/reference/objects/#coin): Coin + +[`MessageCoin`](/docs/reference/objects/#messagecoin): MessageCoin + +## `Consensus` + +The type of consensus mechanism used to validate a block. + +**Types:** + +[`Genesis`](/docs/reference/objects/#genesis): Genesis consensus + +[`PoAConsensus`](/docs/reference/objects/#poaconsensus): PoA +consensus + +## `Input` + +An input type for a transaction. + +**Types:** + +[`InputCoin`](/docs/reference/objects/#inputcoin): An input type for +a coin. + +[`InputContract`](/docs/reference/objects/#inputcontract): An input +type for a contract. + +[`InputMessage`](/docs/reference/objects/#inputmessage): An input +type for a message. + +## `Output` + +An output type for a transaction. + +**Types:** + +[`CoinOutput`](/docs/reference/objects/#coinoutput): Indicates coins +were forwarded from one address to another. + +[`ContractOutput`](/docs/reference/objects/#contractoutput): +Indicates the transaction updated the state of a contract. + +[`ChangeOutput`](/docs/reference/objects/#changeoutput): Indicates +that the output's amount may vary based on transaction execution, but is +otherwise identical to a Coin output. Output changes are always guaranteed to +have an amount of zero since they're only set after execution terminates. + +[`VariableOutput`](/docs/reference/objects/#variableoutput): Similar +to `ChangeOutput`, this output type indicates that the output's amount may vary +based on transaction execution, but is otherwise identical to a Coin output. On +initialization, the amount on variable outputs is zero, but during execution +they could be set to a non-zero value. + +[`ContractCreated`](/docs/reference/objects/#contractcreated): +Indicates a contract was deployed. + +## `TransactionStatus` + +The status type of a transaction. + +[`SubmitedStatus`](/docs/reference/objects/#submittedstatus): The transaction has been submitted. + +[`SuccessStatus`](/docs/reference/objects/#successstatus): The transaction has succeeded. + +[`SqueezedOutStatus`](/docs/reference/objects/#squeezedoutstatus): The transaction was kicked out of the mempool. + +[`FailureStatus`](/docs/reference/objects/#failurestatus): The transaction has failed. diff --git a/docs/beta-4/fuel-graphql-docs/examples/Balance.tsx b/docs/beta-4/fuel-graphql-docs/examples/Balance.tsx new file mode 100644 index 000000000..92a4ebb39 --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/examples/Balance.tsx @@ -0,0 +1,20 @@ +import { Query } from './query'; + +export function Balance() { + const query = `query Balance($address: Address, $assetId: AssetId) { + balance(owner: $address, assetId: $assetId) { + owner + amount + assetId + } + }`; + + const args = { + address: + '0xf65d6448a273b531ee942c133bb91a6f904c7d7f3104cdaf6b9f7f50d3518871', + assetId: + '0x0000000000000000000000000000000000000000000000000000000000000000', + }; + + return ; +} diff --git a/docs/beta-4/fuel-graphql-docs/examples/Balances.tsx b/docs/beta-4/fuel-graphql-docs/examples/Balances.tsx new file mode 100644 index 000000000..08a2091d3 --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/examples/Balances.tsx @@ -0,0 +1,21 @@ +import { Query } from './query'; + +export function Balances() { + const query = `query Balances($filter: BalanceFilterInput) { + balances(filter: $filter, first: 5) { + nodes { + amount + assetId + } + } + }`; + + const args = { + filter: { + owner: + '0xf65d6448a273b531ee942c133bb91a6f904c7d7f3104cdaf6b9f7f50d3518871', + }, + }; + + return ; +} diff --git a/docs/beta-4/fuel-graphql-docs/examples/BlockByHeight.tsx b/docs/beta-4/fuel-graphql-docs/examples/BlockByHeight.tsx new file mode 100644 index 000000000..401f34edd --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/examples/BlockByHeight.tsx @@ -0,0 +1,15 @@ +import { Query } from './query'; + +export function BlockByHeight() { + const query = `query Block($height: U64) { + block(height: $height) { + id + } + }`; + + const args = { + height: '3412', + }; + + return ; +} diff --git a/docs/beta-4/fuel-graphql-docs/examples/ContractBalance.tsx b/docs/beta-4/fuel-graphql-docs/examples/ContractBalance.tsx new file mode 100644 index 000000000..d1c237189 --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/examples/ContractBalance.tsx @@ -0,0 +1,19 @@ +import { Query } from './query'; + +export function ContractBalance() { + const query = `query ContractBalance($contract: ContractId, $asset: AssetId) { + contractBalance(contract: $contract, asset: $asset) { + contract + amount + assetId + } + }`; + + const args = { + contract: + '0xc9a5366c269438d294ef942bc962dd2e6c86121e3bca00192723eb7eb58fa87d', + asset: '0x0000000000000000000000000000000000000000000000000000000000000000', + }; + + return ; +} diff --git a/docs/beta-4/fuel-graphql-docs/examples/ContractBalances.tsx b/docs/beta-4/fuel-graphql-docs/examples/ContractBalances.tsx new file mode 100644 index 000000000..249ab2b2e --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/examples/ContractBalances.tsx @@ -0,0 +1,21 @@ +import { Query } from './query'; + +export function ContractBalances() { + const query = `query ContractBalances($filter: ContractBalanceFilterInput!) { + contractBalances(filter: $filter, first: 5) { + nodes { + amount + assetId + } + } + }`; + + const args = { + filter: { + contract: + '0x0a98320d39c03337401a4e46263972a9af6ce69ec2f35a5420b1bd35784c74b1', + }, + }; + + return ; +} diff --git a/docs/beta-4/fuel-graphql-docs/examples/LatestBlocks.tsx b/docs/beta-4/fuel-graphql-docs/examples/LatestBlocks.tsx new file mode 100644 index 000000000..41bbf0edf --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/examples/LatestBlocks.tsx @@ -0,0 +1,70 @@ +import { Query } from './query'; + +export function LatestBlocks() { + const query = `query LatestBlocks { + blocks(last: 5) { + nodes { + id + transactions { + id + inputAssetIds + inputs { + __typename + ... on InputCoin { + owner + utxoId + amount + assetId + } + ... on InputContract { + utxoId + contract { + id + } + } + ... on InputMessage { + sender + recipient + amount + data + } + } + outputs { + __typename + ... on CoinOutput { + to + amount + assetId + } + ... on ContractOutput { + inputIndex + balanceRoot + stateRoot + } + ... on ChangeOutput { + to + amount + assetId + } + ... on VariableOutput { + to + amount + assetId + } + ... on ContractCreated { + contract { + id + } + stateRoot + } + } + gasPrice + } + } + } + }`; + + const args = {}; + + return ; +} diff --git a/docs/beta-4/fuel-graphql-docs/examples/LatestTransactions.tsx b/docs/beta-4/fuel-graphql-docs/examples/LatestTransactions.tsx new file mode 100644 index 000000000..d7cc8d42a --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/examples/LatestTransactions.tsx @@ -0,0 +1,74 @@ +import { Query } from './query'; + +export function LatestTransactions() { + const query = `query LatestTransactions { + transactions(last: 5) { + nodes { + id + inputs { + __typename + ... on InputCoin { + owner + utxoId + amount + assetId + } + ... on InputContract { + utxoId + contract { + id + } + } + ... on InputMessage { + sender + recipient + amount + data + } + } + outputs { + __typename + ... on CoinOutput { + to + amount + assetId + } + ... on ContractOutput { + inputIndex + balanceRoot + stateRoot + } + ... on ChangeOutput { + to + amount + assetId + } + ... on VariableOutput { + to + amount + assetId + } + ... on ContractCreated { + contract { + id + } + stateRoot + } + } + status { + __typename + ... on FailureStatus { + reason + programState { + returnType + } + } + } + } + } + }`; + + const args = {}; + + return ; +} diff --git a/docs/beta-4/fuel-graphql-docs/examples/MessageInfo.tsx b/docs/beta-4/fuel-graphql-docs/examples/MessageInfo.tsx new file mode 100644 index 000000000..6047fd188 --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/examples/MessageInfo.tsx @@ -0,0 +1,23 @@ +import { Query } from './query'; + +export function MessageInfo() { + const query = `query MessageInfo($address: Address) { + messages(owner: $address, first: 5) { + nodes { + amount + sender + recipient + nonce + data + daHeight + } + } + }`; + + const args = { + address: + '0xf65d6448a273b531ee942c133bb91a6f904c7d7f3104cdaf6b9f7f50d3518871', + }; + + return ; +} diff --git a/docs/beta-4/fuel-graphql-docs/examples/Transactions.tsx b/docs/beta-4/fuel-graphql-docs/examples/Transactions.tsx new file mode 100644 index 000000000..4a80360a3 --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/examples/Transactions.tsx @@ -0,0 +1,77 @@ +import { Query } from './query'; + +export function Transactions() { + const query = `query Transactions($address: Address) { + transactionsByOwner(owner: $address, first: 5) { + nodes { + id + inputs { + __typename + ... on InputCoin { + owner + utxoId + amount + assetId + } + ... on InputContract { + utxoId + contract { + id + } + } + ... on InputMessage { + sender + recipient + amount + data + } + } + outputs { + __typename + ... on CoinOutput { + to + amount + assetId + } + ... on ContractOutput { + inputIndex + balanceRoot + stateRoot + } + ... on ChangeOutput { + to + amount + assetId + } + ... on VariableOutput { + to + amount + assetId + } + ... on ContractCreated { + contract { + id + } + stateRoot + } + } + status { + __typename + ... on FailureStatus { + reason + programState { + returnType + } + } + } + } + } + }`; + + const args = { + address: + '0xf65d6448a273b531ee942c133bb91a6f904c7d7f3104cdaf6b9f7f50d3518871', + }; + + return ; +} diff --git a/docs/beta-4/fuel-graphql-docs/examples/index.tsx b/docs/beta-4/fuel-graphql-docs/examples/index.tsx new file mode 100644 index 000000000..bee4167e0 --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/examples/index.tsx @@ -0,0 +1,9 @@ +export { Balance } from './Balance'; +export { Balances } from './Balances'; +export { BlockByHeight } from './BlockByHeight'; +export { ContractBalance } from './ContractBalance'; +export { ContractBalances } from './ContractBalances'; +export { LatestBlocks } from './LatestBlocks'; +export { LatestTransactions } from './LatestTransactions'; +export { MessageInfo } from './MessageInfo'; +export { Transactions } from './Transactions'; diff --git a/docs/beta-4/fuel-graphql-docs/examples/query.tsx b/docs/beta-4/fuel-graphql-docs/examples/query.tsx new file mode 100644 index 000000000..144677f5e --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/examples/query.tsx @@ -0,0 +1,67 @@ +import { Box, Button, Spinner } from '@fuel-ui/react'; +import { useState } from 'react'; +import { ExampleBox } from '~/src/components/ExampleBox'; + +interface QueryProps { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + query: any; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + args: any; +} + +export function Query(props: QueryProps) { + const [resp, setResp] = useState(); + const [loading, setLoading] = useState(false); + + function runQuery() { + setLoading(true); + fetch('https://beta-4.fuel.network/graphql', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + query: props.query, + variables: props.args, + }), + }) + .then((res) => res.json()) + .then((result) => { + setResp(result); + setLoading(false); + }); + } + + interface IPrettyPrintJson { + data: string; + } + + const PrettyPrintJson = ({ data }: IPrettyPrintJson) => { + return ( +
+
+          {JSON.stringify(data, null, 2)}
+        
+
+ ); + }; + + return ( + + + <> + + + {resp && ( + <> +
Response:
+ + + )} + +
+
+ ); +} diff --git a/docs/beta-4/fuel-graphql-docs/examples/tests/balance.test.ts b/docs/beta-4/fuel-graphql-docs/examples/tests/balance.test.ts new file mode 100644 index 000000000..eda9f487b --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/examples/tests/balance.test.ts @@ -0,0 +1,106 @@ +import { ApolloClient, InMemoryCache, gql } from '@apollo/client'; +import { Client, cacheExchange, fetchExchange } from 'urql'; +import 'isomorphic-fetch'; + +const apolloClient = new ApolloClient({ + uri: 'https://beta-4.fuel.network/graphql', + cache: new InMemoryCache(), +}); + +const urqlClient = new Client({ + url: 'https://beta-4.fuel.network/graphql', + exchanges: [cacheExchange, fetchExchange], +}); + +describe('Balance', () => { + test('get balance with ts', async () => { + const BALANCE_QUERY = `query Balance($address: Address, $assetId: AssetId) { + balance(owner: $address, assetId: $assetId) { + owner + amount + assetId + } + }`; + + const args = { + address: + '0xf65d6448a273b531ee942c133bb91a6f904c7d7f3104cdaf6b9f7f50d3518871', + assetId: + '0x0000000000000000000000000000000000000000000000000000000000000000', + }; + + const getBalance = async () => { + const response = await fetch('https://beta-4.fuel.network/graphql', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Accept: 'application/json', + }, + body: JSON.stringify({ + query: BALANCE_QUERY, + variables: args, + }), + }); + const json = await response.json(); + console.log('BALANCE:', json.data.balance); + expect(json.data.balance.amount).toBeTruthy(); + }; + + await getBalance(); + }); + + test('get balance with apollo', async () => { + const BALANCE_QUERY = `query Balance($address: Address, $assetId: AssetId) { + balance(owner: $address, assetId: $assetId) { + owner + amount + assetId + } + }`; + + const args = { + address: + '0xf65d6448a273b531ee942c133bb91a6f904c7d7f3104cdaf6b9f7f50d3518871', + assetId: + '0x0000000000000000000000000000000000000000000000000000000000000000', + }; + + const getBalance = async () => { + const response = await apolloClient.query({ + query: gql(BALANCE_QUERY), + variables: args, + }); + console.log('BALANCE:', response.data.balance); + expect(response.data.balance.amount).toBeTruthy(); + }; + + await getBalance(); + }); + + test('get balance with urql', async () => { + const BALANCE_QUERY = `query Balance($address: Address, $assetId: AssetId) { + balance(owner: $address, assetId: $assetId) { + owner + amount + assetId + } + }`; + + const args = { + address: + '0xf65d6448a273b531ee942c133bb91a6f904c7d7f3104cdaf6b9f7f50d3518871', + assetId: + '0x0000000000000000000000000000000000000000000000000000000000000000', + }; + + const getBalance = async () => { + const response = await urqlClient.query(BALANCE_QUERY, args).toPromise(); + console.log('BALANCE:', response.data.balance); + expect(response.data.balance.amount).toBeTruthy(); + }; + + await getBalance(); + }); +}); + +export {}; diff --git a/docs/beta-4/fuel-graphql-docs/examples/tests/balances.test.ts b/docs/beta-4/fuel-graphql-docs/examples/tests/balances.test.ts new file mode 100644 index 000000000..b187814a1 --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/examples/tests/balances.test.ts @@ -0,0 +1,109 @@ +import { ApolloClient, InMemoryCache, gql } from '@apollo/client'; +import { Client, cacheExchange, fetchExchange } from 'urql'; +import 'isomorphic-fetch'; + +const apolloClient = new ApolloClient({ + uri: 'https://beta-4.fuel.network/graphql', + cache: new InMemoryCache(), +}); + +const urqlClient = new Client({ + url: 'https://beta-4.fuel.network/graphql', + exchanges: [cacheExchange, fetchExchange], +}); + +describe('Balances', () => { + test('get balances with ts', async () => { + const BALANCES_QUERY = `query Balances($filter: BalanceFilterInput) { + balances(filter: $filter, first: 5) { + nodes { + amount + assetId + } + } + }`; + + const args = { + filter: { + owner: + '0xf65d6448a273b531ee942c133bb91a6f904c7d7f3104cdaf6b9f7f50d3518871', + }, + }; + + const getBalances = async () => { + const response = await fetch('https://beta-4.fuel.network/graphql', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Accept: 'application/json', + }, + body: JSON.stringify({ + query: BALANCES_QUERY, + variables: args, + }), + }); + const json = await response.json(); + console.log('BALANCES:', json.data.balances); + expect(json.data.balances.nodes).toBeTruthy(); + }; + + await getBalances(); + }); + + test('get balances with apollo', async () => { + const BALANCES_QUERY = `query Balances($filter: BalanceFilterInput) { + balances(filter: $filter, first: 5) { + nodes { + amount + assetId + } + } + }`; + + const args = { + filter: { + owner: + '0xf65d6448a273b531ee942c133bb91a6f904c7d7f3104cdaf6b9f7f50d3518871', + }, + }; + + const getBalances = async () => { + const response = await apolloClient.query({ + query: gql(BALANCES_QUERY), + variables: args, + }); + console.log('BALANCES:', response.data.balances); + expect(response.data.balances.nodes).toBeTruthy(); + }; + + await getBalances(); + }); + + test('get balances with urql', async () => { + const BALANCES_QUERY = `query Balances($filter: BalanceFilterInput) { + balances(filter: $filter, first: 5) { + nodes { + amount + assetId + } + } + }`; + + const args = { + filter: { + owner: + '0xf65d6448a273b531ee942c133bb91a6f904c7d7f3104cdaf6b9f7f50d3518871', + }, + }; + + const getBalances = async () => { + const response = await urqlClient.query(BALANCES_QUERY, args).toPromise(); + console.log('BALANCES:', response.data.balances); + expect(response.data.balances.nodes).toBeTruthy(); + }; + + await getBalances(); + }); +}); + +export {}; diff --git a/docs/beta-4/fuel-graphql-docs/examples/tests/block.test.ts b/docs/beta-4/fuel-graphql-docs/examples/tests/block.test.ts new file mode 100644 index 000000000..b09f365f2 --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/examples/tests/block.test.ts @@ -0,0 +1,90 @@ +import { ApolloClient, InMemoryCache, gql } from '@apollo/client'; +import { Client, cacheExchange, fetchExchange } from 'urql'; +import 'isomorphic-fetch'; + +const apolloClient = new ApolloClient({ + uri: 'https://beta-4.fuel.network/graphql', + cache: new InMemoryCache(), +}); + +const urqlClient = new Client({ + url: 'https://beta-4.fuel.network/graphql', + exchanges: [cacheExchange, fetchExchange], +}); + +describe('Block Info', () => { + test('get block info with ts', async () => { + const BLOCK_BY_HEIGHT_QUERY = ` + query Block($height: U64) { + block(height: $height) { + id + } + }`; + + const args = { height: '3412' }; + + const getBlock = async () => { + const response = await fetch('https://beta-4.fuel.network/graphql', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Accept: 'application/json', + }, + body: JSON.stringify({ + query: BLOCK_BY_HEIGHT_QUERY, + variables: args, + }), + }); + const json = await response.json(); + console.log('BLOCK:', json.data.block); + expect(json.data.block.id).toBeTruthy(); + }; + + await getBlock(); + }); + + test('get block info with apollo', async () => { + const BLOCK_BY_HEIGHT_QUERY = ` + query Block($height: U64) { + block(height: $height) { + id + } + }`; + + const args = { height: '3412' }; + + const getBlock = async () => { + const response = await apolloClient.query({ + query: gql(BLOCK_BY_HEIGHT_QUERY), + variables: args, + }); + console.log('BLOCK:', response.data.block); + expect(response.data.block.id).toBeTruthy(); + }; + + await getBlock(); + }); + + test('get block info with urql', async () => { + const BLOCK_BY_HEIGHT_QUERY = ` + query Block($height: U64) { + block(height: $height) { + id + } + }`; + + const args = { height: '3412' }; + + const getBlock = async () => { + const response = await urqlClient + .query(BLOCK_BY_HEIGHT_QUERY, args) + .toPromise(); + console.log('BLOCK:', response.data.block); + expect(response.data.block.id).toBeTruthy(); + }; + + await getBlock(); + }); +}); + +export {}; diff --git a/docs/beta-4/fuel-graphql-docs/examples/tests/contract-balance.test.ts b/docs/beta-4/fuel-graphql-docs/examples/tests/contract-balance.test.ts new file mode 100644 index 000000000..c8fec6086 --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/examples/tests/contract-balance.test.ts @@ -0,0 +1,108 @@ +import { ApolloClient, InMemoryCache, gql } from '@apollo/client'; +import { Client, cacheExchange, fetchExchange } from 'urql'; +import 'isomorphic-fetch'; + +const apolloClient = new ApolloClient({ + uri: 'https://beta-4.fuel.network/graphql', + cache: new InMemoryCache(), +}); + +const urqlClient = new Client({ + url: 'https://beta-4.fuel.network/graphql', + exchanges: [cacheExchange, fetchExchange], +}); + +describe('Contract Balance', () => { + test('get contract balance with ts', async () => { + const CONTRACT_BALANCE_QUERY = `query ContractBalance($contract: ContractId, $asset: AssetId) { + contractBalance(contract: $contract, asset: $asset) { + contract + amount + assetId + } + }`; + + const args = { + contract: + '0xc9a5366c269438d294ef942bc962dd2e6c86121e3bca00192723eb7eb58fa87d', + asset: + '0x0000000000000000000000000000000000000000000000000000000000000000', + }; + + const getContractBalance = async () => { + const response = await fetch('https://beta-4.fuel.network/graphql', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Accept: 'application/json', + }, + body: JSON.stringify({ + query: CONTRACT_BALANCE_QUERY, + variables: args, + }), + }); + const json = await response.json(); + console.log('CONTRACT BALANCE:', json.data.contractBalance); + expect(json.data.contractBalance.amount).toBeTruthy(); + }; + + await getContractBalance(); + }); + + test('get contract balance with apollo', async () => { + const CONTRACT_BALANCE_QUERY = `query ContractBalance($contract: ContractId, $asset: AssetId) { + contractBalance(contract: $contract, asset: $asset) { + contract + amount + assetId + } + }`; + + const args = { + contract: + '0xc9a5366c269438d294ef942bc962dd2e6c86121e3bca00192723eb7eb58fa87d', + asset: + '0x0000000000000000000000000000000000000000000000000000000000000000', + }; + + const getContractBalance = async () => { + const response = await apolloClient.query({ + query: gql(CONTRACT_BALANCE_QUERY), + variables: args, + }); + console.log('CONTRACT BALANCE:', response.data.contractBalance); + expect(response.data.contractBalance.amount).toBeTruthy(); + }; + + await getContractBalance(); + }); + + test('get contract balance with urql', async () => { + const CONTRACT_BALANCE_QUERY = `query ContractBalance($contract: ContractId, $asset: AssetId) { + contractBalance(contract: $contract, asset: $asset) { + contract + amount + assetId + } + }`; + + const args = { + contract: + '0xc9a5366c269438d294ef942bc962dd2e6c86121e3bca00192723eb7eb58fa87d', + asset: + '0x0000000000000000000000000000000000000000000000000000000000000000', + }; + + const getContractBalance = async () => { + const response = await urqlClient + .query(CONTRACT_BALANCE_QUERY, args) + .toPromise(); + console.log('CONTRACT BALANCE:', response.data.contractBalance); + expect(response.data.contractBalance.amount).toBeTruthy(); + }; + + await getContractBalance(); + }); +}); + +export {}; diff --git a/docs/beta-4/fuel-graphql-docs/examples/tests/contract-balances.test.ts b/docs/beta-4/fuel-graphql-docs/examples/tests/contract-balances.test.ts new file mode 100644 index 000000000..9eb08759c --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/examples/tests/contract-balances.test.ts @@ -0,0 +1,114 @@ +import { ApolloClient, InMemoryCache, gql } from '@apollo/client'; +import { Client, cacheExchange, fetchExchange } from 'urql'; +import 'isomorphic-fetch'; + +const apolloClient = new ApolloClient({ + uri: 'https://beta-4.fuel.network/graphql', + cache: new InMemoryCache(), +}); + +const urqlClient = new Client({ + url: 'https://beta-4.fuel.network/graphql', + exchanges: [cacheExchange, fetchExchange], +}); + +describe('Contract balances', () => { + test('get contract balances with ts', async () => { + const CONTRACT_BALANCES_QUERY = ` + query ContractBalances($filter: ContractBalanceFilterInput!) { + contractBalances(filter: $filter, first: 5) { + nodes { + amount + assetId + } + } + }`; + + const args = { + filter: { + contract: + '0x0a98320d39c03337401a4e46263972a9af6ce69ec2f35a5420b1bd35784c74b1', + }, + }; + + const getContractBalances = async () => { + const response = await fetch('https://beta-4.fuel.network/graphql', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Accept: 'application/json', + }, + body: JSON.stringify({ + query: CONTRACT_BALANCES_QUERY, + variables: args, + }), + }); + const json = await response.json(); + console.log('CONTRACT BALANCES:', json.data.contractBalances); + expect(json.data.contractBalances.nodes).toBeTruthy(); + }; + + await getContractBalances(); + }); + + test('get contract balances with apollo', async () => { + const CONTRACT_BALANCES_QUERY = ` + query ContractBalances($filter: ContractBalanceFilterInput!) { + contractBalances(filter: $filter, first: 5) { + nodes { + amount + assetId + } + } + }`; + + const args = { + filter: { + contract: + '0x0a98320d39c03337401a4e46263972a9af6ce69ec2f35a5420b1bd35784c74b1', + }, + }; + + const getContractBalances = async () => { + const response = await apolloClient.query({ + query: gql(CONTRACT_BALANCES_QUERY), + variables: args, + }); + console.log('CONTRACT BALANCES:', response.data.contractBalances); + expect(response.data.contractBalances.nodes).toBeTruthy(); + }; + + await getContractBalances(); + }); + + test('get contract balances with urql', async () => { + const CONTRACT_BALANCES_QUERY = ` + query ContractBalances($filter: ContractBalanceFilterInput!) { + contractBalances(filter: $filter, first: 5) { + nodes { + amount + assetId + } + } + }`; + + const args = { + filter: { + contract: + '0x0a98320d39c03337401a4e46263972a9af6ce69ec2f35a5420b1bd35784c74b1', + }, + }; + + const getContractBalances = async () => { + const response = await urqlClient + .query(CONTRACT_BALANCES_QUERY, args) + .toPromise(); + console.log('CONTRACT BALANCES:', response.data.contractBalances); + expect(response.data.contractBalances.nodes).toBeTruthy(); + }; + + await getContractBalances(); + }); +}); + +export {}; diff --git a/docs/beta-4/fuel-graphql-docs/examples/tests/latest-blocks.test.ts b/docs/beta-4/fuel-graphql-docs/examples/tests/latest-blocks.test.ts new file mode 100644 index 000000000..2656f1af1 --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/examples/tests/latest-blocks.test.ts @@ -0,0 +1,250 @@ +import { ApolloClient, InMemoryCache, gql } from '@apollo/client'; +import { Client, cacheExchange, fetchExchange } from 'urql'; +import 'isomorphic-fetch'; + +const apolloClient = new ApolloClient({ + uri: 'https://beta-4.fuel.network/graphql', + cache: new InMemoryCache(), +}); + +const urqlClient = new Client({ + url: 'https://beta-4.fuel.network/graphql', + exchanges: [cacheExchange, fetchExchange], +}); + +describe('Latest blocks', () => { + test('get latest blocks with ts', async () => { + const LATEST_BLOCKS_QUERY = `query LatestBlocks { + blocks(last: 5) { + nodes { + id + transactions { + id + inputAssetIds + inputs { + __typename + ... on InputCoin { + owner + utxoId + amount + assetId + } + ... on InputContract { + utxoId + contract { + id + } + } + ... on InputMessage { + sender + recipient + amount + data + } + } + outputs { + __typename + ... on CoinOutput { + to + amount + assetId + } + ... on ContractOutput { + inputIndex + balanceRoot + stateRoot + } + ... on ChangeOutput { + to + amount + assetId + } + ... on VariableOutput { + to + amount + assetId + } + ... on ContractCreated { + contract { + id + } + stateRoot + } + } + gasPrice + } + } + } + }`; + + const getLatestBlocks = async () => { + const response = await fetch('https://beta-4.fuel.network/graphql', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Accept: 'application/json', + }, + body: JSON.stringify({ + query: LATEST_BLOCKS_QUERY, + }), + }); + const json = await response.json(); + console.log('BLOCKS:', json.data.blocks); + expect(json.data.blocks.nodes.length).toBeTruthy(); + }; + + await getLatestBlocks(); + }); + + test('get latest blocks with apollo', async () => { + const LATEST_BLOCKS_QUERY = `query LatestBlocks { + blocks(last: 5) { + nodes { + id + transactions { + id + inputAssetIds + inputs { + __typename + ... on InputCoin { + owner + utxoId + amount + assetId + } + ... on InputContract { + utxoId + contract { + id + } + } + ... on InputMessage { + sender + recipient + amount + data + } + } + outputs { + __typename + ... on CoinOutput { + to + amount + assetId + } + ... on ContractOutput { + inputIndex + balanceRoot + stateRoot + } + ... on ChangeOutput { + to + amount + assetId + } + ... on VariableOutput { + to + amount + assetId + } + ... on ContractCreated { + contract { + id + } + stateRoot + } + } + gasPrice + } + } + } + }`; + + const getLatestBlocks = async () => { + const response = await apolloClient.query({ + query: gql(LATEST_BLOCKS_QUERY), + }); + console.log('BLOCKS:', response.data.blocks); + expect(response.data.blocks.nodes.length).toBeTruthy(); + }; + + await getLatestBlocks(); + }); + + test('get latest blocks with urql', async () => { + const LATEST_BLOCKS_QUERY = `query LatestBlocks { + blocks(last: 5) { + nodes { + id + transactions { + id + inputAssetIds + inputs { + __typename + ... on InputCoin { + owner + utxoId + amount + assetId + } + ... on InputContract { + utxoId + contract { + id + } + } + ... on InputMessage { + sender + recipient + amount + data + } + } + outputs { + __typename + ... on CoinOutput { + to + amount + assetId + } + ... on ContractOutput { + inputIndex + balanceRoot + stateRoot + } + ... on ChangeOutput { + to + amount + assetId + } + ... on VariableOutput { + to + amount + assetId + } + ... on ContractCreated { + contract { + id + } + stateRoot + } + } + gasPrice + } + } + } + }`; + + const getLatestBlocks = async () => { + const response = await urqlClient + .query(LATEST_BLOCKS_QUERY, undefined) + .toPromise(); + console.log('BLOCKS:', response.data.blocks); + expect(response.data.blocks.nodes.length).toBeTruthy(); + }; + + await getLatestBlocks(); + }); +}); + +export {}; diff --git a/docs/beta-4/fuel-graphql-docs/examples/tests/latest-transactions.test.ts b/docs/beta-4/fuel-graphql-docs/examples/tests/latest-transactions.test.ts new file mode 100644 index 000000000..7eda5408e --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/examples/tests/latest-transactions.test.ts @@ -0,0 +1,265 @@ +import { ApolloClient, InMemoryCache, gql } from '@apollo/client'; +import { Client, cacheExchange, fetchExchange } from 'urql'; +import 'isomorphic-fetch'; + +const apolloClient = new ApolloClient({ + uri: 'https://beta-4.fuel.network/graphql', + cache: new InMemoryCache(), +}); + +const urqlClient = new Client({ + url: 'https://beta-4.fuel.network/graphql', + exchanges: [cacheExchange, fetchExchange], +}); + +describe('Latest transactions', () => { + test('get latest transactions with ts', async () => { + const LATEST_TRANSACTIONS_QUERY = ` + query LatestTransactions { + transactions(last: 5) { + nodes { + id + inputs { + __typename + ... on InputCoin { + owner + utxoId + amount + assetId + } + ... on InputContract { + utxoId + contract { + id + } + } + ... on InputMessage { + sender + recipient + amount + data + } + } + outputs { + __typename + ... on CoinOutput { + to + amount + assetId + } + ... on ContractOutput { + inputIndex + balanceRoot + stateRoot + } + ... on ChangeOutput { + to + amount + assetId + } + ... on VariableOutput { + to + amount + assetId + } + ... on ContractCreated { + contract { + id + } + stateRoot + } + } + status { + __typename + ... on FailureStatus { + reason + programState { + returnType + } + } + } + } + } + }`; + + const getLatestTransactions = async () => { + const response = await fetch('https://beta-4.fuel.network/graphql', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Accept: 'application/json', + }, + body: JSON.stringify({ + query: LATEST_TRANSACTIONS_QUERY, + }), + }); + const json = await response.json(); + console.log('TRANSACTIONS:', json.data.transactions); + expect(json.data.transactions.nodes.length).toBeTruthy(); + }; + + await getLatestTransactions(); + }); + + test('get latest transactions with apollo', async () => { + const LATEST_TRANSACTIONS_QUERY = ` + query LatestTransactions { + transactions(last: 5) { + nodes { + id + inputs { + __typename + ... on InputCoin { + owner + utxoId + amount + assetId + } + ... on InputContract { + utxoId + contract { + id + } + } + ... on InputMessage { + sender + recipient + amount + data + } + } + outputs { + __typename + ... on CoinOutput { + to + amount + assetId + } + ... on ContractOutput { + inputIndex + balanceRoot + stateRoot + } + ... on ChangeOutput { + to + amount + assetId + } + ... on VariableOutput { + to + amount + assetId + } + ... on ContractCreated { + contract { + id + } + stateRoot + } + } + status { + __typename + ... on FailureStatus { + reason + programState { + returnType + } + } + } + } + } + }`; + + const getLatestTransactions = async () => { + const response = await apolloClient.query({ + query: gql(LATEST_TRANSACTIONS_QUERY), + }); + console.log('TRANSACTIONS:', response.data.transactions); + expect(response.data.transactions.nodes.length).toBeTruthy(); + }; + + await getLatestTransactions(); + }); + + test('get latest transactions with urql', async () => { + const LATEST_TRANSACTIONS_QUERY = ` + query LatestTransactions { + transactions(last: 5) { + nodes { + id + inputs { + __typename + ... on InputCoin { + owner + utxoId + amount + assetId + } + ... on InputContract { + utxoId + contract { + id + } + } + ... on InputMessage { + sender + recipient + amount + data + } + } + outputs { + __typename + ... on CoinOutput { + to + amount + assetId + } + ... on ContractOutput { + inputIndex + balanceRoot + stateRoot + } + ... on ChangeOutput { + to + amount + assetId + } + ... on VariableOutput { + to + amount + assetId + } + ... on ContractCreated { + contract { + id + } + stateRoot + } + } + status { + __typename + ... on FailureStatus { + reason + programState { + returnType + } + } + } + } + } + }`; + + const getLatestTransactions = async () => { + const response = await urqlClient + .query(LATEST_TRANSACTIONS_QUERY, undefined) + .toPromise(); + console.log('TRANSACTIONS:', response.data.transactions); + expect(response.data.transactions.nodes.length).toBeTruthy(); + }; + + await getLatestTransactions(); + }); +}); + +export {}; diff --git a/docs/beta-4/fuel-graphql-docs/examples/tests/messages.test.ts b/docs/beta-4/fuel-graphql-docs/examples/tests/messages.test.ts new file mode 100644 index 000000000..02ebd72f2 --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/examples/tests/messages.test.ts @@ -0,0 +1,119 @@ +import { ApolloClient, InMemoryCache, gql } from '@apollo/client'; +import { Client, cacheExchange, fetchExchange } from 'urql'; +import 'isomorphic-fetch'; + +const apolloClient = new ApolloClient({ + uri: 'https://beta-4.fuel.network/graphql', + cache: new InMemoryCache(), +}); + +const urqlClient = new Client({ + url: 'https://beta-4.fuel.network/graphql', + exchanges: [cacheExchange, fetchExchange], +}); + +describe('Messages', () => { + test('get messages with ts', async () => { + const MESSAGES_QUERY = ` + query MessageInfo($address: Address) { + messages(owner: $address, first: 5) { + nodes { + amount + sender + recipient + nonce + data + daHeight + } + } + }`; + + const args = { + address: + '0xf65d6448a273b531ee942c133bb91a6f904c7d7f3104cdaf6b9f7f50d3518871', + }; + + const getMessages = async () => { + const response = await fetch('https://beta-4.fuel.network/graphql', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Accept: 'application/json', + }, + body: JSON.stringify({ + query: MESSAGES_QUERY, + variables: args, + }), + }); + const json = await response.json(); + console.log('MESSAGES:', json.data.messages); + expect(json.data.messages.nodes).toBeTruthy(); + }; + + await getMessages(); + }); + + test('get messages with apollo', async () => { + const MESSAGES_QUERY = ` + query MessageInfo($address: Address) { + messages(owner: $address, first: 5) { + nodes { + amount + sender + recipient + nonce + data + daHeight + + } + } + }`; + + const args = { + address: + '0xf65d6448a273b531ee942c133bb91a6f904c7d7f3104cdaf6b9f7f50d3518871', + }; + + const getMessages = async () => { + const response = await apolloClient.query({ + query: gql(MESSAGES_QUERY), + variables: args, + }); + console.log('MESSAGES:', response.data.messages); + expect(response.data.messages.nodes).toBeTruthy(); + }; + + await getMessages(); + }); + + test('get messages with urql', async () => { + const MESSAGES_QUERY = ` + query MessageInfo($address: Address) { + messages(owner: $address, first: 5) { + nodes { + amount + sender + recipient + nonce + data + daHeight + } + } + }`; + + const args = { + address: + '0xf65d6448a273b531ee942c133bb91a6f904c7d7f3104cdaf6b9f7f50d3518871', + }; + + const getMessages = async () => { + const response = await urqlClient.query(MESSAGES_QUERY, args).toPromise(); + console.log('MESSAGES:', response.data.messages); + expect(response.data.messages.nodes).toBeTruthy(); + }; + + await getMessages(); + }); +}); + +export {}; diff --git a/docs/beta-4/fuel-graphql-docs/examples/tests/transactions-by-owner.test.ts b/docs/beta-4/fuel-graphql-docs/examples/tests/transactions-by-owner.test.ts new file mode 100644 index 000000000..1e4dc0dab --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/examples/tests/transactions-by-owner.test.ts @@ -0,0 +1,282 @@ +import { ApolloClient, InMemoryCache, gql } from '@apollo/client'; +import { Client, cacheExchange, fetchExchange } from 'urql'; +import 'isomorphic-fetch'; + +const apolloClient = new ApolloClient({ + uri: 'https://beta-4.fuel.network/graphql', + cache: new InMemoryCache(), +}); + +const urqlClient = new Client({ + url: 'https://beta-4.fuel.network/graphql', + exchanges: [cacheExchange, fetchExchange], +}); + +describe('Transactions by owner', () => { + test('get transactions with ts', async () => { + const TRANSACTIONS_BY_OWNER_QUERY = ` + query Transactions($address: Address) { + transactionsByOwner(owner: $address, first: 5) { + nodes { + id + inputs { + __typename + ... on InputCoin { + owner + utxoId + amount + assetId + } + ... on InputContract { + utxoId + contract { + id + } + } + ... on InputMessage { + sender + recipient + amount + data + } + } + outputs { + __typename + ... on CoinOutput { + to + amount + assetId + } + ... on ContractOutput { + inputIndex + balanceRoot + stateRoot + } + ... on ChangeOutput { + to + amount + assetId + } + ... on VariableOutput { + to + amount + assetId + } + ... on ContractCreated { + contract { + id + } + stateRoot + } + } + status { + __typename + ... on FailureStatus { + reason + programState { + returnType + } + } + } + } + } + }`; + + const args = { + address: + '0xf65d6448a273b531ee942c133bb91a6f904c7d7f3104cdaf6b9f7f50d3518871', + }; + + const getTransactions = async () => { + const response = await fetch('https://beta-4.fuel.network/graphql', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Accept: 'application/json', + }, + body: JSON.stringify({ + query: TRANSACTIONS_BY_OWNER_QUERY, + variables: args, + }), + }); + const json = await response.json(); + console.log('TRANSACTIONS:', json.data.transactionsByOwner); + expect(json.data.transactionsByOwner.nodes.length).toBeTruthy(); + }; + + await getTransactions(); + }); + + test('get transactions with apollo', async () => { + const TRANSACTIONS_BY_OWNER_QUERY = ` + query Transactions($address: Address) { + transactionsByOwner(owner: $address, first: 5) { + nodes { + id + inputs { + __typename + ... on InputCoin { + owner + utxoId + amount + assetId + } + ... on InputContract { + utxoId + contract { + id + } + } + ... on InputMessage { + sender + recipient + amount + data + } + } + outputs { + __typename + ... on CoinOutput { + to + amount + assetId + } + ... on ContractOutput { + inputIndex + balanceRoot + stateRoot + } + ... on ChangeOutput { + to + amount + assetId + } + ... on VariableOutput { + to + amount + assetId + } + ... on ContractCreated { + contract { + id + } + stateRoot + } + } + status { + __typename + ... on FailureStatus { + reason + programState { + returnType + } + } + } + } + } + }`; + + const args = { + address: + '0xf65d6448a273b531ee942c133bb91a6f904c7d7f3104cdaf6b9f7f50d3518871', + }; + + const getTransactions = async () => { + const response = await apolloClient.query({ + query: gql(TRANSACTIONS_BY_OWNER_QUERY), + variables: args, + }); + console.log('TRANSACTIONS:', response.data.transactionsByOwner); + expect(response.data.transactionsByOwner.nodes.length).toBeTruthy(); + }; + + await getTransactions(); + }); + + test('get transactions with urql', async () => { + const TRANSACTIONS_BY_OWNER_QUERY = ` + query Transactions($address: Address) { + transactionsByOwner(owner: $address, first: 5) { + nodes { + id + inputs { + __typename + ... on InputCoin { + owner + utxoId + amount + assetId + } + ... on InputContract { + utxoId + contract { + id + } + } + ... on InputMessage { + sender + recipient + amount + data + } + } + outputs { + __typename + ... on CoinOutput { + to + amount + assetId + } + ... on ContractOutput { + inputIndex + balanceRoot + stateRoot + } + ... on ChangeOutput { + to + amount + assetId + } + ... on VariableOutput { + to + amount + assetId + } + ... on ContractCreated { + contract { + id + } + stateRoot + } + } + status { + __typename + ... on FailureStatus { + reason + programState { + returnType + } + } + } + } + } + }`; + + const args = { + address: + '0xf65d6448a273b531ee942c133bb91a6f904c7d7f3104cdaf6b9f7f50d3518871', + }; + + const getTransactions = async () => { + const response = await urqlClient + .query(TRANSACTIONS_BY_OWNER_QUERY, args) + .toPromise(); + console.log('TRANSACTIONS:', response.data.transactionsByOwner); + expect(response.data.transactionsByOwner.nodes.length).toBeTruthy(); + }; + + await getTransactions(); + }); +}); + +export {}; diff --git a/docs/beta-4/fuel-graphql-docs/package.json b/docs/beta-4/fuel-graphql-docs/package.json new file mode 100644 index 000000000..9dbe54cc2 --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/package.json @@ -0,0 +1,97 @@ +{ + "name": "docs", + "version": "0.0.1", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "check:prod": "npm run lint:prod && npm run prettier:check", + "export": "DOCS_DIST=${DOCS_DIST:=dist} next export -o $DOCS_DIST", + "start": "next start", + "lint": "eslint . --ext .ts,.tsx,.js,.jsx", + "lint:fix": "eslint . --ext .ts,.tsx,.js,.jsx --fix", + "lint:prod": "eslint . --ext .ts,.tsx,.js,.jsx -c .eslintrc.prod", + "lint:docs:check": "markdownlint --config .markdownlint.yaml '**/*.mdx'", + "lint:docs:fix": "markdownlint --config .markdownlint.yaml '**/*.mdx' --fix", + "test:examples": "jest -c jest.examples.ts", + "prettier:check": "prettier --check .", + "prettier:format": "prettier --write ." + }, + "dependencies": { + "@apollo/client": "^3.8.6", + "@docsearch/css": "^3.5.2", + "@docsearch/react": "3.5.2", + "@fuel-ui/css": "0.21.0-pr-305-04b8434", + "@fuel-ui/icons": "0.21.0-pr-305-04b8434", + "@fuel-ui/react": "0.21.0-pr-305-04b8434", + "@fuel-wallet/sdk": "0.13.0", + "@fuels/eslint-plugin": "^0.0.8", + "@fuels/prettier-config": "^0.0.8", + "@fuels/ts-config": "^0.0.8", + "@mdx-js/mdx": "^2.3.0", + "@mdx-js/react": "^2.3.0", + "acorn": "^8.10.0", + "acorn-loose": "^8.3.0", + "acorn-walk": "^8.2.0", + "cookie": "^0.5.0", + "dotenv": "^16.3.1", + "framer-motion": "^10.16.4", + "fuels": "0.60.0", + "globby": "^13.2.2", + "graphql": "^16.8.1", + "gray-matter": "^4.0.3", + "hast-util-from-text": "^2.0.1", + "hast-util-heading-rank": "^2.1.1", + "hast-util-to-string": "^2.0.0", + "hast-util-to-text": "^3.1.2", + "hastscript": "^7.2.0", + "isomorphic-fetch": "^3.0.0", + "markdownlint-cli": "^0.37.0", + "next": "13.4.19", + "next-mdx-remote": "^4.4.1", + "node-html-markdown": "^1.3.0", + "plyr-react": "^5.3.0", + "pm2": "^5.3.0", + "prettier": "2.8.0", + "react": "^18.2.0", + "react-aria": "^3.27.0", + "react-dom": "^18.2.0", + "react-hook-form": "^7.46.1", + "react-syntax-highlighter": "^15.5.0", + "rehype-pretty-code": "^0.10.0", + "remark": "^14.0.3", + "remark-frontmatter": "^4.0.1", + "remark-gfm": "^3.0.1", + "remark-mdx": "^2.3.0", + "remark-parse": "^10.0.2", + "remark-slug": "^7.0.1", + "strip-indent": "^4.0.0", + "swr": "^2.2.2", + "unified": "^10.1.2", + "unist-util-visit": "^5.0.0", + "updates": "^15.0.2", + "urql": "^4.0.5", + "vfile": "^6.0.1" + }, + "devDependencies": { + "@next/eslint-plugin-next": "^13.4.12", + "@playwright/test": "^1.36.2", + "@types/chrome": "^0.0.245", + "@types/cookie": "^0.5.2", + "@types/jest": "^29.5.6", + "@types/node": "^20.5.9", + "@types/react": "^18.2.21", + "@types/react-dom": "^18.2.7", + "@types/react-syntax-highlighter": "^15.5.7", + "@typescript-eslint/eslint-plugin": "^6.9.0", + "eslint": "^8.48.0", + "husky": "^8.0.3", + "lint-staged": "^14.0.1", + "npm-run-all": "^4.1.5", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "sharp": "^0.32.5", + "ts-jest": "^29.0.3", + "typescript": "^5.2.2" + } +} diff --git a/docs/beta-4/fuel-graphql-docs/src/components.json b/docs/beta-4/fuel-graphql-docs/src/components.json new file mode 100644 index 000000000..29de4f3d6 --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/src/components.json @@ -0,0 +1,4 @@ +{ + "folders": ["/src/components"], + "ignore": ["CodeImport", "CodeExamples", "GQLExamples"] +} diff --git a/docs/beta-4/fuel-graphql-docs/src/components/Blockquote.tsx b/docs/beta-4/fuel-graphql-docs/src/components/Blockquote.tsx new file mode 100644 index 000000000..946eebd95 --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/src/components/Blockquote.tsx @@ -0,0 +1,36 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +import { cssObj } from '@fuel-ui/css'; +import { Box } from '@fuel-ui/react'; + +export function Blockquote(props: any) { + return ; +} + +const styles = { + root: cssObj({ + position: 'relative', + my: '$6', + mx: '$0', + py: '$3', + pl: '$4', + background: '$gray1', + color: '$gray9', + fontStyle: 'italic', + + '& > p': { + margin: '$0', + }, + + '&:before': { + position: 'absolute', + display: 'block', + content: '""', + top: 0, + left: 0, + width: 4, + height: '100%', + background: '$gray3', + }, + }), +}; diff --git a/docs/beta-4/fuel-graphql-docs/src/components/Breadcrumb.tsx b/docs/beta-4/fuel-graphql-docs/src/components/Breadcrumb.tsx new file mode 100644 index 000000000..2a5e6d841 --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/src/components/Breadcrumb.tsx @@ -0,0 +1,43 @@ +import { cssObj } from '@fuel-ui/css'; +import { Box, Icon, Text } from '@fuel-ui/react'; +import Link from 'next/link'; +import type { DocType } from '~/src/types'; + +type BreadcrumbProps = { + doc: DocType; +}; + +export function Breadcrumb({ doc }: BreadcrumbProps) { + return ( + + + Docs + + {doc.category && ( + + + {doc.category} + + + )} + {doc.title} + + ); +} + +const styles = { + root: cssObj({ + alignItems: 'center', + gap: '$2', + + span: { + color: '$gray8', + fontSize: '$sm', + }, + '& > span:last-of-type': { + color: '$gray10', + }, + }), +}; diff --git a/docs/beta-4/fuel-graphql-docs/src/components/Code.tsx b/docs/beta-4/fuel-graphql-docs/src/components/Code.tsx new file mode 100644 index 000000000..b6ec41c4d --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/src/components/Code.tsx @@ -0,0 +1,21 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +import { cssObj } from '@fuel-ui/css'; +import { Box } from '@fuel-ui/react'; + +export function Code(props: any) { + return ; +} + +const styles = { + root: cssObj({ + pt: '2px', + pb: '3px', + px: '6px', + borderRadius: '$md', + fontFamily: 'monospace', + background: '$gray3', + // color: '$gray10', + // fontSize: '0.9rem', + }), +}; diff --git a/docs/beta-4/fuel-graphql-docs/src/components/CodeExamples.tsx b/docs/beta-4/fuel-graphql-docs/src/components/CodeExamples.tsx new file mode 100644 index 000000000..004504126 --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/src/components/CodeExamples.tsx @@ -0,0 +1,159 @@ +import { cssObj } from '@fuel-ui/css'; +import { Link, Tabs, Box } from '@fuel-ui/react'; + +import { REPO_LINK } from '../constants'; + +import { Pre } from './Pre'; + +export type CodeExamplesProps = { + file: string; + ts_lines?: number[]; + apollo_lines?: number[]; + urql_lines?: number[]; + ts_testCase?: string; + apollo_testCase?: string; + urql_testCase?: string; + ts_title?: string; + apollo_title?: string; + urql_title?: string; + __ts_content: string; + __apollo_content: string; + __urql_content: string; + __filepath: string; + __filename: string; + __ts_language: string; + __ts_lineStart: number; + __apollo_lineStart: number; + __urql_lineStart: number; + __ts_lineEnd?: number; + __apollo_lineEnd?: number; + __urql_lineEnd?: number; +}; + +export function CodeExamples({ + __ts_content: ts_content, + __apollo_content: apollo_content, + __urql_content: urql_content, + __filepath: filePath, + __filename: filename, + __ts_language: ts_language, + __ts_lineStart: ts_lineStart, + __apollo_lineStart: apollo_lineStart, + __urql_lineStart: urql_lineStart, + __ts_lineEnd: ts_lineEnd, + __apollo_lineEnd: apollo_lineEnd, + __urql_lineEnd: urql_lineEnd, +}: CodeExamplesProps) { + const ts_lines = `L${ts_lineStart}${ts_lineEnd ? `-L${ts_lineEnd}` : ''}`; + const apollo_lines = `L${apollo_lineStart}${ + apollo_lineEnd ? `-L${apollo_lineEnd}` : '' + }`; + const urql_lines = `L${urql_lineStart}${ + urql_lineEnd ? `-L${urql_lineEnd}` : '' + }`; + const ts_link = `${REPO_LINK}tree/main/${filePath}#${ts_lines}`; + const apollo_link = `${REPO_LINK}tree/main/${filePath}#${apollo_lines}`; + const urql_link = `${REPO_LINK}tree/main/${filePath}#${urql_lines}`; + + const apolloImport = `import { ApolloClient, InMemoryCache, gql } from '@apollo/client'; + +const apolloClient= new ApolloClient({ + uri: 'https://beta-4.fuel.network/graphql', + cache: new InMemoryCache(), +}); + +`; + + const urqlImport = `import { Client, cacheExchange, fetchExchange } from 'urql'; + +const urqlClient = new Client({ + url: 'https://beta-4.fuel.network/graphql', + exchanges: [cacheExchange, fetchExchange], +}); + +`; + + const codeTitle = (linkType: string) => ( + <> + + {filename} + + + ); + + interface TabContentProps { + value: string; + content: string; + codeLink: string; + } + + const TabContent = ({ value, content, codeLink }: TabContentProps) => { + const title = codeTitle(codeLink); + return ( + +
+          {content}
+        
+
+ ); + }; + + return ( + + + + + TypeScript + + + Apollo Client + + + urql + + + + + + + + ); +} + +const styles = { + tabsTrigger: cssObj({ + fontSize: 'var(--fontSizes-default)', + }), + tabs: cssObj({ + justifyContent: 'space-around', + padding: '$2 0', + margin: '0', + }), + tabsContainer: cssObj({ + marginTop: '$8', + backgroundColor: '$gray1', + borderRadius: '8px', + }), + codeContainer: cssObj({ + maxHeight: '500px', + overflow: 'scroll', + }), + filename: cssObj({ + '&, &:visited': { + fontSize: '$sm', + color: '$gray9', + }, + '&:hover': { + color: '$gray11', + textDecoration: 'none', + }, + }), +}; diff --git a/docs/beta-4/fuel-graphql-docs/src/components/CodeImport.tsx b/docs/beta-4/fuel-graphql-docs/src/components/CodeImport.tsx new file mode 100644 index 000000000..da2fca404 --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/src/components/CodeImport.tsx @@ -0,0 +1,55 @@ +import { cssObj } from '@fuel-ui/css'; +import { Link } from '@fuel-ui/react'; +import { REPO_LINK } from '~/src/constants'; + +import { Pre } from './Pre'; + +export type CodeImportProps = { + file: string; + lines?: number[]; + testCase?: string; + title?: string; + __content: string; + __filepath: string; + __filename: string; + __language: string; + __lineStart: number; + __lineEnd?: number; +}; + +export function CodeImport({ + __content: content, + __filepath: filePath, + __filename: filename, + __language: language, + __lineStart: lineStart, + __lineEnd: lineEnd, +}: CodeImportProps) { + const lines = `L${lineStart}${lineEnd ? `-L${lineEnd}` : ''}`; + const link = `${REPO_LINK}/${filePath}#${lines}`; + const title = ( + <> + + {filename} + + + ); + return ( +
+      {content}
+    
+ ); +} + +const styles = { + filename: cssObj({ + '&, &:visited': { + fontSize: '$sm', + color: '$gray9', + }, + '&:hover': { + color: '$gray11', + textDecoration: 'none', + }, + }), +}; diff --git a/docs/beta-4/fuel-graphql-docs/src/components/DocFooter.tsx b/docs/beta-4/fuel-graphql-docs/src/components/DocFooter.tsx new file mode 100644 index 000000000..6031d74d8 --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/src/components/DocFooter.tsx @@ -0,0 +1,65 @@ +import { cssObj } from '@fuel-ui/css'; +import { Box, Icon } from '@fuel-ui/react'; +import Link from 'next/link'; +import { useRouter } from 'next/router'; +import { useDocContext } from '~/src/hooks/useDocContext'; + +export function DocFooter() { + const { docLink } = useDocContext(); + const router = useRouter(); + return ( + + + {docLink.prev && ( + + {docLink.prev.label} + + )} + + + {docLink.next && ( + + {docLink.next.label} + + )} + + + ); +} + +const styles = { + root: cssObj({ + pb: '$4', + pt: '$4', + mt: '$6', + display: 'flex', + borderTop: '1px dashed $gray3', + + a: { + display: 'inline-flex', + alignItems: 'center', + gap: '$4', + color: '$gray9', + }, + 'a:hover': { + color: '#00F58C', + }, + + '@xl': { + pt: '$12', + mt: '$14', + }, + + '@md': { + a: { + fontSize: '$xl', + }, + }, + }), +}; diff --git a/docs/beta-4/fuel-graphql-docs/src/components/ExampleBox.tsx b/docs/beta-4/fuel-graphql-docs/src/components/ExampleBox.tsx new file mode 100644 index 000000000..845dd7db5 --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/src/components/ExampleBox.tsx @@ -0,0 +1,52 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { cssObj } from '@fuel-ui/css'; +import { Box, Text } from '@fuel-ui/react'; +import type { ReactNode } from 'react'; + +export function ExampleBox({ + children, + error, +}: { + children: ReactNode; + error?: any; +}) { + return ( + + + {error && {error.message}} + {children} + + + ); +} + +const styles = { + root: cssObj({ + display: 'flex', + flexDirection: 'column', + gap: '$4', + padding: '$4', + borderRadius: '$md', + border: '1px dashed $gray3', + maxWidth: '90vw', + overflowWrap: 'break-word', + '@xl': { + maxWidth: '55vw', + }, + h6: { + display: 'flex', + alignItems: 'center', + justifyContent: 'space-between', + margin: '$0', + color: '$gray10', + gap: '$2', + + '& .fuel_icon': { + color: 'currentColor', + }, + }, + }), + alert: cssObj({ + maxWidth: '100%', + }), +}; diff --git a/docs/beta-4/fuel-graphql-docs/src/components/Header.tsx b/docs/beta-4/fuel-graphql-docs/src/components/Header.tsx new file mode 100644 index 000000000..7aa49e6d7 --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/src/components/Header.tsx @@ -0,0 +1,110 @@ +import { cssObj } from '@fuel-ui/css'; +import { Box, Icon } from '@fuel-ui/react'; +import Image from 'next/image'; +import Link from 'next/link'; + +import { MobileMenu } from './MobileMenu'; +import { Search } from './Search'; + +export function Header() { + return ( + + + + Fuel Logo + + Fuel GraphQL Docs + + + + + + + + + + + + + + ); +} + +const styles = { + root: cssObj({ + zIndex: '$10', + position: 'sticky', + top: 0, + background: '#090a0a', + gap: '$2', + py: '$4', + px: '$4', + alignItems: 'center', + borderBottom: '1px solid $gray2', + gridColumn: '1 / 4', + + '.logo': { + display: 'inline-flex', + color: '$gray9', + }, + + '@md': { + px: '$8', + }, + + '@xl': { + position: 'relative', + py: '$4', + px: '$8', + }, + }), + logoText: cssObj({ + alignItems: 'center', + flex: 1, + fontSize: '$lg', + fontWeight: '$semibold', + marginLeft: '$2', + }), + version: cssObj({ + ml: '$2', + color: '$gray8', + fontSize: '$xs', + fontStyle: 'italic', + }), + desktop: cssObj({ + display: 'none', + + '@xl': { + display: 'flex', + alignItems: 'center', + }, + }), + mobile: cssObj({ + display: 'flex', + alignItems: 'center', + '.fuel_button': { + height: 'auto !important', + padding: '$0 !important', + }, + + '@xl': { + display: 'none', + }, + }), + menu: cssObj({ + gap: '$6', + + a: { + color: '$gray10', + transition: 'all 0.3s', + }, + + 'a.active, a:hover': { + color: '#00F58C', + }, + }), +}; diff --git a/docs/beta-4/fuel-graphql-docs/src/components/Heading.tsx b/docs/beta-4/fuel-graphql-docs/src/components/Heading.tsx new file mode 100644 index 000000000..a6d9a4f6d --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/src/components/Heading.tsx @@ -0,0 +1,55 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { cssObj } from '@fuel-ui/css'; +import { Heading as FuelHeading } from '@fuel-ui/react'; +import Link from 'next/link'; +import { useRouter } from 'next/router'; +import { useState, useEffect } from 'react'; + +export function Heading({ children, ...props }: any) { + const [link, setLink] = useState(); + const router = useRouter(); + + useEffect(() => { + if (typeof children == 'string') { + setLink(children.replace(/[\s_]+/g, '-').toLowerCase()); + } else if (typeof children == 'object' && children.props) { + setLink(children.props.children.replace(/[\s_]+/g, '-').toLowerCase()); + } + }, [children]); + + return ( + + + {children} + + + ); +} + +const styles = { + root: cssObj({ + '&[data-rank=h1]': { + mb: '$6', + color: '$gray12', + }, + '&[data-rank=h2]': { + mt: '$12', + mb: '$5', + pb: '$2', + color: '$gray12', + borderBottom: '1px dashed $gray3', + }, + '&[data-rank=h3]': { + mt: '$8', + mb: '$4', + color: '$gray11', + }, + '&[data-rank=h4], &[data-rank=h5], &[data-rank=h6]': { + mt: '$6', + mb: '$2', + color: '$gray11', + }, + }), +}; diff --git a/docs/beta-4/fuel-graphql-docs/src/components/Layout.tsx b/docs/beta-4/fuel-graphql-docs/src/components/Layout.tsx new file mode 100644 index 000000000..985efc9e4 --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/src/components/Layout.tsx @@ -0,0 +1,50 @@ +import { cssObj } from '@fuel-ui/css'; +import { Box } from '@fuel-ui/react'; +import Head from 'next/head'; +import type { ReactNode } from 'react'; + +import { META_DESC, META_OGIMG } from '../constants'; + +import { Header } from './Header'; + +type LayoutProps = { + title?: string; + children: ReactNode; +}; + +export function Layout({ title, children }: LayoutProps) { + const titleText = title + ? `${title} | Fuel GraphQL Docs` + : 'Fuel GraphQL Docs'; + return ( + <> + + {titleText} + + + + + + +
+ {children} + + + ); +} + +const styles = { + root: cssObj({ + maxW: '100vw', + height: '100vh', + display: 'grid', + gridTemplateColumns: '1fr', + gridTemplateRows: '80px auto', + + '@xl': { + gridTemplateColumns: '0.75fr 2.5fr 0.75fr', + gridTemplateRows: '80px auto', + gridColumnGap: '$14', + }, + }), +}; diff --git a/docs/beta-4/fuel-graphql-docs/src/components/Link.tsx b/docs/beta-4/fuel-graphql-docs/src/components/Link.tsx new file mode 100644 index 000000000..b0b066e58 --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/src/components/Link.tsx @@ -0,0 +1,6 @@ +import type { LinkProps } from '@fuel-ui/react'; +import { Link as FuelLink } from '@fuel-ui/react'; + +export function Link(props: LinkProps) { + return ; +} diff --git a/docs/beta-4/fuel-graphql-docs/src/components/List.tsx b/docs/beta-4/fuel-graphql-docs/src/components/List.tsx new file mode 100644 index 000000000..8dfc18482 --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/src/components/List.tsx @@ -0,0 +1,33 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +import { cssObj } from '@fuel-ui/css'; +import { List } from '@fuel-ui/react'; + +export function UL({ children, ...props }: any) { + const isOrdered = children.some((c: any) => c?.type === 'ol'); + return ( + + {children + .map((child: any, idx: number) => { + if (!child?.type) return null; + return {child.props.children}; + }) + .filter(Boolean)} + + ); +} + +const styles = { + root: cssObj({ + ml: '$4', + listStyle: 'outside', + li: { + pl: '$2', + lineHeight: '1.7', + }, + }), +}; diff --git a/docs/beta-4/fuel-graphql-docs/src/components/MobileMenu.tsx b/docs/beta-4/fuel-graphql-docs/src/components/MobileMenu.tsx new file mode 100644 index 000000000..9acab4921 --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/src/components/MobileMenu.tsx @@ -0,0 +1,145 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { cssObj } from '@fuel-ui/css'; +import { Box, IconButton, Icon } from '@fuel-ui/react'; +import { AnimatePresence, motion } from 'framer-motion'; +import type { AnimationProps } from 'framer-motion'; +import Image from 'next/image'; +import { useEffect, useState } from 'react'; + +import { Search } from './Search'; +import { Sidebar } from './Sidebar'; + +const MotionBox = motion(Box); +const SPRING: AnimationProps['transition'] = { + ease: 'linear', + duration: '0.1', +}; + +export function MobileMenu() { + const [showing, setShowing] = useState(false); + + function toggle() { + setShowing((s) => !s); + } + + useEffect(() => { + if (showing) { + document.body.classList.add('no-scroll'); + } else { + document.body.classList.remove('no-scroll'); + } + }, [showing]); + + const button = ( + + ); + + const content = ( + + + + Fuel Logo + + + + + {button} + + + + ); + + return ( + + + {button} + + {showing && {content}} + + + ); +} + +const styles = { + root: cssObj({ + display: 'flex', + alignItems: 'center', + gap: '$4', + + '.mobile-button': { + height: 'auto !important', + padding: '$0 !important', + color: '$gray8 !important', + }, + + '@xl': { + display: 'none', + }, + }), + menu: cssObj({ + pb: '$4', + mb: '$4', + borderBottom: '1px solid $gray3', + gap: '$6', + alignItems: 'center', + justifyContent: 'space-between', + + a: { + color: '$gray10', + transition: 'all 0.3s', + }, + + 'a.active, a:hover': { + color: '#00F58C', + }, + + '& > .fuel_box': { + gap: '$4', + alignItems: 'center', + }, + }), + overlay: cssObj({ + display: 'flex', + flexDirection: 'row-reverse', + zIndex: '$10', + position: 'fixed', + top: 0, + left: 0, + right: 0, + bottom: 0, + width: '100vw', + height: '100vh', + background: 'rgba(0,0,0,.8)', + overflow: 'hidden', + boxSizing: 'border-box', + }), + content: cssObj({ + boxSizing: 'border-box', + padding: '$6', + width: '100vw', + height: '100%', + background: '$bodyColor', + + '@sm': { + width: '400px', + }, + }), +}; diff --git a/docs/beta-4/fuel-graphql-docs/src/components/Paragraph.tsx b/docs/beta-4/fuel-graphql-docs/src/components/Paragraph.tsx new file mode 100644 index 000000000..0a742382b --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/src/components/Paragraph.tsx @@ -0,0 +1,17 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +import { cssObj } from '@fuel-ui/css'; +import { Text } from '@fuel-ui/react'; + +export function Paragraph(props: any) { + return ; +} + +const styles = { + root: cssObj({ + mt: '$3', + mb: '$5', + textSize: 'base', + lineHeight: '1.7', + }), +}; diff --git a/docs/beta-4/fuel-graphql-docs/src/components/Player.tsx b/docs/beta-4/fuel-graphql-docs/src/components/Player.tsx new file mode 100644 index 000000000..feb77bc87 --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/src/components/Player.tsx @@ -0,0 +1,46 @@ +'use client'; + +import { cssObj } from '@fuel-ui/css'; +import { Box } from '@fuel-ui/react'; +import Plyr from 'plyr-react'; +import type { PlyrProps } from 'plyr-react'; +import { useEffect, useState } from 'react'; + +type PlayerProps = PlyrProps & { + src: string; +}; + +export default function Player({ src, ...props }: PlayerProps) { + const [showing, setShowing] = useState(false); + + useEffect(() => { + setShowing(true); + }, []); + + return ( + showing && ( + + + + ) + ); +} + +const styles = { + root: cssObj({ + my: '$8', + fontFamily: '$sans', + + '.video-react-duration, .video-react-current-time': { + fontFamily: '$sans', + }, + }), +}; diff --git a/docs/beta-4/fuel-graphql-docs/src/components/Pre.tsx b/docs/beta-4/fuel-graphql-docs/src/components/Pre.tsx new file mode 100644 index 000000000..70437f448 --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/src/components/Pre.tsx @@ -0,0 +1,109 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +import { cssObj } from '@fuel-ui/css'; +import { Box, Icon, IconButton, Text } from '@fuel-ui/react'; +import { Children } from 'react'; +import type { ReactNode } from 'react'; +import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; +import theme from 'react-syntax-highlighter/dist/cjs/styles/prism/night-owl'; + +type PreProps = { + children: ReactNode; + title?: ReactNode; +}; + +export function Pre({ children, title }: PreProps) { + const codeEl: any = Children.toArray(children)[0]; + const codeStr = codeEl?.props.children || ''; + const code = codeStr.endsWith('\n') ? codeStr.slice(0, -1) : codeStr; + const language = codeEl?.props.className.replace('language-', ''); + + return ( + + + typeof window !== 'undefined' && navigator.clipboard.writeText(code) + } + /> + {title && {title}} + + {code} + + + ); +} + +const styles = { + root: cssObj({ + boxSizing: 'border-box', + position: 'relative', + maxWidth: 'calc(100vw - $8)', + + pre: { + pr: '50px', + mb: '$5 !important', + padding: '$4 $2 !important', + borderRadius: '$lg', + fontSize: '14px !important', + background: '$gray1 !important', + }, + 'pre[data-title=true]': { + marginTop: '$0 !important', + borderTopLeftRadius: '$0', + borderTopRightRadius: '$0', + }, + + h6: { + display: 'flex', + alignItems: 'center', + margin: 0, + padding: '$1 $3', + background: '$gray2', + color: '$gray10', + borderTopLeftRadius: '$lg', + borderTopRightRadius: '$lg', + borderBottom: '2px solid $bodyColor', + + span: { + fontSize: '$sm', + }, + a: { + color: '$gray10', + }, + }, + + '.token.plain': { + color: '$gray11', + }, + + '.linenumber': { + boxSizing: 'border-box', + minWidth: '30px !important', + color: '$gray8 !important', + mr: '$1', + }, + }), + copyIcon: cssObj({ + position: 'absolute', + right: 0, + top: 0, + color: '$gray7 !important', + transition: 'all .3s', + background: '$gray1 !important', + + '&:hover': { + color: '$gray9 !important', + }, + }), +}; diff --git a/docs/beta-4/fuel-graphql-docs/src/components/Provider.tsx b/docs/beta-4/fuel-graphql-docs/src/components/Provider.tsx new file mode 100644 index 000000000..ce1e4b6d9 --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/src/components/Provider.tsx @@ -0,0 +1,53 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +'use client'; + +import { ThemeProvider } from '@fuel-ui/react'; +import { MDXProvider } from '@mdx-js/react'; +import type { ReactNode } from 'react'; + +import * as GQLExamples from '../../examples'; + +import { Blockquote } from './Blockquote'; +import { Code } from './Code'; +import { CodeExamples } from './CodeExamples'; +import { CodeImport } from './CodeImport'; +import { Heading } from './Heading'; +import { Link } from './Link'; +import { UL } from './List'; +import { Paragraph } from './Paragraph'; +import Player from './Player'; +import { Pre } from './Pre'; +import { Table } from './Table'; + +const components = { + a: Link, + h1: Heading, + h2: Heading, + h3: Heading, + h4: Heading, + h5: Heading, + h6: Heading, + pre: Pre, + p: Paragraph, + code: Code, + blockquote: Blockquote, + table: Table, + ul: UL, + CodeImport, + Player, + GQLExamples, + CodeExamples, +}; + +type ProviderProps = { + children: ReactNode; +}; + +export function Provider({ children }: ProviderProps) { + return ( + + {children} + + ); +} diff --git a/docs/beta-4/fuel-graphql-docs/src/components/Search.tsx b/docs/beta-4/fuel-graphql-docs/src/components/Search.tsx new file mode 100644 index 000000000..265307314 --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/src/components/Search.tsx @@ -0,0 +1,13 @@ +import { DocSearch } from '@docsearch/react'; +import docsearch from '~/docsearch.json'; + +export function Search() { + return ( + + ); +} diff --git a/docs/beta-4/fuel-graphql-docs/src/components/Sidebar.tsx b/docs/beta-4/fuel-graphql-docs/src/components/Sidebar.tsx new file mode 100644 index 000000000..78b703a39 --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/src/components/Sidebar.tsx @@ -0,0 +1,37 @@ +import { cssObj } from '@fuel-ui/css'; +import { Box } from '@fuel-ui/react'; +import { useDocContext } from '~/src/hooks/useDocContext'; + +import { SidebarLink } from './SidebarLink'; +import { SidebarSubmenu } from './SidebarSubmenu'; + +interface SidebarProps { + handleClick: () => void; +} + +export function Sidebar({ handleClick }: SidebarProps) { + const { links } = useDocContext(); + return ( + + {links.map((link) => { + return link.slug ? ( + + ) : ( + + ); + })} + + ); +} + +const styles = { + root: cssObj({ + display: 'flex', + flexDirection: 'column', + gap: '$1', + }), +}; diff --git a/docs/beta-4/fuel-graphql-docs/src/components/SidebarLink.tsx b/docs/beta-4/fuel-graphql-docs/src/components/SidebarLink.tsx new file mode 100644 index 000000000..ef1f4faf3 --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/src/components/SidebarLink.tsx @@ -0,0 +1,55 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +import { cx, styled } from '@fuel-ui/css'; +import { Box } from '@fuel-ui/react'; +import NextLink from 'next/link'; +import { usePathname } from 'next/navigation'; +import { forwardRef } from 'react'; +import type { SidebarLinkItem } from '~/src/types'; + +const Link = styled(Box, { + py: '$1', + px: '$2', + color: '$gray10', + borderRadius: '$md', + '&:focus, &:hover': { + color: '$gray11', + background: '$whiteA3', + }, + '&.active': { + color: '#00F58C', + background: '#001a0e', + }, + '&:focus': { + outline: 'none', + }, +}); + +export type SidebarLinkProps = { + item: SidebarLinkItem; + handleClick: () => void; +}; + +export const SidebarLink = forwardRef( + ({ item, handleClick }, ref) => { + const pathname = usePathname() || ''; + const fullSlug = `/docs/${item.slug}`; + const isActive = cx({ + active: + (pathname === '/' && fullSlug === '/docs/install') || + pathname.includes(fullSlug), + }); + return ( + + {item.label} + + ); + } +); diff --git a/docs/beta-4/fuel-graphql-docs/src/components/SidebarSubmenu.tsx b/docs/beta-4/fuel-graphql-docs/src/components/SidebarSubmenu.tsx new file mode 100644 index 000000000..8d50b1c47 --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/src/components/SidebarSubmenu.tsx @@ -0,0 +1,98 @@ +import { cssObj, cx } from '@fuel-ui/css'; +import { Button, Box, Icon, List } from '@fuel-ui/react'; +import { usePathname } from 'next/navigation'; +import { useState } from 'react'; +import type { SidebarLinkItem } from '~/src/types'; + +import { SidebarLink } from './SidebarLink'; + +interface SidebarSubmenuProps extends SidebarLinkItem { + handleClick: () => void; +} + +export function SidebarSubmenu({ + label, + submenu, + subpath, + handleClick, +}: SidebarSubmenuProps) { + const pathname = usePathname(); + const isActive = pathname?.startsWith(`/docs/${subpath}`); + const [isOpened, setIsOpened] = useState(Boolean(isActive)); + + function toggle() { + setIsOpened((s) => !s); + } + + return ( + +
+ +
+ {isOpened && ( + + {submenu?.map((item) => { + if (item.label.replace(/\s+/g, '-').toLowerCase() != subpath) { + return ( + + + + ); + } + })} + + )} +
+ ); +} + +const styles = { + root: cssObj({ + flexDirection: 'column', + + '.fuel_button': { + padding: '$0', + justifyContent: 'space-between', + color: '$gray10', + fontWeight: '$normal', + }, + '.fuel_button:focus': { + outline: 'none', + color: '$gray12', + }, + '.fuel_button.active': { + color: '$gray12', + }, + '.fuel_button:hover': { + color: '$gray11', + textDecoration: 'none', + }, + + '.fuel_list': { + display: 'flex', + flexDirection: 'column', + gap: '$1', + mt: '$2', + }, + '.fuel_list-item': { + gap: '$2', + }, + '.fuel_list-item a': { + flex: 1, + }, + }), +}; diff --git a/docs/beta-4/fuel-graphql-docs/src/components/StyleProvider.tsx b/docs/beta-4/fuel-graphql-docs/src/components/StyleProvider.tsx new file mode 100644 index 000000000..9d85ad577 --- /dev/null +++ b/docs/beta-4/fuel-graphql-docs/src/components/StyleProvider.tsx @@ -0,0 +1,13 @@ +'use client'; + +import { getCssText } from '@fuel-ui/css'; +import { useServerInsertedHTML } from 'next/navigation'; + +export function StyleProvider() { + useServerInsertedHTML(() => ( + <> + - - - - - + + + + + + + + + + + ); } diff --git a/src/pages/api/image/[imageName].ts b/src/pages/api/image/[imageName].ts index 9b1f65f66..73acde953 100644 --- a/src/pages/api/image/[imageName].ts +++ b/src/pages/api/image/[imageName].ts @@ -1,5 +1,6 @@ import fs from 'fs'; import type { NextApiRequest, NextApiResponse } from 'next'; +import type { VersionSet } from '~/src/types'; export default function handler(req: NextApiRequest, res: NextApiResponse) { try { @@ -13,9 +14,14 @@ export default function handler(req: NextApiRequest, res: NextApiResponse) { ? imageName!.replaceAll('&&', '/') : imageName[0]; - const isNightly = req.headers.referer?.includes('/nightly/'); + let versionSet: VersionSet = 'default'; + if (req.headers.referer?.includes('/nightly/')) { + versionSet = 'nightly'; + } else if (req.headers.referer?.includes('/beta-4/')) { + versionSet = 'beta-4'; + } const imagePath = `${rootDir}/docs/${ - isNightly ? 'nightly/' : '' + versionSet === 'default' ? '' : versionSet }fuels-wallet/packages/docs/public/${realName}.png`; if (fs.existsSync(imagePath)) { diff --git a/src/pages/guides.tsx b/src/pages/guides.tsx index 29c2de291..ab45e1c9f 100644 --- a/src/pages/guides.tsx +++ b/src/pages/guides.tsx @@ -4,9 +4,10 @@ import { join } from 'path'; import { useState, useEffect } from 'react'; import { Layout } from '../components/Layout'; -import { DOCS_DIRECTORY } from '../config/constants'; +import { DOCS_DIRECTORY, FUEL_TESTNET_UPPER_CASE } from '../config/constants'; import { useVersion } from '../hooks/useVersion'; import { GuidesPage } from '../screens/GuidesPage'; +import type { VersionSet } from '../types'; export interface GuideInfo { title: string; @@ -17,7 +18,6 @@ export interface GuideInfo { export interface GuidesProps { guides: { [key: string]: GuideInfo }; - // nightlyGuides: { [key: string]: GuideInfo }; } export default function Guides({ guides }: GuidesProps) { @@ -28,11 +28,18 @@ export default function Guides({ guides }: GuidesProps) { setIsMounted(true); }, []); - const isNightly = mounted && version === 'Nightly'; + let versionSet: VersionSet = 'default'; + if (mounted && version !== FUEL_TESTNET_UPPER_CASE) { + if (version === 'Nightly') { + versionSet = 'nightly'; + } else { + versionSet = 'beta-4'; + } + } return ( - - + + ); } diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 22978da68..3a3521d7d 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -28,15 +28,22 @@ export const getStaticProps: GetStaticProps = async () => { DOCS_DIRECTORY, `../src/generated/sidebar-links/all-nightly-orders.json` ); + const allBeta4NavsPath = join( + DOCS_DIRECTORY, + `../src/generated/sidebar-links/all-beta-4-orders.json` + ); const allNavs = JSON.parse(readFileSync(allNavsPath, 'utf8')); const allnightlyNavs = JSON.parse(readFileSync(allnightlyNavsPath, 'utf8')); - const versions = getVersions(false); - const nightlyVersions = getVersions(true); + const allBeta4Navs = JSON.parse(readFileSync(allBeta4NavsPath, 'utf8')); + const versions = getVersions('default'); + const nightlyVersions = getVersions('nightly'); + const beta4Versions = getVersions('beta-4'); return { props: { allNavs, allnightlyNavs, + allBeta4Navs, code, md: doc.md, doc: doc.item, @@ -44,6 +51,7 @@ export const getStaticProps: GetStaticProps = async () => { docLink: doc.navLinks, versions, nightlyVersions, + beta4Versions, }, }; }; diff --git a/src/screens/DocPage.tsx b/src/screens/DocPage.tsx index 5aca7709c..aaa1ff52e 100644 --- a/src/screens/DocPage.tsx +++ b/src/screens/DocPage.tsx @@ -9,22 +9,43 @@ import { MDXRender } from '../components/MDXRender'; import { useVersion } from '../hooks/useVersion'; import { getComponents } from '../lib/imports'; import type { DocPageProps } from '../pages/[...slug]'; +import type { VersionSet } from '../types'; export function DocScreen(props: DocPageProps) { - const { doc, allNavs, allnightlyNavs } = props; - const [isNightly, setIsNightly] = useState(false); + const { doc, allNavs, allnightlyNavs, allBeta4Navs } = props; + const [versionSet, setVersionSet] = useState('default'); const version = useVersion(); useEffect(() => { - setIsNightly(version === 'Nightly' || doc.isNightly); + if (version === 'Nightly' || doc.versionSet === 'nightly') { + setVersionSet('nightly'); + } else if (version === 'Beta-4' || doc.versionSet === 'beta-4') { + setVersionSet('beta-4'); + } else { + setVersionSet('default'); + } }, [version, doc]); - const components = getComponents(doc.slug, doc.isNightly); - const navs = doc.originalSlug.includes('guides') - ? undefined - : isNightly - ? allnightlyNavs - : allNavs; + const components = getComponents(doc.slug, doc.versionSet); + let navs = undefined; + if (!doc.originalSlug.includes('guides')) { + if (versionSet === 'nightly') { + navs = allnightlyNavs; + } else if (versionSet === 'beta-4') { + navs = allBeta4Navs; + } else { + navs = allNavs; + } + } + + let versions = props.versions; + if (versionSet !== 'default') { + if (versionSet === 'nightly') { + versions = props.nightlyVersions; + } else { + versions = props.beta4Versions; + } + } return ( @@ -32,8 +53,8 @@ export function DocScreen(props: DocPageProps) { title={doc?.title} isClean={false} config={doc.docsConfig} - isNightly={isNightly} - versions={isNightly ? props.nightlyVersions : props.versions} + versionSet={versionSet} + versions={versions} allNavs={navs} > @@ -43,8 +64,10 @@ export function DocScreen(props: DocPageProps) { )} diff --git a/src/screens/GuidesPage.tsx b/src/screens/GuidesPage.tsx index fab47cc1a..b9ba1d431 100644 --- a/src/screens/GuidesPage.tsx +++ b/src/screens/GuidesPage.tsx @@ -6,13 +6,14 @@ import { TAG_CATEGORIES } from '~/docs/guides/docs/categories'; import { Card } from '../components/Card'; import { Heading } from '../components/Heading'; import type { GuideInfo } from '../pages/guides'; +import type { VersionSet } from '../types'; interface GuidesPageProps { guides: { [key: string]: GuideInfo }; - isNightly: boolean; + versionSet: VersionSet; } -export function GuidesPage({ guides }: GuidesPageProps) { +export function GuidesPage({ guides, versionSet }: GuidesPageProps) { const [active, setActive] = useState('all'); return ( @@ -57,6 +58,7 @@ export function GuidesPage({ guides }: GuidesPageProps) { key={guideName} guideInfo={guideInfo} cardName={guideName} + versionSet={versionSet} /> ); } diff --git a/src/types.ts b/src/types.ts index 7cff194e5..df091e4b8 100644 --- a/src/types.ts +++ b/src/types.ts @@ -16,6 +16,8 @@ export type Config = { }; }; +export type VersionSet = 'default' | 'nightly' | 'beta-4'; + export type DocType = { _raw: RawDocumentData; title: string; @@ -27,7 +29,7 @@ export type DocType = { menu: string[]; docsConfig: Config; parent?: { label: string; link: string }; - isNightly: boolean; + versionSet: VersionSet; }; export type BreadCrumb = { @@ -84,7 +86,6 @@ export type Versions = { Forc: VersionItem; Sway: VersionItem; Fuelup: VersionItem; - Indexer: VersionItem; 'Fuel Rust SDK': VersionItem; 'Fuel TS SDK': VersionItem; 'Fuel Wallet': VersionItem; diff --git a/tests/utils/button.ts b/tests/utils/button.ts index 9535f48b1..5fe12ecc4 100644 --- a/tests/utils/button.ts +++ b/tests/utils/button.ts @@ -9,6 +9,14 @@ export function getButtonByText(page: Page, selector: string | RegExp) { return page.locator('button').getByText(selector); } +export async function clickByLocator(page: Page, locator: string) { + await page.locator(locator).click(); +} + +export async function clickByLabel(page: Page, label: string) { + await page.getByLabel(label, { exact: true }).click(); +} + export async function clickCopyButton(page: Page, id: string) { let clipboardText = { text: '', output: '' }; const selector = `#${id} + div > div > div > button[aria-label="Copy to Clipboard"]`; diff --git a/tests/utils/checks.ts b/tests/utils/checks.ts index 53dc4d305..411a5eed4 100644 --- a/tests/utils/checks.ts +++ b/tests/utils/checks.ts @@ -19,10 +19,18 @@ export function checkIfIsIncremented(initialIndex: number, finalIndex: number) { expect(isIncremented).toBeTruthy(); } +export function checkValue(index: number, value: string) { + console.log('INDEX:', index); + console.log('EXPECTED VALUE:', value); + const savedValue = saved[index]; + console.log('ACTUAL VALUE:', savedValue); + expect(savedValue).toEqual(value); +} + export async function getByLocator( page: Page, locator: string, - removeFromValue: string + removeFromValue: string | null | undefined ) { const locatorVals = await page.locator(locator).allInnerTexts(); let locatorVal = locatorVals[0]; diff --git a/tests/utils/fixtures/index.ts b/tests/utils/fixtures/index.ts index f8d1a065d..f2038b266 100644 --- a/tests/utils/fixtures/index.ts +++ b/tests/utils/fixtures/index.ts @@ -1,9 +1,9 @@ /* eslint-disable no-empty-pattern */ // Use a test fixture to set the context so tests have access to the wallet extension. +import { downloadFuel } from '@fuel-wallet/playwright-utils'; import type { BrowserContext } from '@playwright/test'; import { chromium, test as base } from '@playwright/test'; -import { downloadFuel } from './utils/downloadFuel'; import { getExtensionsData } from './utils/getExtensionsData'; import { waitForExtensions } from './utils/waitForExtenssions'; @@ -13,7 +13,7 @@ export const test = base.extend<{ }>({ context: async ({}, use) => { // download fuel wallet - const fuelPathExtension = await downloadFuel('0.13.0'); + const fuelPathExtension = await downloadFuel('0.15.1'); // prepare browser args const browserArgs = [ `--disable-extensions-except=${fuelPathExtension}`, diff --git a/tests/utils/fixtures/utils/downloadFuel.ts b/tests/utils/fixtures/utils/downloadFuel.ts deleted file mode 100644 index 8c78881bc..000000000 --- a/tests/utils/fixtures/utils/downloadFuel.ts +++ /dev/null @@ -1,59 +0,0 @@ -import admZip from 'adm-zip'; -import { createWriteStream } from 'fs'; -import https from 'https'; -import { tmpdir } from 'os'; -import path from 'path'; - -export async function downloadFuel(version: string) { - const tempDirPath = tmpdir(); - const extensionUrl = `https://github.com/FuelLabs/fuels-wallet/releases/download/v${version}/fuel-wallet-chrome-${version}.zip`; - const zipFile = path.join(tempDirPath, './fuel-wallet.zip'); - const zipFileStream = createWriteStream(zipFile); - - function downloadFile(url, attempt = 1) { - return new Promise((resolve, reject) => { - https - .get(url, (res) => { - if (res.statusCode === 302 || res.statusCode === 301) { - if (attempt > 5) { - // prevent infinite loops if there's a redirect loop - reject(new Error('Too many redirects')); - return; - } - - const newUrl = res.headers.location; - console.log(`Redirecting to: ${newUrl}`); - downloadFile(newUrl, attempt + 1).then(resolve, reject); - return; - } - - if (res.statusCode !== 200) { - reject(new Error(`Unexpected status code: ${res.statusCode}`)); - return; - } - - res.pipe(zipFileStream); - - zipFileStream.on('finish', () => { - zipFileStream.close(resolve); - }); - - zipFileStream.on('error', (error) => { - reject(error); - }); - }) - .on('error', (error) => { - reject(error); - }); - }); - } - - await downloadFile(extensionUrl); - console.log('Download Completed extracting zip...'); - const zip = new admZip(zipFile); - const extPath = path.join(tempDirPath, './dist-crx'); - zip.extractAllTo(extPath, true); - console.log('zip extracted'); - - return extPath; -} diff --git a/tests/utils/runTest.ts b/tests/utils/runTest.ts index 403e9fbde..bef63d891 100644 --- a/tests/utils/runTest.ts +++ b/tests/utils/runTest.ts @@ -1,6 +1,7 @@ import type { BrowserContext, Page } from '@playwright/test'; -import { checkIfIsIncremented, getByLocator } from './checks'; +import { clickByLocator, clickByLabel } from './button'; +import { checkIfIsIncremented, checkValue, getByLocator } from './checks'; import { compareFiles, compareToFile, writeToFile, modifyFile } from './files'; import { getTestActions } from './getTestActions'; import { runCommand } from './runCommand'; @@ -84,6 +85,12 @@ export async function runTest( case 'clickByTestId': await page.getByTestId(step['data-testid']).click(); break; + case 'clickByLocator': + await clickByLocator(page, step['data-click-by-locator']); + break; + case 'clickByLabel': + await clickByLabel(page, step['data-click-by-label']); + break; case 'writeBySelector': await page.fill(step['data-selector'], 'hello world'); break; @@ -99,6 +106,9 @@ export async function runTest( parseInt(step['data-final-index']) ); break; + case 'checkValue': + checkValue(parseInt(step['data-index']), step['data-check-value']); + break; default: console.log('STEP NOT FOUND:', step); } diff --git a/tests/utils/types.ts b/tests/utils/types.ts index 7015f978b..599aed7b4 100644 --- a/tests/utils/types.ts +++ b/tests/utils/types.ts @@ -10,10 +10,13 @@ export type Action = | GetByLocatorAndSave | ClickByRole | ClickByTestId + | ClickByLocator + | ClickByLabel | WriteBySelector | WalletApprove | WalletApproveConnect - | CheckIfIsIncremented; + | CheckIfIsIncremented + | CheckValue; // runs a command export type RunCommand = { @@ -86,7 +89,7 @@ export type GetByLocatorAndSave = { }; // click an element by the role/name -// refer to https://playwright.dev/ +// refer to https://playwright.dev/docs/locators#locate-by-role export type ClickByRole = { name: 'clickByRole'; role: string; @@ -98,6 +101,16 @@ export type ClickByTestId = { testId: string; }; +export type ClickByLocator = { + name: 'clickByLocator'; + locator: string; +}; + +export type ClickByLabel = { + name: 'clickByLabel'; + label: string; +}; + export type WriteBySelector = { name: 'writeBySelector'; selector: string; @@ -118,3 +131,9 @@ export type CheckIfIsIncremented = { initialIndex: number; finalIndex: number; }; + +export type CheckValue = { + name: 'checkValue'; + index: number; + value: string; +}; diff --git a/tests/utils/wallet.ts b/tests/utils/wallet.ts index 56945ac92..813fe1964 100644 --- a/tests/utils/wallet.ts +++ b/tests/utils/wallet.ts @@ -51,7 +51,7 @@ export async function walletSetup( await signupPage .locator('h2') .getByText('Wallet created successfully') - .waitFor({ state: 'visible', timeout: 9000 }); + .waitFor({ state: 'visible', timeout: 20000 }); await signupPage.close(); }