Skip to content

Commit f4b22b7

Browse files
Torres-ssfpetertonysmith94arboleya
authored
feat: add support for pre-confirmations (#3857)
* fix changeset * using existent helper * Applied suggestions Co-authored-by: Anderson Arboleya <anderson@arboleya.me> * Fix hidden * improve docs * add docs API reference * define type for assembleTx response * refact code * add docs API reference * add link * improve doc description * remove documentation * add TS DOC * remove public word * add comments to code * add docs to method * remove config from doc page * add values to spell words file * moving docs around * add word to spell check file * make lint happy * fuck this doc lint thing, seriously * rename doc files * try to make lint happy * fix link * rollback changes on fundWithRequiredCoins * deprecate addSignersCallback * adjust test * made accountCoinQuantities optional * Added comments to `readEvent` * more comments * Update apps/docs/src/guide/transactions/assemble-tx.md Co-authored-by: Peter Smith <peter@blueoceancomputing.co.uk> * Update packages/account/src/providers/provider.ts Co-authored-by: Peter Smith <peter@blueoceancomputing.co.uk> * Update packages/fuel-gauge/src/call-test-contract.test.ts Co-authored-by: Peter Smith <peter@blueoceancomputing.co.uk> * nit * remove unused snippet * nit * adjusting test case * deprecating code * add comment * add doc section * deprecate `Account.getTransactionCost` * make lint happy * fix snippet code * Update apps/docs/src/guide/transactions/assemble-tx.md Co-authored-by: Anderson Arboleya <anderson@arboleya.me> * uncomment e2e * recoment tests for testnet * create new type ResourcesIDsToIgnore * rename excludedIds to resourcesIDsToIgnore * capturing two errors on mapGqlErrorMessage * simplify validation * update test suite * update doc snippet * create new error code * add error code to errors guide * remove error handling section from assembleTx docs * remove unused doc snippet * fix const key name * rename resourcesIDsToIgnore to resourcesIdsToIgnore * made assembleTx to return rawReceipts * refact tests related to improved JSON RPC * update assembleTx docs * add word to spell check * fix flaky test * feat: optimistic concurrency control (#3834) * Renamed to `ENABLE_RPC_CONSISTENCY` * WIP changes * linting * adjust test for SDK retry attempts * simplify some tests parameters * linting * remove BLOCK_HEIGHT_SENSITIVE_OPERATIONS * remove validation from loop * adjust test values * refact some code * linting --------- Co-authored-by: Torres-ssf <sergio.uft@gmail.com> Co-authored-by: Sérgio Torres <30977845+Torres-ssf@users.noreply.github.com> * Update apps/docs/src/guide/provider/rpc-consistency.md Co-authored-by: Anderson Arboleya <anderson@arboleya.me> * Update apps/docs/src/guide/provider/rpc-consistency.md Co-authored-by: Anderson Arboleya <anderson@arboleya.me> * Update apps/docs/src/guide/provider/rpc-consistency.md Co-authored-by: Anderson Arboleya <anderson@arboleya.me> * Update .changeset/yummy-tools-sip.md * chore: upgrade `fuel-core` to `0.43.0` (#3838) * Changeset * Added types for pre-conf * Added pre conf statuses * Add tests for PRECONFIRMATION_SUCCESS and PRECONFIRMATION_FAILURE statuses in transaction summary * Lintfix * Added `includePreconfirmation` method to the `sendTransaction` method * Added required flag for `includePreconfirmation` and `waitForPreconfirmation` to the `TransactionResponse` * remove preconf flag * skip some tests * include optional fields on preconfirmation tx fragments * rename method waitForStatusChange * ensure waitForConfirmation waits for the right statuses * add waitForPreConfirmationStatuses * create type PreConfirmationTransactionSummary * include preconfirmation statuses when submitting TX * add receipts property to preconfirmation statuses types * edit TransactionSummary type to maintain its old signature * extract receipts from preconfirmation statuses at processGraphqlStatus * wip assemblePreconfirmationTransactionSummary * implement waitForPreConfirmation helpers on TransactionResponse * remove skip from test * lint fix * remove pre confirmation status from transactionStatusFragment * add cast * rename internal method * improve readability * implement helper deserializeProcessedTxOutput * use deserializeProcessedTxOutput in favor of mapGqlOutputsToTxOutputs * expose * add type SubmittableTransactions * using SubmittableTransactions * remove unnecessary method * add note * implement inner helper * adding some notes * add rawPayload to PreconfirmationSuccessStatus statuses * extract transaction from pre confirmation statuses * refact assemblePreConfirmationTransactionSummary * consider transaction property on pre confirmation results * renaming some types * include resolved outputs within pre confirmation statuses * renaming type * creating new type for resolved outputs * extracting resolved outputs * create type PreConfirmationFunctionResult * implement helper buildPreConfirmationFunctionResult * add callback waitForPreConfirmation to baseInvocationScope * update test case * add errorReason to PreConfirmationTransactionSummary * add test case for preconfirmation false * rename flag on query * improve TS DOC * add flag includePreConfirmation to ProviderSendTxParams * stop using flag for now * undo * Upgrading `fuel-core` to `0.43.1` * remove unnecessary test * remove .skip * lint * Update .changeset/yummy-tools-sip.md * Upgrading `@fuels/vm-asm` to `0.66.1` * Updating lock file * re-introduce pre-confirmation * avoid using 2 subscriptions * remove test case * rollback change * chore: upgrading `forc` to `0.68.0` (#3860) * Upgrading `forc` to `0.68.0` * Adding [empty] changeset (not merging into `master`) * Adjusting changesets * avoid subscribing to the same event twice * fix promise resolvers on transaction response * adding more tests for pre-confirmation * remove test case retries * add test env * add missing graphql error map from master * adjusting pre confirmation types * adjusting test suite * fix test * slim down type PreConfirmationTransactionSummary * unnecessary test * add waitForPreConfirmation to DeployContractResult type * refact code * add more tests * add transaction properties to PreConfirmationTransactionSummary * extracting more properties on processGraphqlStatus * use transaction request on assemblePreConfirmationTransactionSummary * adjusting some tests * adding docs * adjust docs * add words to spell check * remove unnecessary .todo tests * add connector test case * Update apps/docs/src/guide/transactions/pre-confirmation.md Co-authored-by: Anderson Arboleya <anderson@arboleya.me> * Update apps/docs/src/guide/transactions/pre-confirmation.md Co-authored-by: Anderson Arboleya <anderson@arboleya.me> * Update apps/docs/src/guide/transactions/pre-confirmation.md Co-authored-by: Anderson Arboleya <anderson@arboleya.me> * Update apps/docs/src/guide/transactions/pre-confirmation.md Co-authored-by: Anderson Arboleya <anderson@arboleya.me> * Update apps/docs/src/guide/transactions/pre-confirmation.md Co-authored-by: Anderson Arboleya <anderson@arboleya.me> * Update apps/docs/src/guide/transactions/pre-confirmation.md Co-authored-by: Anderson Arboleya <anderson@arboleya.me> * Update apps/docs/src/guide/transactions/pre-confirmation.md Co-authored-by: Anderson Arboleya <anderson@arboleya.me> * Update apps/docs/.vitepress/config.ts Co-authored-by: Anderson Arboleya <anderson@arboleya.me> * Update apps/docs/src/guide/transactions/pre-confirmation.md Co-authored-by: Anderson Arboleya <anderson@arboleya.me> * Update apps/docs/src/guide/transactions/pre-confirmation.md Co-authored-by: Anderson Arboleya <anderson@arboleya.me> * rename doc page * update doc * Update apps/docs/src/guide/transactions/pre-confirmations.md Co-authored-by: Anderson Arboleya <anderson@arboleya.me> * Update apps/docs/src/guide/transactions/pre-confirmations.md Co-authored-by: Anderson Arboleya <anderson@arboleya.me> * Update apps/docs/src/guide/transactions/pre-confirmations.md Co-authored-by: Anderson Arboleya <anderson@arboleya.me> * Update apps/docs/src/guide/transactions/pre-confirmations.md Co-authored-by: Anderson Arboleya <anderson@arboleya.me> * Update apps/docs/src/guide/transactions/pre-confirmations.md Co-authored-by: Anderson Arboleya <anderson@arboleya.me> * Update apps/docs/src/guide/transactions/pre-confirmations.md Co-authored-by: Anderson Arboleya <anderson@arboleya.me> * Update apps/docs/src/guide/transactions/pre-confirmations.md Co-authored-by: Anderson Arboleya <anderson@arboleya.me> * Update apps/docs/src/guide/transactions/pre-confirmations.md Co-authored-by: Anderson Arboleya <anderson@arboleya.me> * Update apps/docs/src/guide/transactions/pre-confirmations.md Co-authored-by: Anderson Arboleya <anderson@arboleya.me> * Update apps/docs/src/guide/transactions/pre-confirmations.md Co-authored-by: Anderson Arboleya <anderson@arboleya.me> * Update apps/docs/src/guide/transactions/pre-confirmations.md Co-authored-by: Anderson Arboleya <anderson@arboleya.me> * add some comments on the code * improve docs --------- Co-authored-by: Peter Smith <peter@blueoceancomputing.co.uk> Co-authored-by: Anderson Arboleya <anderson@arboleya.me>
1 parent 640d613 commit f4b22b7

File tree

26 files changed

+1595
-255
lines changed

26 files changed

+1595
-255
lines changed

.changeset/empty-pandas-invent.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
---
3+
4+
feat: add support for pre-confirmations

apps/docs/.vitepress/config.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,10 @@ export default defineConfig({
381381
text: 'Optimizing Frontend Apps',
382382
link: '/guide/transactions/optimizing-frontend-apps',
383383
},
384+
{
385+
text: 'Pre-Confirmations',
386+
link: '/guide/transactions/pre-confirmations',
387+
},
384388
],
385389
},
386390
{

apps/docs/spell-check-custom-words.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,3 +356,7 @@ io
356356
asm
357357
github
358358
vm
359+
PreconfirmationSuccessStatus
360+
PreconfirmationFailureStatus
361+
OutputChange
362+
OutputVariable
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Pre-Confirmations
2+
3+
## What is a Pre-Confirmation?
4+
5+
A **pre-confirmation** is an intermediate transaction status that occurs after a transaction has been **submitted** and **accepted** by the blockchain, but **before** it is fully **processed and included** in a new block.
6+
7+
At this stage, the transaction is pre-executed and assigned one of two possible statuses:
8+
9+
- `PreconfirmationSuccessStatus`: The transaction is expected to be successfully included in a future block.
10+
11+
- `PreconfirmationFailureStatus`: The transaction will **not** be included in any future block.
12+
13+
## Why are Pre-Confirmations important?
14+
15+
Pre-confirmations allow applications to **react earlier** by providing immediate feedback about a transaction's expected outcome without waiting for full block finalization.
16+
17+
Additionally, pre-confirmations expose **processed outputs** (such as `OutputChange` and `OutputVariable`) that can be **immediately reused** in new transactions.
18+
19+
## Available Outputs for Pre-Confirmations
20+
21+
When a transaction reaches the **pre-confirmation** stage, certain `resolvedOutputs` become available:
22+
23+
- `OutputChange`: Represents the change UTXO generated from unspent inputs, grouped by `assetId` (one per asset).
24+
25+
- `OutputVariable`: Similar to `OutputCoin`, but only created if the transaction succeeds.
26+
27+
These outputs can be:
28+
29+
- Extracted directly from the pre-confirmation response.
30+
- **Used immediately** to fund new transactions, without waiting for block confirmation.
31+
32+
This significantly improves the ability to build transaction sequences or reactive transaction flows.
33+
34+
This is the `ResolvedOutput` interface structure:
35+
36+
<<< @/../../../packages/account/src/providers/transaction-summary/types.ts#resolved-output-type{ts:line-numbers}
37+
38+
## Example Workflow
39+
40+
Suppose you send a transaction that will send funds to another wallet.
41+
42+
As soon as you receive a `PreconfirmationSuccessStatus`, you can:
43+
44+
- Use the `OutputChange` in a new transaction.
45+
- Submit the next transaction **without waiting** for block finalization.
46+
47+
This reduces wait times and accelerates transaction chaining.
48+
49+
## Code Examples
50+
51+
### Using Pre-Confirmations when Submitting a Transfer
52+
53+
The following example sends a transfer, waits for the pre-confirmation success, and then submits another transfer using the resolved outputs from the first:
54+
55+
<<< @./snippets/pre-confirmation/send-transaction.ts#pre-confirmation-send-transaction-1{ts:line-numbers}
56+
57+
### Using Pre-Confirmations with a Contract Call
58+
59+
This example performs a contract call, waits for pre-confirmation success, and then uses the resolved output to execute another contract call:
60+
61+
<<< @./snippets/pre-confirmation/contract-call.ts#pre-confirmation-contract-call-1{ts:line-numbers}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { Address, bn, OutputType, Provider, Wallet } from 'fuels';
2+
3+
import { LOCAL_NETWORK_URL, WALLET_PVT_KEY } from '../../../../env';
4+
import { CounterFactory } from '../../../../typegend';
5+
6+
const provider = new Provider(LOCAL_NETWORK_URL);
7+
8+
const wallet = Wallet.fromPrivateKey(WALLET_PVT_KEY, provider);
9+
const baseAssetId = await provider.getBaseAssetId();
10+
const { waitForResult } = await new CounterFactory(wallet).deploy();
11+
const { contract } = await waitForResult();
12+
13+
// #region pre-confirmation-contract-call-1
14+
// Send a contract call and retrieve the pre-confirmation callback
15+
const { waitForPreConfirmation } = await contract.functions
16+
.increment_count(1)
17+
.call();
18+
19+
const {
20+
transactionResult: { resolvedOutputs, isStatusPreConfirmationSuccess },
21+
} = await waitForPreConfirmation();
22+
23+
// Check if the pre-confirmation status indicates success
24+
if (isStatusPreConfirmationSuccess) {
25+
// Find the change output associated with the base asset ID
26+
const resolvedChangeOutput = resolvedOutputs?.find(
27+
(resolved) =>
28+
resolved.output.type === OutputType.Change &&
29+
resolved.output.assetId === baseAssetId
30+
);
31+
32+
// If we find the change output, we can use it to create a new transaction
33+
if (resolvedChangeOutput) {
34+
const { output, utxoId } = resolvedChangeOutput;
35+
36+
// Create a new transaction request for a new contract call
37+
const request = await contract.functions
38+
.increment_count(1)
39+
.txParams({
40+
maxFee: 100_000,
41+
gasLimit: 100_000,
42+
})
43+
.getTransactionRequest();
44+
45+
// Add the change output as an input resource for the new transaction
46+
request.addResource({
47+
id: utxoId,
48+
assetId: output.assetId,
49+
amount: output.amount,
50+
owner: new Address(output.to),
51+
blockCreated: bn(0),
52+
txCreatedIdx: bn(0),
53+
});
54+
55+
// Send the new transaction
56+
await wallet.sendTransaction(request);
57+
}
58+
}
59+
// #endregion pre-confirmation-contract-call-1
60+
61+
console.log('isPreConfirmationStatusSuccess', isStatusPreConfirmationSuccess);
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import {
2+
Address,
3+
bn,
4+
OutputType,
5+
Provider,
6+
ScriptTransactionRequest,
7+
Wallet,
8+
} from 'fuels';
9+
10+
import {
11+
LOCAL_NETWORK_URL,
12+
WALLET_PVT_KEY,
13+
WALLET_PVT_KEY_2,
14+
WALLET_PVT_KEY_3,
15+
} from '../../../../env';
16+
17+
// #region pre-confirmation-send-transaction-1
18+
const provider = new Provider(LOCAL_NETWORK_URL);
19+
20+
const wallet = Wallet.fromPrivateKey(WALLET_PVT_KEY, provider);
21+
const recipient1 = Wallet.fromPrivateKey(WALLET_PVT_KEY_2, provider);
22+
const recipient2 = Wallet.fromPrivateKey(WALLET_PVT_KEY_3, provider);
23+
const baseAssetId = await provider.getBaseAssetId();
24+
25+
// Send a transfer and retrieve the pre-confirmation callback
26+
const { waitForPreConfirmation } = await wallet.transfer(
27+
recipient1.address,
28+
1000
29+
);
30+
31+
// Wait for the transaction to reach a pre-confirmation status
32+
const { resolvedOutputs, isStatusPreConfirmationSuccess } =
33+
await waitForPreConfirmation();
34+
35+
// Check if the pre-confirmation status indicates success
36+
if (isStatusPreConfirmationSuccess) {
37+
// Find the change output associated with the base asset ID
38+
const resolvedChangeOutput = resolvedOutputs?.find(
39+
(resolved) =>
40+
resolved.output.type === OutputType.Change &&
41+
resolved.output.assetId === baseAssetId
42+
);
43+
44+
// If we find the change output, we can use it to create a new transaction
45+
if (resolvedChangeOutput) {
46+
const { output, utxoId } = resolvedChangeOutput;
47+
48+
// Create a new transaction request
49+
const newTransaction = new ScriptTransactionRequest({
50+
maxFee: 1000,
51+
gasLimit: 1000,
52+
});
53+
54+
// Add the change output as an input resource for the new transaction
55+
newTransaction.addResource({
56+
id: utxoId,
57+
assetId: output.assetId,
58+
amount: output.amount,
59+
owner: new Address(output.to),
60+
blockCreated: bn(0),
61+
txCreatedIdx: bn(0),
62+
});
63+
64+
// Define the transfer recipient of the new transaction
65+
newTransaction.addCoinOutput(recipient2.address, 1000, baseAssetId);
66+
67+
// Send the new transaction
68+
await wallet.sendTransaction(newTransaction);
69+
}
70+
}
71+
// #endregion pre-confirmation-send-transaction-1
72+
73+
console.log('isPreConfirmationStatusSuccess', isStatusPreConfirmationSuccess);

packages/account/src/account.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,9 @@ describe('Account', () => {
340340

341341
expect(sendTransaction.mock.calls.length).toEqual(1);
342342
expect(sendTransaction.mock.calls[0][0]).toEqual(transactionRequest);
343+
expect(sendTransaction.mock.calls[0][1], 'Should have default parameters').toEqual({
344+
estimateTxDependencies: false,
345+
});
343346
});
344347

345348
it('should execute simulateTransaction just fine', async () => {

packages/account/src/providers/operations.graphql

Lines changed: 109 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,85 @@ fragment SqueezedOutStatusFragment on SqueezedOutStatus {
122122
reason
123123
}
124124

125+
fragment PreconfirmationSuccessStatusFragment on PreconfirmationSuccessStatus {
126+
type: __typename
127+
totalGas
128+
totalFee
129+
resolvedOutputs {
130+
utxoId
131+
output {
132+
type: __typename
133+
... on CoinOutput {
134+
to
135+
amount
136+
assetId
137+
}
138+
... on ContractOutput {
139+
inputIndex
140+
balanceRoot
141+
stateRoot
142+
}
143+
... on ChangeOutput {
144+
to
145+
amount
146+
assetId
147+
}
148+
... on VariableOutput {
149+
to
150+
amount
151+
assetId
152+
}
153+
... on ContractCreated {
154+
contract
155+
stateRoot
156+
}
157+
}
158+
}
159+
preconfirmationReceipts: receipts {
160+
...receiptFragment
161+
}
162+
}
163+
164+
fragment PreconfirmationFailureStatusFragment on PreconfirmationFailureStatus {
165+
type: __typename
166+
reason
167+
totalGas
168+
totalFee
169+
resolvedOutputs {
170+
utxoId
171+
output {
172+
type: __typename
173+
... on CoinOutput {
174+
to
175+
amount
176+
assetId
177+
}
178+
... on ContractOutput {
179+
inputIndex
180+
balanceRoot
181+
stateRoot
182+
}
183+
... on ChangeOutput {
184+
to
185+
amount
186+
assetId
187+
}
188+
... on VariableOutput {
189+
to
190+
amount
191+
assetId
192+
}
193+
... on ContractCreated {
194+
contract
195+
stateRoot
196+
}
197+
}
198+
}
199+
preconfirmationReceipts: receipts {
200+
...receiptFragment
201+
}
202+
}
203+
125204
fragment transactionStatusFragment on TransactionStatus {
126205
... on SubmittedStatus {
127206
...SubmittedStatusFragment
@@ -196,6 +275,12 @@ fragment transactionStatusSubscriptionFragment on TransactionStatus {
196275
... on SqueezedOutStatus {
197276
...SqueezedOutStatusFragment
198277
}
278+
... on PreconfirmationSuccessStatus {
279+
...PreconfirmationSuccessStatusFragment
280+
}
281+
... on PreconfirmationFailureStatus {
282+
...PreconfirmationFailureStatusFragment
283+
}
199284
}
200285

201286
fragment transactionFragment on Transaction {
@@ -592,6 +677,12 @@ query getTransactionWithReceipts($transactionId: TransactionId!) {
592677
... on SqueezedOutStatus {
593678
...SqueezedOutStatusFragment
594679
}
680+
... on PreconfirmationSuccessStatus {
681+
...PreconfirmationSuccessStatusFragment
682+
}
683+
... on PreconfirmationFailureStatus {
684+
...PreconfirmationFailureStatusFragment
685+
}
595686
}
596687
}
597688
}
@@ -1042,14 +1133,28 @@ query getConsensusParametersVersion {
10421133
}
10431134
}
10441135

1045-
subscription submitAndAwaitStatus($encodedTransaction: HexString!) {
1046-
submitAndAwaitStatus(tx: $encodedTransaction) {
1136+
subscription submitAndAwaitStatus(
1137+
$encodedTransaction: HexString!
1138+
$estimatePredicates: Boolean
1139+
$includePreConfirmation: Boolean
1140+
) {
1141+
submitAndAwaitStatus(
1142+
tx: $encodedTransaction
1143+
estimatePredicates: $estimatePredicates
1144+
includePreconfirmation: $includePreConfirmation
1145+
) {
10471146
...transactionStatusSubscriptionFragment
10481147
}
10491148
}
10501149

1051-
subscription statusChange($transactionId: TransactionId!) {
1052-
statusChange(id: $transactionId) {
1150+
subscription statusChange(
1151+
$transactionId: TransactionId!
1152+
$includePreConfirmation: Boolean
1153+
) {
1154+
statusChange(
1155+
id: $transactionId
1156+
includePreconfirmation: $includePreConfirmation
1157+
) {
10531158
...transactionStatusSubscriptionFragment
10541159
}
10551160
}

0 commit comments

Comments
 (0)