-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
base: master
Are you sure you want to change the base?
Conversation
It seems that we're not passing the sdk cached coins to the |
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
let exclude = match exclude { | ||
Some((mut utxos, mut nonces)) => { | ||
utxos.extend(cache_utxos); | ||
nonces.extend(cache_nonces); | ||
|
||
Some((utxos, nonces)) | ||
} | ||
None => Some((cache_utxos, cache_nonces)), | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the provider is used concurrently then the cache can have entries unrelated to the owners mentioned here. Technically the minimum we can send here is just the cached utxos and nonces of the owners mentioned in require balances.
If the user clones the provider a lot (like they should do if they want to reuse the underlying connection pool) and if they use it to send concurrent transactions then we could end up having this request be bigger than it needs to be.
Not sure that's necessarily a huge deal, but just pointing it out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Co-authored-by: Ahmed Sagdati <[email protected]>
Co-authored-by: Ahmed Sagdati <[email protected]>
Co-authored-by: Ahmed Sagdati <[email protected]>
Co-authored-by: Ahmed Sagdati <[email protected]>
Co-authored-by: Ahmed Sagdati <[email protected]>
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. |
There was a problem hiding this comment.
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"?
@@ -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. |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
@@ -291,21 +288,20 @@ async fn test_contract_call_fee_estimation() -> Result<()> { | |||
), | |||
); | |||
|
|||
let gas_limit = 800; | |||
let gas_limit = 3800; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did this need to increase so much? I assume it's somewhat arbitrary, but I wouldn't expect assemble-tx to significantly increase costs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had to increase the scipt gas limit here as the old value would have no effect. As it is lower then the script gas estimated by assemble tx it would have been overwritten by the higher value.
@@ -390,13 +390,13 @@ async fn multi_call_contract_with_contract_logs() -> Result<()> { | |||
|
|||
let call_handler_1 = contract_caller_instance | |||
.methods() | |||
.logs_from_external_contract(contract_instance.id()) | |||
.with_contracts(&[&contract_instance]); | |||
.logs_from_external_contract(contract_instance.contract_id()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(With my limited context) I think I kinda prefer the id()
syntax more. What was the thought process of changing that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The id()
method was part of a removed ContractDependency
trait. I wanted the method to be clearer on what id it returns :). we can, of course, change it to id
if it is clear enough.
@@ -835,6 +810,43 @@ async fn transactions_with_the_same_utxo() -> Result<()> { | |||
Ok(()) | |||
} | |||
|
|||
#[cfg(feature = "coin-cache")] | |||
#[tokio::test] | |||
async fn transfers_at_same_time_with_cache() -> Result<()> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we could name it something like
async fn transfers_at_same_time_with_cache() -> Result<()> { | |
async fn transfer__assemble_tx_can_remove_used_coins() -> Result<()> { |
Also can we add given/when/then
?
@@ -1453,3 +1465,51 @@ async fn is_account_query_test() -> Result<()> { | |||
|
|||
Ok(()) | |||
} | |||
|
|||
#[tokio::test] | |||
async fn assemble_tx_transfer() -> Result<()> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this test exists for the purpose of documentation. I think we should mark it as such, maybe in the name? What do you think?
@@ -123,6 +123,27 @@ async fn adjust_fee_empty_transaction() -> Result<()> { | |||
Ok(()) | |||
} | |||
|
|||
#[tokio::test] | |||
async fn adjust_for_fee_error() -> Result<()> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add more clarity here. G/W/T and a more informative name?
Ok(script_transaction) | ||
} | ||
|
||
async fn assemble_tx( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have tests for each implementation of assemble_tx
, for all the tx types?
closes: #1641
Release notes
In this release, we:
Summary
We added support for assemble transactions and made it the default build strategy for all
CallHandlers
and transfers.Breaking Changes
Contract dependencies → automatic & log decoding
The old
with_contracts
/with_contract_ids
APIs are gone—contract inputs are now set using assemble tx, and if you need to decode logs/reverts you pass in the external contract’s decoder:Dependency & output estimation → fully automatic
You no longer need to chain on
with_variable_output_policy(...)
or calldetermine_missing_contracts()
: the SDK will auto-estimate both missing contracts and variable outputs.Script gas limit & TxPolicies → dedicated handler method
TxPolicies
does not hold thescript_gas_limit
anymore. Use.with_script_gas_limit(n)
directly on your call handler.Transaction submission →
submit
send_transaction
is renamed tosubmit
Manual fee/inputs adjustment → “assemble” strategy
You do not have to use
wallet.adjust_for_fee(&mut tb, …).await?
if you use the new assemble strategy.Removed the
ContractDependency
traitChecklist