Skip to content

feat!: add support for assemble tx #1634

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 52 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
5a8cba6
feat: support for assemble tx
hal3e Feb 28, 2025
723eb55
Merge branch 'master' into feat/assemble-tx
hal3e Mar 5, 2025
93eaebe
initial impl
hal3e Mar 9, 2025
648d5ff
merge master
hal3e Mar 14, 2025
658a928
fix merge
hal3e Mar 14, 2025
b3d1c7f
merge master
hal3e Apr 2, 2025
2069cdb
remove dbg
hal3e Apr 2, 2025
d179a2a
cargo fmt
hal3e Apr 2, 2025
b5bdbc6
remove fcore-client dep
hal3e Apr 2, 2025
dba5782
Merge branch 'master' into feat/assemble-tx
hal3e Apr 7, 2025
342dd59
remove variable output and missing contracts estimation
hal3e Apr 7, 2025
b6c4be2
remove anchor, fix docs later
hal3e Apr 7, 2025
8a82538
merge master
hal3e Apr 9, 2025
72b010d
Merge branch 'master' into feat/assemble-tx
hal3e Apr 11, 2025
4c16920
work in progress
hal3e Apr 11, 2025
3a1d523
refactor
hal3e Apr 14, 2025
ca880ac
merge master
hal3e Apr 14, 2025
d971704
refactor
hal3e Apr 14, 2025
c6bd94e
remove test
hal3e Apr 15, 2025
494ac3a
merge master
hal3e Apr 17, 2025
6b0cc1c
fix todo
hal3e Apr 17, 2025
2478f48
remove unused lines
hal3e Apr 21, 2025
f0e32f6
create sdk version of AssembleTXResult struct and expose rest
hal3e Apr 22, 2025
aa289f0
update docs
hal3e Apr 22, 2025
575af13
docs
hal3e Apr 23, 2025
f45e499
Merge branch 'master' into feat/assemble-tx
hal3e Apr 23, 2025
30ab40a
Merge branch 'master' into feat/assemble-tx
hal3e Apr 23, 2025
b2bc3ea
add asseble tx docs
hal3e Apr 23, 2025
43a8079
tests
hal3e Apr 23, 2025
c30fb8a
fix docs
hal3e Apr 23, 2025
81b557e
Merge branch 'master' into feat/assemble-tx
hal3e Apr 23, 2025
8d4af88
docs related suggestions
hal3e Apr 25, 2025
dc841ea
Update packages/fuels-core/src/types/transaction_builders.rs
hal3e Apr 25, 2025
6e2d9e0
Merge branch 'master' into feat/assemble-tx
segfault-magnet May 2, 2025
b85f8e2
Update packages/fuels-accounts/src/provider.rs
hal3e May 6, 2025
0d52722
update docstring
hal3e May 6, 2025
cd6c12b
update max_fee handling
hal3e May 6, 2025
ed99330
fix typo
hal3e May 6, 2025
e2096da
add docstring
hal3e May 6, 2025
c364488
update docs
hal3e May 6, 2025
26d45d4
pr comment
hal3e May 6, 2025
d1a83ec
add coin cache exclude
hal3e May 6, 2025
56f379f
Update packages/fuels-accounts/src/coin_cache.rs
hal3e May 9, 2025
08e8ee8
Update packages/fuels-core/src/types/transaction_builders.rs
hal3e May 9, 2025
d5c0aac
Update packages/fuels-core/src/types/transaction_builders.rs
hal3e May 9, 2025
323da72
Update packages/fuels-core/src/types/transaction_builders.rs
hal3e May 9, 2025
8186383
Update packages/fuels-core/src/types/transaction_builders.rs
hal3e May 9, 2025
95a80d2
coin-cache assemble-tx
hal3e May 12, 2025
5cdc2f4
un-delete cfg flag
hal3e May 12, 2025
cbcfad9
check tx after building
hal3e May 12, 2025
7cccd9b
merge master
hal3e May 13, 2025
18caac7
Merge branch 'master' into feat/assemble-tx
hal3e May 14, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/src/SUMMARY.md
Original file line number Diff line number Diff line change
@@ -49,6 +49,7 @@
- [Pre-uploading code](./preuploading-code.md)
- [Custom transactions](./custom-transactions/index.md)
- [Transaction builders](./custom-transactions/transaction-builders.md)
- [Assemble transactions](./custom-transactions/assemble_tx.md)
- [Custom contract and script calls](./custom-transactions/custom-calls.md)
- [Types](./types/index.md)
- [`Bytes32`](./types/bytes32.md)
8 changes: 3 additions & 5 deletions docs/src/calling-contracts/other-contracts.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
# Calling other contracts

