Giter Club home page Giter Club logo

fuels-rs's Introduction

fuels-rs

build crates.io docs discord

Rust SDK for Fuel. It can be used for a variety of things, including but not limited to:

  • Compiling, deploying, and testing Sway contracts;
  • Launching a local Fuel network;
  • Crafting and signing transactions with hand-crafted scripts or contract calls;
  • Generating type-safe Rust bindings of contract methods;
  • And more, fuels-rs is still in active development.

Documentation

See the fuels-rs book

Features

  • Launch Fuel nodes
  • Deploy contracts
  • Interact with deployed contracts
  • Type-safe Sway contracts bindings code generation
  • Run Sway scripts
  • CLI for common operations
  • Local test wallets
  • Wallet integration
  • Events querying/monitoring

FAQ

What dependencies do I need?

How can I run the SDK tests?

First, build the test projects using forc:

forc build --release --path packages/fuels

Then you can run the SDK tests with:

cargo test

You can also run specific tests. The following example will run all integration tests in types.rs whose names contain in_vector and show their outputs:

cargo test --test types in_vector -- --show-output

How to run WASM tests?

You need to have wasm32 as a target, if you don't already:

 rustup target add wasm32-unknown-unknown

You also need wasm-pack, if you don't already:

cargo install wasm-pack

Navigate to packages/wasm-tests and run wasm-pack test.

What to do if my tests are failing on master

Before doing anything else, try all these commands:

cargo clean
rm Cargo.lock
forc build --release --path packages/fuels
cargo test

Why is the prefix fuels and not fuel?

In order to make the SDK for Fuel feel familiar with those coming from the ethers.js ecosystem, this project opted for an s at the end. The fuels-* family of SDKs is inspired by The Ethers Project.

How can I run the docs locally?

Install mdbook by running:

cargo install mdbook

Next, navigate to the docs folder and run the command below to start a local server and open a new tab in you browser.

mdbook serve --open

You can build the book by running:

mdbook build

fuels-rs's People

Contributors

adlerjohn avatar anton-trunov avatar br1ght0ne avatar cold-briu avatar digorithm avatar hal3e avatar hattizai avatar igi-111 avatar iqdecay avatar joshuabatty avatar k1-r1 avatar kayagokalp avatar matt-user avatar miles-six avatar mitchmindtree avatar mohammadfawaz avatar mpoplavkov avatar mujkica avatar paplo75 avatar ra0x3 avatar rakita avatar salka1988 avatar sarahschwartz avatar segfault-magnet avatar sellskin avatar tedbyron avatar thdaraujo avatar tjsharp1 avatar voxelot avatar xgreenx avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fuels-rs's Issues

Integrate the SDK with `forc test`

Once #11 is merged, anyone will be able to write Rust code to test their Sway contracts deployed on Fuel nodes.

However, there's one last ergonomic aspect missing, which is being able to do all that using forc, so we can have better vertical integration.

A new forc command should be created: forc test, and it will look for Rust files within a Sway project, these Rust files should have tests written in Rust, using fuels-rs' SDK.

ABIgen should conform to `rustfmt`

Currently, the ABIgen-generated Rust-code doesn't conform to rustfmt. It's not a pressing issue for now but this should be solved in the long-run (eg. for tests generation it could be problematic).

Refactor `no-std` feature to not break build

Having a “no-std” feature isn't really the idiomatic way. Typically you make it so that disabling default features is all you need to do to be no-std friendly.
@Voxelot

Currently, #51 fails because turning on features breaks the build. Features should be refactored so that turning off features makes the crate no-std friendly.

abigen! macro fails to read .json file on Windows

I found a bug where the abigen! macro works for me when compiling on my mac, but fails when building on windows.

The error i'm getting is:

message: called `Result::unwrap()` on an `Err` value: unable to canonicalize file from working dir C:\Users\conta\Desktop\counter_project with path /C:/Users/conta/Desktop/counter_project/my_contract_abi.json

I'll take a look into this.

Make necessary refactoring to enable `no_std` support

Due to many issues with the current way we were enabling no_std support on fuels-rs, we had to revert and remove no_std support for now. Previous versions will still work normally.