If your contract method is calling other contracts you will have to add the appropriate `Inputs` and `Outputs` to your transaction. For your convenience, the `CallHandler` provides methods that prepare those inputs and outputs for you. You have two methods that you can use: `with_contracts(&[&contract_instance, ...])` and `with_contract_ids(&[&contract_id, ...])`.

`with_contracts(&[&contract_instance, ...])` requires contract instances that were created using the `abigen` macro. When setting the external contracts with this method, logs and require revert errors originating from the external contract can be propagated and decoded by the calling contract.
If your contract method is calling other contracts you will have to add the appropriate `Inputs` and `Outputs` to your transaction. For your convenience, the `CallHandler` will fill in all missing `Inputs`/`Outputs` before sending the transaction.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not super familiar with the bounds of this "fill in all missing Inputs/Outputs". How much of this is communicated back to the sender before they click "send"?


```rust,ignore
{{#include ../../../e2e/tests/contracts.rs:external_contract}}
```

If however, you do not need to decode logs or you do not have a contract instance that was generated using the `abigen` macro you can use `with_contract_ids(&[&contract_id, ...])` and provide the required contract ids.
If you need to decode logs and require revert errors originating from the external contract you will need to pass the `LogDecoder` from the external contract to the contract instance making the call.

```rust,ignore
{{#include ../../../e2e/tests/contracts.rs:external_contract_ids}}
{{#include ../../../e2e/tests/contracts.rs:external_contract_logs}}
```
23 changes: 2 additions & 21 deletions docs/src/calling-contracts/tx-dependency-estimation.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,9 @@
# Transaction dependency estimation

Previously, we mentioned that a contract call might require you to manually specify external contracts, variable outputs, or output messages. The SDK can also attempt to estimate and set these dependencies for you at the cost of running multiple simulated calls in the background.
Previously, we mentioned that a contract call might require you to manually specify external contracts, variable outputs, or output messages. The SDK will estimate and set these dependencies for you.

The following example uses a contract call that calls an external contract and later mints assets to a specified address. Calling it without including the dependencies will result in a revert:

```rust,ignore
{{#include ../../../examples/contracts/src/lib.rs:dependency_estimation_fail}}
```

As mentioned in previous chapters, you can specify the external contract and add an output variable to resolve this:

```rust,ignore
{{#include ../../../examples/contracts/src/lib.rs:dependency_estimation_manual}}
```

But this requires you to know the contract ID of the external contract and the needed number of output variables. Alternatively, by chaining

- `.with_variable_output_policy(VariableOutputPolicy::EstimateMinimum)` and
- `.determine_missing_contracts()`

the dependencies will be estimated by the SDK and set automatically.
The following example uses a contract call that calls an external contract and later mints assets to a specified address.

```rust,ignore
{{#include ../../../examples/contracts/src/lib.rs:dependency_estimation}}
```

> **Note:** Both `with_variable_output_policy` and `determine_missing_contracts` can also be used when working with script calls or multi calls. `determine_missing_contracts()` will not enable logging from an external contract. For more information, see [here](./other-contracts.md).
8 changes: 5 additions & 3 deletions docs/src/calling-contracts/tx-policies.md
Original file line number Diff line number Diff line change
@@ -15,9 +15,6 @@ Where:
3. **Maturity** - Block until which the transaction cannot be included.
4. **Expiration** - Block after which the transaction cannot be included.
5. **Max Fee** - The maximum fee payable by this transaction.
6. **Script Gas Limit** - The maximum amount of gas the transaction may consume for executing its script code.

When the **Script Gas Limit** is not set, the Rust SDK will estimate the consumed gas in the background and set it as the limit.

If the **Witness Limit** is not set, the SDK will set it to the size of all witnesses and signatures defined in the transaction builder.