However, we still want to enable no_std to some parts of fuels-rs that are needed as no_std, such as the Fuel's indexer. This will require some major refactoring/reorganization in order to make it more no_std friendly.

Some parts that need to be included as no_std:

  1. The code that gets emitted from wasm_abigen;
  2. ABIDecoder;
  3. Token, Tokenizable, ParamType, and related dependencies.

Connect contract instance to existing contract

Currently, we're only able to create a contract instance by compiling and deploying it:

let contract_instance = MyContract::new(compiled, client);

We should be able to create a contract instance from an already deployed contract by referencing to its deployed address, similar to ethers.js / ethers-rs. Something similar to this:

 let contract_instance = MyContract::connect("0x...");

Support contract methods with only 3 params (no user input param)

Right now we're strictly looking for a 4th param:

if n_inputs != 4 {
    return Err(Error::MissingData(format!(
        "Expected exactly 4 inputs, found {}",
        n_inputs
    )));
}

But there are cases like this one:

fn get_counter(gas_: u64, amount_: u64, color_: b256, input: ()) -> u64 {
  get(COUNTER_KEY)
}

Where the user doesn't send the 4th input.

This causes:

help: message: called `Result::unwrap()` on an `Err` value: MissingData("cannot parse custom type with no components")

Because since () isn't a primitive type, it's trying to create a custom type without components.

We should allow the 4th param to be () and not try expanding it when going through the abigen!.

Failing CI on `master`

After merging PR #49, CI isn't passing anymore.
Even though the PR CI was passing before merging.
Error in CI is:

failures:
---- call_with_structs stdout ----
thread 'call_with_structs' panicked at 'called `Result::unwrap()` on an `Err` value: CompilationError("Failed to compile core")', fuels-abigen-macro/tests/harness.rs:1028:14
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Create initial abstraction for signers

The SDK should have an entrypoint abstraction for signers, in order to enable transaction signing. To begin with, we could keep things simple and generate it all from within the SDK, and eventually add support for Ledger, MetaMask, and so on.

Enable passing in multiple contract IDs with a call

Currently calling a contract only sets add an input-output pair for that one contract ID. There are many cases where a transaction will want to call a contract that then calls another contract, and so on.

Support crafting a script transaction with multiple contract IDs as input-output pairs.

Add `from_token` feature to allow decoding to rust type.

For the WASM indexers, it will be useful to convert from an ABI-encoded byte blob back into the rust type defined in the contract.
Currently, we can go from a struct into ABI encoded bytes like this: my_struct.into_token(), the WASM indexers will also need to be able to do something like let struct = MyStruct::from_token(decoded_tokens).

Write tests at the component-level of the `abigen!`

Right now we have an end-to-end test suite for the abigen! under fuels-abigen/tests/harness.rs.

But it would be nice to have more granular tests at the level of each main component of the abigen!, for instance at the level of custom_types_gen.rs, where we generate custom types coming from the ABI. Or functions_gen.rs, where we generate the functions coming from the ABI.

abigen: exclude first 3 fields instead of name matching