@@ -40,3 +37,8 @@ This way:
```

As you might have noticed, `TxPolicies` can also be specified when deploying contracts or transferring assets by passing it to the respective methods.

> **Note:** The `Script Gas Limit` is set directly on the call handler:
```rust,ignore
{{#include ../../../examples/contracts/src/lib.rs:tx_script_gas_limit}}
5 changes: 2 additions & 3 deletions docs/src/calling-contracts/variable-outputs.md
Original file line number Diff line number Diff line change
@@ -11,15 +11,14 @@ Let's say you deployed a contract with the following method:
{{#include ../../../e2e/sway/contracts/token_ops/src/main.sw:variable_outputs}}
```

When calling `transfer_coins_to_output` with the SDK, you can specify the number of variable outputs:
When calling `transfer_coins_to_output` with the SDK, the correct number of variable outputs will be estimated and you will not have to change your code.

```rust,ignore
{{#include ../../../examples/contracts/src/lib.rs:variable_outputs}}
```

<!-- This section should explain what the `with_variable_output_policy` method does -->
<!-- with_variable_output_policy:example:start -->
`with_variable_output_policy` sets the policy regarding variable outputs. You can either set the number of variable outputs yourself by providing `VariableOutputPolicy::Exactly(n)` or let the SDK estimate it for you with `VariableOutputPolicy::EstimateMinimum`. A variable output indicates that the amount and the owner may vary based on transaction execution.
However, if you convert the contract call into a `TransactionBuilder` you have to make sure that you have the appropriate number of variable outputs present. You can use the `with_variable_output_policy` method to either set the number of variable outputs yourself by providing `VariableOutputPolicy::Exactly(n)` or let the SDK estimate it for you with `VariableOutputPolicy::EstimateMinimum`. A variable output indicates that the amount and the owner may vary based on transaction execution.
<!-- with_variable_output_policy:example:end -->

> **Note:** that the Sway `lib-std` function `mint_to_address` calls `transfer_to_address` under the hood, so you need to call `with_variable_output_policy` in the Rust SDK tests like you would for `transfer_to_address`.
35 changes: 35 additions & 0 deletions docs/src/custom-transactions/assemble_tx.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Assemble Transactions

Assemble transactions makes it possible to create a minimal `TransactionBuilder` and let the fuel node fill in the missing details. The node will add missing inputs, outputs, set transactions limits etc. Below is an example how the assemble strategy can be used to create a transfer.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Along the lines of previous question, when is the tx signed?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see in the snippet code:

tb.add_signer(wallet.signer().clone())?;

I assume this happens on the client side.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The transaction is signed at the end after receiving the assembled tx. This happens in the TransactionBuilder's build method.


Let's first launch a local node with a funded wallet and create a random wallet that will receive some base asset.

```rust,ignore
{{#include ../../../e2e/tests/providers.rs:assemble_wallets}}
```

Next, we create an base asset output to the receiver wallet.

```rust,ignore
{{#include ../../../e2e/tests/providers.rs:assemble_output}}
```

Now we tell the node what kind of inputs do we require. Note that we do not specify any inputs just the amount, asset id and which require balance should be used to pay for the fees.

```rust,ignore
{{#include ../../../e2e/tests/providers.rs:assemble_req_balance}}
```

We can now build the transaction using the assemble strategy.

```rust,ignore
{{#include ../../../e2e/tests/providers.rs:assemble_tb}}
```

> **Note** The assemble strategy will make sure that we have enough base asset coins in the inputs to cover the transfer and the fee. Also a change output is added to the transaction.
At the end, we send the transaction and make sure that the receiver balance matches the sent amount.

```rust,ignore
{{#include ../../../e2e/tests/providers.rs:assemble_response}}
```
2 changes: 2 additions & 0 deletions docs/src/predicates/index.md
Original file line number Diff line number Diff line change
@@ -54,3 +54,5 @@ Each configurable constant will get a dedicated `with` method in the SDK. For ex
```rust,ignore
{{#include ../../../e2e/tests/predicates.rs:predicate_configurables}}
```

> **Note:** if a custom transaction is using predicates where the execution is dependant on some malleable fields and the fields are changed, then you will have to re-estimate the predicates to set the right gas limit.
10 changes: 1 addition & 9 deletions docs/src/running-scripts.md
Original file line number Diff line number Diff line change
@@ -40,20 +40,12 @@ Script calls provide the same logging functions, `decode_logs()` and `decode_log

## Calling contracts from scripts

Scripts use the same interfaces for setting external contracts as [contract methods](./calling-contracts/other-contracts.md).

Below is an example that uses `with_contracts(&[&contract_instance, ...])`.
Similarly to [contract methods](./calling-contracts/other-contracts.md), script calls will automatically estimate all missing contracts inputs. If you need to decode logs or revert errors from the external contract you should add the `LogDecoder` with `add_log_decoder`.

```rust,ignore
{{#include ../../e2e/tests/logs.rs:external_contract}}
```

And this is an example that uses `with_contract_ids(&[&contract_id, ...])`.

```rust,ignore
{{#include ../../e2e/tests/logs.rs:external_contract_ids}}
```

## Configurable constants

Same as contracts, you can define `configurable` constants in `scripts` which can be changed during the script execution. Here is an example how the constants are defined.
Loading