if param.name == "gas_" || param.name == "amount_" || param.name == "color_" {

Currently, only fields with specific names are ignored. This isn't really documented anywhere and is the source of endless confusion. Moreover, currently the compiler requires exactly 4 fields from ABI methods: 3 implicit and one for user parameters. Therefore, there's no reason to prune on matching names when the first 3 can simply be pruned.

Investigate weird Sway compilation error in a test case

The following test https://github.com/FuelLabs/fuels-rs/blob/master/fuels-rs/tests/calls.rs#L17 is failing because forc can't build this very simple Sway script (https://github.com/FuelLabs/fuels-rs/blob/master/fuels-abigen-macro/tests/test_projects/simple_script/src/main.sw).

However, this is only happening in this CI server, and locally it can build just fine:

$ forc build
  Compiled library "core".
  Compiled library "core".
  Compiled library "lib-std" with 2 warnings.
  Compiled script "Fuel example project".
  Bytecode size is 396 bytes.

This is the reason why we're currently skipping this test with an #[ignore]. but the test itself is fine. This needs further investigation. It feels like it's something related to Github Actions. Could be related to its caching mechanism. It's unlikely (but not impossible!) to be related to fuels-rs itself or forc.

This is a relatively low priority issue, however. The test we're skipping isn't very critical and is tested indirectly through the main harness.rs test suite. Still, it's a curious behavior that needs some investigation.

Remove `launch_and_deploy` function, refactor launching node

The launch_and_deploy() function is generally messy and confusing because it conflates two things: launching a node and deploying a contract.

/// Launches a local `fuel-core` network and deploys a contract to it.
/// If you want to deploy a contract against another network of
/// your choosing, use the `deploy` function instead.
pub async fn launch_and_deploy(
compiled_contract: &CompiledContract,
) -> Result<(FuelClient, ContractId), Error> {
let srv = FuelService::new_node(Config::local_node()).await.unwrap();
let fuel_client = FuelClient::from(srv.bound_address);
let contract_id = Self::deploy(compiled_contract, &fuel_client).await?;
Ok((fuel_client, contract_id))
}

It also makes writing tests more brittle and non-uniform, e.g. if you deploy two contracts for a single test, the second contract has to use deploy. Then if you rearrange things to deploy the second contract first, all of a sudden your test will break.

Action

  • Remove launch_and_deploy().
  • Add a new function launch() that launches a new node with the provided configuration (e.g. port, and genesis state), so long as there's not a node already running at that port. When done, the node should be shut down.
  • Maybe add a new function connect() that connects to an already-running node. When done, the node should not be shut down. Can be left to a future issue.

Better handle generated custom types that are equivalent between Sway and `fuel_types`

Motivation

In cases where a Sway contract is using the stdlib's native structs such as:

use std::{address::Address, contract_id::ContractId};

pub struct ParamsGetBalance {
    target: b256,
    asset_id: ContractId,
}

the SDK's abigen! will generate these as custom structs:

{
    "components": [
        {
            "components": null,
            "name": "value",
            "type": "b256"
        }
    ],
    "name": "asset_id",
    "type": "struct ContractId"
}
 pub struct ContractId {
    pub value: [u8; 32],
}

And, then, when using it in the SDK:

#[tokio::test]
async fn mint() {
    let salt = get_new_salt();

    abigen!(TestFuelCoinContract, "test_projects/token_ops/src/abi.json",);

    let compiled = Contract::compile_sway_contract("test_projects/token_ops", salt).unwrap();

    let (client, fuelcoin_id) = Contract::launch_and_deploy(&compiled).await.unwrap();

    let fuel_coin_instance = TestFuelCoinContract::new(compiled, client);

    let c = testfuelcoincontract_mod::ContractId {
        value: fuelcoin_id.into(),
    };

    let default_balance_params = ParamsGetBalance {
        target: fuelcoin_id.into(),
        asset_id: c,
    };

    let balance_result = fuel_coin_instance.get_balance(default_balance_params);

    let result = fuel_coin_instance.mint_coins(11).call().await.unwrap();
}

Note that you have to reference the generated ContractId through its namespace: testfuelcoincontract_mod::ContractId. But, underneath, it's equivalent to fuel_types::ContractId: they're [u8; 32];

This works fine, but it would be more ergonomic if we treated Sway's ContractId (and Address) as fuel_types::ContractId. So that we could eliminate this conversion step:

 let c = testfuelcoincontract_mod::ContractId {
    value: fuelcoin_id.into(),
};

And simply use fuelcoin_id: fuel_types::ContractId to a contract method that takes the Sway's ContractId.

Potential solution

The abigen! process would have to detect that the Sway type being generated is named as ContractId (and others such as Address) and allow for fuel_types::ContractId to be used instead. This require significant changes to the abigen! macro.

For instance, this is the generated code when there's a ContractId in the custom types:

 pub struct ContractId {
    pub value: [u8; 32],
}
impl ContractId {
    pub fn param_types() -> Vec<ParamType> {
        let mut types = Vec::new();
        types.push(ParamType::B256);
        types
    }
    
    pub fn into_token(self) -> Token {
        let mut tokens = Vec::new();
        tokens.push(Token::B256(self.value));
        Token::Struct(tokens)
    }
    
    pub fn new_from_tokens(tokens: &[Token]) -> Self {
        Self { value : < [u8 ; 32] > :: from_token (tokens [0usize] . clone ()) . expect ("Failed to run `new_from_tokens()` for custom struct, make sure to pass tokens in the right order and right types") , }
    }    
}

impl fuels_core::Detokenize for ContractId {
    fn from_tokens(
        mut tokens: Vec<Token>,
    ) -> Result<Self, fuels_core::InvalidOutputType> {
        let token = match tokens.len() {
            0 => Token::Struct(::alloc::vec::Vec::new()),
            1 => tokens.remove(0),
            _ => Token::Struct(tokens),
        };
        Ok(ContractId::new_from_tokens(&[token]))
    }
}

There are many correct approaches to change this section to use fuel_types::ContractId instead. Part of the resolution of this issue is deciding which approach to use.

Make ABI compatible with a WASM target.

Currently, abigen and abidecode import dependencies that require std. In order to compile to WASM, we'll need a feature flag that allows building in a no_std environment.

Model `abigen!`s `Source::Path` behaviour after `include_str!`

Follow-up to #94.

Currently the path passed to the right hand side argument of abigen! is expected to be relative to the std::env::current_dir:

let root = env::current_dir()?.canonicalize()?;

This evaluates to whatever happens to be the current directory at the time of macro expansion. This means that the necessary path given to abigen! can change when the project is moved to a different subdirectory of the same workspace, or if its moved from a workspace into its own project, or vice versa. Ideally, we want our src not to be dependent on the directory that the project happens to be executed within.

To fix this, we could model our behaviour after the std include_str! macro. include_str! accepts a path that is relative to the file in which it is invoked. For example if we have:

project/my-contract-abi.json
project/tests/harness.rs

the abigen! macro could then be invoked within the project/tests/harness.rs with

abigen!(MyContract, "../my-contract-abi.json");

`expand_fn_outputs` has inconsistent behavior

  • Having a &[Property{type_field: "enum xxx"}] requires providing valid components but not with type_field: "struct xx"
  • With 1 output, structs and enum are not expanded, but are expanded with ≥2 arguments

Unwrap on `get_receipt_value()` error

Repro: https://github.com/ControlCplusControlV/Sway-Example-Repo/tree/3beeb4c5e0415e1109a730f50ad40dcd22487154

$ forc test
   Compiling core_test v0.1.0 (/home/devel/local/ControlCplusControlV/Sway-Example-Repo)
warning: unused variable: `contract_id`
  --> tests/harness.rs:21:18
   |
21 |     let (client, contract_id) = Contract::launch_and_deploy(&compiled).await.unwrap();
   |                  ^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_contract_id`
   |
   = note: `#[warn(unused_variables)]` on by default

warning: unused variable: `result`
  --> tests/harness.rs:29:9
   |
29 |     let result = contract_instance.sqrtu32(100).call().await;
   |         ^^^^^^ help: if this is intentional, prefix it with an underscore: `_result`

warning: `core_test` (test "integration_tests") generated 2 warnings
    Finished test [unoptimized + debuginfo] target(s) in 10.04s
     Running tests/harness.rs (target/debug/deps/integration_tests-07366f577abc0bae)

running 1 test
  Compiled library "core".
  Compiled library "core".
  Compiled library "lib-std" with 2 warnings.
  Compiled script "core_test" with 3 warnings.
  Bytecode size is 12724 bytes.
thread 'harness' panicked at 'called `Option::unwrap()` on a `None` value', /usr/local/cargo/registry/src/github.com-1ecc6299db9ec823/fuels-rs-0.1.2/src/contract.rs:329:65
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
test harness ... FAILED

failures:

failures:
    harness

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 84.04s

error: test failed, to rerun pass '--test integration_tests'

Looks like this line is trying to unwrap() even though the result being unwrapped is not guaranteed to be ok.

https://github.com/FuelLabs/fuels-rs/blob/v0.1.2/fuels-rs/src/contract.rs#L329

Support custom types as ABI-defined function output

Currently we support custom types as inputs to ABI-defined functions, meaning the SDK's abigen! will generate Rust structs whose functions can take custom types that are also generated by the abigen!. This covers most of the cases, but there are cases where the output of an ABI-defined function is also a custom struct, i.e:

let custom_input = MyStruct::new();
let my_custom_output: CustomOutput = MyCustomContract.do_something(custom_input);

In this case, the SDK already supports the generation and manipulation of MyStruct as an input, but not the creation of CustomOutput struct, that's only defined as the output of a function.

This is a relatively straightforward task, as we have to do something similar to what we already do for the custom types for the input (see expand_function_arguments() in functions_gen.rs ) for the output as well, in functions_gen.rs:

/// Expands the output of a function, i.e. what comes after `->` in a function
/// signature.
fn expand_fn_outputs(outputs: &[Property]) -> Result<TokenStream, Error> {
    // TODO: future, support struct outputs
    match outputs.len() {
        0 => Ok(quote! { () }),
        1 => expand_type(&parse_param(&outputs[0])?),
        _ => {
            let types = outputs
                .iter()
                .map(|param| expand_type(&parse_param(param)?))
                .collect::<Result<Vec<_>, Error>>()?;
            Ok(quote! { (#( #types ),*) })
        }
    }
}

☝️ This is where we need to extend to support outputs with custom types.

Make contract calls with structs as inputs work

As of now, contract calls with structs as inputs don't work because of the way we're crafting the script_data and script being passed to the transaction.

We need to develop a way to read custom types in contract calls.

Improve the data returned by contract calls

As of now, we return the parsed return value equivalent to the contract call's return type, e.g. if my_method() returns a bool, the call to this method using the SDK will return only the bool. It might be useful to return more context about the call, such as the other receipts, containing all the rest of the context of the call.

In more detail, this is fairly simple. In fuels-rs/src/contract.rs we have:

pub async fn call(self) -> Result<D, Error> {
    let receipts = Contract::call(
        self.contract_id,
        Some(self.encoded_selector),
        Some(self.encoded_args),
        &self.fuel_client,
        self.utxo_id,
        self.balance_root,
        self.state_root,
        self.input_index,
        self.gas_price,
        self.gas_limit,
        self.maturity,
        self.custom_inputs,
    )
    .await
    .unwrap();

    let returned_value = Self::get_receipt_value(&receipts).unwrap().to_be_bytes();

    let mut decoder = ABIDecoder::new();

    let decoded = decoder.decode(&self.output_params, &returned_value)?;

    Ok(D::from_tokens(decoded)?)
}

We need to find an ergonomic way to return, along with the D::from_tokens(decoded) (the decoded Tokens), the other receipts that are already in there.

Different methods taking different structs as input with same argument name generates only one struct

For a given contract:

contract;

pub struct StructOne {
    foo: u64,
}

pub struct StructTwo {
    bar: u64,
}

abi MyTest {
    fn something(gas_: u64, amount_: u64, color_: b256, input: StructTwo) -> u64;
    fn something_else(gas_: u64, amount_: u64, color_: b256, input: StructOne) -> u64;
}

impl MyTest for Contract {
    fn something(gas_: u64, amount_: u64, color_: b256, input: StructOne) -> u64 {
        let v = input.foo; 
        v + 1
    }    

    fn something_else(gas_: u64, amount_: u64, color_: b256, input: StructTwo) -> u64 {
        let v = input.bar; 
        v - 1
    }    
}

something takes input as StructOne. something_else takes input as StructTwo. Because both args are named input, the abigen! macro only generates StructOne, and not StructTwo.

This is easily worked around by renaming one of the input args to something else other than "input". Nonetheless, this is a wrong behavior.

Use `fuel-crypto` instead of `fuel-vm` for signatures

Currently fuels-rs signers and wallet abstractions require cryptography-related functions from fuel-vm, e.g. in fuels-core lib.rs:

use fuel_vm::crypto::secp256k1_sign_compact_recover;

Recently we've created fuel-crypto (https://github.com/FuelLabs/fuel-crypto/) that will host all cryptography-related code that will be used downstream and eventually fuel-vm won't host this type of code anymore.

fuels-rs needs to be modified to use the signing/recovery functions in fuel-crypto instead of fuel-vm.

Response errors; unexpected block execution error OutputAlreadyExists When Running Multiple Tests

So was finally getting around to debugging my Sushi Sway Repo my withdraw test was failing with the following error

thread 'withdraw' panicked at 'called `Result::unwrap()` on an `Err` value: Custom { kind: Other, error: "Response errors; unexpected block execution error OutputAlreadyExists" }', /hom/me/.cargo/registry/src/github.com-1ecc6299db9ec823/fuels-rs-0.2.1/src/script.rs:28:56
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
test withdraw ... FAILED

failures:

failures:
    withdraw

It seems there seems to be some concurrency failure when running multiple tests at once. If this an error in my code though let me know and I can close the issue

Abigen support for tuple return values

abigen! panics with :

error: proc macro panicked ... = help: message: called Result::unwrap() on an Err value: MissingData("cannot parse custom type with no components")

when parsing an ABI containing functions which return tuples, e.g.

fn my_tuple_function(gas_: u64, amount_: u64, asset_id_: b256, params: () ) -> (u64, u64);

Add `Vec` type

I've found myself wanting to use the equivalent of Rust's Vec when writing Sway code. I'd like to see this implemented in the SDK 😄

This probably is dependent on this issue: FuelLabs/sway#428

Add random change to script transaction

Full context and discussion here: #89.

The overall idea is to enable contracts calls that may be view-only to be able to be called multiple times without causing tx id collision.

This will be a temporary workaround for the lack of explicit view-only ABI methods and different ways of calling different types of functions (.call(), .send(), etc, as you see in Solidity).

Later, we should explore other potential solutions.

Investigate weird `MemoryOverflow` error

Context: trying to run the exact same very simple contract (that just sets a storage slots to a certain value) gives out different results depending on the storage address used. The invalid result yield a MemoryOverflow error.
Did some more testing:

  • Let (pos, val) represent a storage key where byte in position pos has value val (it follows that pos is in [0,31] and value in [0,255]).
  • Then :
( pos is in [0,4] && val is in [1,255]) || (pos == 5 && val is in [128,255])
<=>
MemoryOverflow

You can find a repro on branch https://github.com/FuelLabs/fuels-rs/tree/repro-storage-slots. Run cargo test storage -- --show-output.

Consider removing support for paths in `abigen!` in favour of Rust's `include_str!`

We might be able to simplify the implementation of abigen! a little and add a little flexibility by only accepting expressions that evaluate to a str in the right-hand side argument.

For example, as an alternative to:

abigen!(MyContract, "./my-contract-abi.json");

which involves some custom path and file handling, we could potentially accept an Expr in the right-hand side argument (instead of LitStr) and offload the path and file-handling work to the Rust include_str macro from std:

abigen!(MyContract, include_str!("./my-contract-abi.json"));

Currently, even though we technically accept full contract ABI JSON strings in the right argument, we are unable to use macros that evaluate to a str like above as the parser for the right hand side argument expects a LitStr (string literal) rather than an Expr (expression). By taking an Expr, I believe users would be free to use both literal strings and macros that expand to a str, e.g. include_str, or an alternative to include_str that accepted absolute paths rather than relative, etc.


Motivation

I ran into this while moving an example out of The Sway Book into a standalone project within the sway repo examples directory as a part of solving FuelLabs/sway#544.

I noticed that currently the path accepted in the right-hand side of abigen! seems to be relative to the root of the current workspace (rather than the project). This makes the invocation of abigen! within the test harnesses of the examples that are nested within the sway repo a little awkward as they must specify the path relative to the sway workspace root, rather than the example's own project root. E.g. in examples/hello_world/tests/harness.rs currently we have to do

abigen!(MyContract, "./examples/hello_world/my-contract-abi.json");

rather than ideally

abigen!(MyContract, "./my-contract-abi.json");

or

abigen!(MyContract, include_str!("../my-contract-abi.json"));

Ideally we'd be able to write one of the latter as we'd like to include these examples into the book verbatim with

{{#include ../../../examples/hello_world/tests/harness.rs}}

Addressing this issue should allow for the latter.

Create `examples/` directory centralizing all SDK examples

Currently, all our examples are scattered across many tests, both in the "central" harness.rs under fuels-abigen-macro and in smaller tests across the repo.

We should have a root-level examples/ directory containing many different examples with the most common use-cases.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.