Skip to content

feat(txm): Stellar TXM broadcast, confirm, restore, and invoker integration#111

Open
Krish-vemula wants to merge 10 commits into
mainfrom
feat/stellar-txm-lifecycle
Open

feat(txm): Stellar TXM broadcast, confirm, restore, and invoker integration#111
Krish-vemula wants to merge 10 commits into
mainfrom
feat/stellar-txm-lifecycle

Conversation

@Krish-vemula
Copy link
Copy Markdown
Contributor

@Krish-vemula Krish-vemula commented May 12, 2026

Summary

Implements the Stellar/Soroban transaction manager end-to-end: transactions move through enqueue, simulation, optional restore when state is expired, assembly, signing, submit, and confirmation, with background broadcast and confirm loops, fee handling, retries, pruning, and metrics. Adds InvokerAdapter so generated contract bindings can route state-changing work through EnqueueAndWait and read paths through simulation. Builds on the chain wiring from the interface PR (this branch is a superset of main for the same chain/mocks files).

What changed

  • relayer/chain
    • Same as the interface PR, plus resolving NetworkPassphrase from chain ID (txm.NetworkPassphrase) and constructing the real TXM with txm.Config{} and passphrase (no new required TOML passphrase field; passphrases come from public/testnet mapping in code).
  • relayer/txm
    • txm.goStellarTxm service: start/stop, broadcast + confirm goroutines, enqueue / wait APIs, account store, integration with config, fees, store, and metrics.
    • broadcast.go — build / simulate / sign / send path and shared helpers used by tests.
    • restore.go — restore footprint flow from simulation, submit, retries, metrics.
    • invoker_adapter.gobindings.Invoker-style adapter over TXM enqueue + simulate with ledger bounds / source options.
    • config.go, fee.go, metrics.go, failed_result.go, tx.go, txstore.go, utils.go, network.go — defaults, fee strategy, metrics, failure modeling, in-memory tx model + store, helpers, passphrase resolution by chainID.
    • Testsconfig_test, fee_test, failed_result_test, txstore_test, txm_test, broadcast_test, handle_send_test, invoker_adapter_test.
  • internal/mocks — aligned with expanded Chain / RPCClient (including methods the full TXM path uses).

@Krish-vemula Krish-vemula changed the title Feat/stellar txm lifecycle feat(txm): Stellar TXM broadcast, confirm, restore, and invoker integration May 12, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 12, 2026

Soroban Contract Test Coverage

92.71% line coverage — 16414 / 17704 lines hit

Metric Hit Total Coverage
Lines 16414 17704 92.71%
Functions 1036 1326 78.13%
Regions 29982 32137 93.29%

Per-Contract Breakdown

Contract Lines (Hit / Total) Line Cov Funcs (Hit / Total) Func Cov
other 16414 / 17704 92.7% 1036 / 1326 78.1%
Full file-level coverage report
Filename                                                 Regions    Missed Regions     Cover   Functions  Missed Functions  Executed       Lines      Missed Lines     Cover    Branches   Missed Branches     Cover
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ccip-ramp-registry/src/lib.rs                                188                75    60.11%           8                 3    62.50%         104                41    60.58%           0                 0         -
ccip-ramp-registry/src/test.rs                               214                 0   100.00%           5                 0   100.00%         128                 0   100.00%           0                 0         -
ccip-ramp-registry/src/types.rs                               83                11    86.75%          17                 6    64.71%          83                11    86.75%           0                 0         -
ccvs/committee-verifier/src/lib.rs                           438                43    90.18%          22                 2    90.91%         294                 8    97.28%           0                 0         -
ccvs/committee-verifier/src/test.rs                         1363                28    97.95%          49                 2    95.92%         621                15    97.58%           0                 0         -
ccvs/committee-verifier/src/types.rs                          15                 6    60.00%           4                 3    25.00%          12                 5    58.33%           0                 0         -
ccvs/versioned-verifier-resolver/src/lib.rs                  287                21    92.68%          14                 1    92.86%         162                 4    97.53%           0                 0         -
ccvs/versioned-verifier-resolver/src/test.rs                 680                 9    98.68%          20                 0   100.00%         359                 3    99.16%           0                 0         -
ccvs/versioned-verifier-resolver/src/types.rs                 89                 6    93.26%          16                 4    75.00%          83                 4    95.18%           0                 0         -
common/authorization/src/allowlist.rs                        167                51    69.46%          12                 4    66.67%         110                40    63.64%           0                 0         -
common/authorization/src/lib.rs                              426                27    93.66%          16                 0   100.00%         277                16    94.22%           0                 0         -
common/authorization/src/ownable.rs                          102                13    87.25%           9                 1    88.89%          62                 6    90.32%           0                 0         -
common/authorization/src/test.rs                            1195                 0   100.00%          57                 0   100.00%         462                 0   100.00%           0                 0         -
common/guard/src/initializable.rs                             30                 1    96.67%           4                 0   100.00%          22                 1    95.45%           0                 0         -
common/guard/src/lib.rs                                       32                 1    96.88%           4                 0   100.00%          22                 0   100.00%           0                 0         -
common/guard/src/test.rs                                     101                 0   100.00%           8                 0   100.00%          47                 0   100.00%           0                 0         -
common/helpers/src/curse_checkable.rs                        103                24    76.70%           6                 1    83.33%          56                12    78.57%           0                 0         -
common/helpers/src/map_updater.rs                             94                15    84.04%           7                 3    57.14%          39                 8    79.49%           0                 0         -
common/helpers/src/soroban_invoke.rs                         204                 4    98.04%           8                 0   100.00%          81                 0   100.00%           0                 0         -
common/interfaces/src/ccip_receiver.rs                         8                 8     0.00%           8                 8     0.00%           8                 8     0.00%           0                 0         -
common/interfaces/src/committee_verifier.rs                   10                10     0.00%          10                10     0.00%          10                10     0.00%           0                 0         -
common/interfaces/src/fee_quoter.rs                           17                17     0.00%          17                17     0.00%          17                17     0.00%           0                 0         -
common/interfaces/src/offramp.rs                              11                11     0.00%          11                11     0.00%          11                11     0.00%           0                 0         -
common/interfaces/src/onramp.rs                                9                 9     0.00%           9                 9     0.00%           9                 9     0.00%           0                 0         -
common/interfaces/src/ramp_registry.rs                         5                 5     0.00%           5                 5     0.00%           5                 5     0.00%           0                 0         -
common/interfaces/src/rmn_proxy.rs                             6                 6     0.00%           6                 6     0.00%           6                 6     0.00%           0                 0         -
common/interfaces/src/router.rs                                9                 9     0.00%           9                 9     0.00%           9                 9     0.00%           0                 0         -
common/interfaces/src/siloed_lock_release_pool.rs             21                21     0.00%          21                21     0.00%          21                21     0.00%           0                 0         -
common/interfaces/src/token_admin_registry.rs                  8                 8     0.00%           8                 8     0.00%           8                 8     0.00%           0                 0         -
common/interfaces/src/token_lock_box.rs                        6                 6     0.00%           6                 6     0.00%           6                 6     0.00%           0                 0         -
common/interfaces/src/token_pool.rs                           11                11     0.00%          11                11     0.00%          11                11     0.00%           0                 0         -
common/interfaces/src/versioned_verifier_resolver.rs          10                10     0.00%          10                10     0.00%          10                10     0.00%           0                 0         -
common/message/src/lib.rs                                    586                41    93.00%          28                 4    85.71%         298                 9    96.98%           0                 0         -
common/message/src/test.rs                                   641                 2    99.69%          28                 0   100.00%         323                 0   100.00%           0                 0         -
common/pool/src/decimals.rs                                  109                10    90.83%           6                 0   100.00%          76                 3    96.05%           0                 0         -
common/pool/src/finality_codec.rs                             52                 1    98.08%           3                 0   100.00%          41                 0   100.00%           0                 0         -
common/pool/src/lib.rs                                       460                31    93.26%          32                 1    96.88%         409                26    93.64%           0                 0         -
common/pool/src/rate_limit.rs                                180                 7    96.11%           9                 0   100.00%         145                 3    97.93%           0                 0         -
common/pool/src/types.rs                                      20                14    30.00%          16                14    12.50%          30                14    53.33%           0                 0         -
common/verifier/src/signatures.rs                            293                18    93.86%          10                 2    80.00%         192                11    94.27%           0                 0         -
fee-quoter/src/lib.rs                                        771               164    78.73%          20                 3    85.00%         527               100    81.02%           0                 0         -
fee-quoter/src/test.rs                                       861                 0   100.00%          17                 0   100.00%         427                 0   100.00%           0                 0         -
fee-quoter/src/types.rs                                       13                13     0.00%          13                13     0.00%          13                13     0.00%           0                 0         -
mcms/src/abi_encoding.rs                                     216                 5    97.69%          10                 0   100.00%          98                 2    97.96%           0                 0         -
mcms/src/constants.rs                                         10                 0   100.00%           2                 0   100.00%           6                 0   100.00%           0                 0         -
mcms/src/crypto.rs                                           202                 3    98.51%           7                 0   100.00%         109                 2    98.17%           0                 0         -
mcms/src/error.rs                                              8                 4    50.00%           1                 0   100.00%           8                 4    50.00%           0                 0         -
mcms/src/lib.rs                                              713                52    92.71%          20                 0   100.00%         483                24    95.03%           0                 0         -
mcms/src/test.rs                                            2057                18    99.12%          55                 0   100.00%         987                 2    99.80%           0                 0         -
mcms/src/types.rs                                             10                10     0.00%          10                10     0.00%          10                10     0.00%           0                 0         -
offramp/src/lib.rs                                           729               400    45.13%          23                 8    65.22%         473               224    52.64%           0                 0         -
offramp/src/test.rs                                          890                 0   100.00%          28                 0   100.00%         363                 0   100.00%           0                 0         -
offramp/src/types.rs                                          21                 9    57.14%           6                 5    16.67%          17                 7    58.82%           0                 0         -
onramp/src/lib.rs                                           1181               149    87.38%          27                 2    92.59%         739                61    91.75%           0                 0         -
onramp/src/test.rs                                          1591                 4    99.75%          37                 0   100.00%         708                 4    99.44%           0                 0         -
onramp/src/types.rs                                           23                 9    60.87%           6                 5    16.67%          19                 7    63.16%           0                 0         -
pools/burn-mint-pool/src/lib.rs                              390               107    72.56%          28                 9    67.86%         282                55    80.50%           0                 0         -
pools/burn-mint-pool/src/test.rs                            2671                24    99.10%          56                 5    91.07%        1744                55    96.85%           0                 0         -
pools/lock-release-pool/src/lib.rs                           404               100    75.25%          28                 8    71.43%         288                48    83.33%           0                 0         -
pools/lock-release-pool/src/test.rs                         2330                24    98.97%          55                 5    90.91%        1524                55    96.39%           0                 0         -
pools/siloed-lock-release-pool/src/lib.rs                    556               196    64.75%          38                17    55.26%         384               123    67.97%           0                 0         -
pools/siloed-lock-release-pool/src/test.rs                  1303                12    99.08%          38                 2    94.74%         695                18    97.41%           0                 0         -
pools/token-lock-box/src/lib.rs                              197                17    91.37%          13                 1    92.31%         113                 2    98.23%           0                 0         -
pools/token-lock-box/src/test.rs                             257                 0   100.00%           7                 0   100.00%          73                 0   100.00%           0                 0         -
registry/src/lib.rs                                            8                 0   100.00%           1                 0   100.00%           3                 0   100.00%           0                 0         -
registry/src/test.rs                                          27                 0   100.00%           1                 0   100.00%          11                 0   100.00%           0                 0         -
rmn_proxy/src/lib.rs                                          66                12    81.82%           5                 1    80.00%          34                 3    91.18%           0                 0         -
rmn_proxy/src/test.rs                                        279                 0   100.00%          11                 0   100.00%          91                 0   100.00%           0                 0         -
rmn_remote/src/lib.rs                                        302                26    91.39%          16                 1    93.75%         171                10    94.15%           0                 0         -
rmn_remote/src/test.rs                                       393                 0   100.00%          14                 0   100.00%         133                 0   100.00%           0                 0         -
router/src/lib.rs                                            593                87    85.33%          18                 1    94.44%         374                43    88.50%           0                 0         -
router/src/test.rs                                          1186                 0   100.00%          29                 0   100.00%         497                 0   100.00%           0                 0         -
router/src/test_panic_receiver.rs                              5                 0   100.00%           2                 0   100.00%           5                 0   100.00%           0                 0         -
router/src/types.rs                                            3                 3     0.00%           3                 3     0.00%           3                 3     0.00%           0                 0         -
timelock/src/error.rs                                          6                 2    66.67%           1                 0   100.00%           6                 2    66.67%           0                 0         -
timelock/src/lib.rs                                          649                46    92.91%          32                 2    93.75%         393                18    95.42%           0                 0         -
timelock/src/roles.rs                                        141                10    92.91%           6                 0   100.00%          76                 7    90.79%           0                 0         -
timelock/src/storage.rs                                      115                15    86.96%          12                 1    91.67%          68                 7    89.71%           0                 0         -
timelock/src/test.rs                                        1479                16    98.92%          37                 0   100.00%         531                 1    99.81%           0                 0         -
timelock/src/types.rs                                          3                 3     0.00%           3                 3     0.00%           3                 3     0.00%           0                 0         -
token-admin-registry/src/lib.rs                              368                23    93.75%          18                 1    94.44%         257                 4    98.44%           0                 0         -
token-admin-registry/src/test.rs                             825                 0   100.00%          21                 0   100.00%         287                 0   100.00%           0                 0         -
token-admin-registry/src/types.rs                              2                 2     0.00%           2                 2     0.00%           2                 2     0.00%           0                 0         -
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
TOTAL                                                      32137              2155    93.29%        1326               290    78.13%       17704              1290    92.71%           0                 0         -```

</details>

> Commit `1c6c643e` | [Full CI run](https://github.com/smartcontractkit/chainlink-stellar/actions/runs/26837314770)

<!-- Sticky Pull Request Commentcontract-coverage -->

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 12, 2026

Integration Test Coverage (Token Pool)

total:														(statements)				2.6%

Full coverage report

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 12, 2026

Integration Test Coverage (excl. Token Pool)

total:														(statements)				4.5%

Full coverage report

@Krish-vemula Krish-vemula requested a review from amit-momin May 12, 2026 17:21
@Krish-vemula Krish-vemula marked this pull request as ready for review May 12, 2026 17:21
@Krish-vemula Krish-vemula requested a review from ilija42 May 12, 2026 17:21
Comment thread relayer/chain/chain.go Outdated
Comment thread relayer/txm/broadcast.go Outdated
Comment thread relayer/txm/broadcast.go
Comment thread relayer/txm/broadcast.go Outdated
Comment thread relayer/txm/broadcast.go
Comment thread relayer/txm/broadcast.go Outdated
Comment thread relayer/txm/broadcast.go
Comment thread relayer/txm/broadcast.go
Comment thread relayer/txm/broadcast.go Outdated
Comment thread relayer/txm/broadcast.go Outdated
Comment thread relayer/txm/broadcast.go Outdated
Comment thread relayer/txm/txm.go Outdated
Comment thread relayer/txm/broadcast.go Outdated
return simResult, nil
}

func isRetryableSimulationError(ctx context.Context, err error) bool {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

what is this list of errors based on?

Comment thread relayer/txm/broadcast.go
simResult, err := client.SimulateTransaction(ctx, protocolrpc.SimulateTransactionRequest{
Transaction: txXDR,
})
s.metrics.ObserveSimulationDuration(ctx, time.Since(start).Seconds())
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

what is the use case for tracking this?

Comment thread relayer/txm/broadcast.go Outdated
Comment thread relayer/txm/broadcast.go Outdated
Comment thread relayer/txm/broadcast.go Outdated
Comment thread relayer/txm/txm.go Outdated
Comment thread relayer/txm/tx.go Outdated
Comment thread relayer/txm/txm.go
Comment on lines +372 to +417
func (s *StellarTxm) updateTransactionStatus(tx *StellarTx, status commontypes.TransactionStatus) {
s.transactionsLock.Lock()
defer s.transactionsLock.Unlock()
tx.Status = status
}

func (s *StellarTxm) updateTransactionHash(tx *StellarTx, hash string) {
s.transactionsLock.Lock()
defer s.transactionsLock.Unlock()
tx.TxHash = hash
}

func (s *StellarTxm) updateTransactionFee(tx *StellarTx, fee *big.Int) {
s.transactionsLock.Lock()
defer s.transactionsLock.Unlock()
tx.Fee = fee
}

func (s *StellarTxm) updateTransactionResultXDR(tx *StellarTx, resultXDR string) {
s.transactionsLock.Lock()
defer s.transactionsLock.Unlock()
tx.ResultXDR = resultXDR
}

func (s *StellarTxm) updateTransactionResultCode(tx *StellarTx, code string) {
s.transactionsLock.Lock()
defer s.transactionsLock.Unlock()
tx.ResultCode = code
}

func (s *StellarTxm) updateTransactionResultMeta(tx *StellarTx, resultMetaXDR string) {
s.transactionsLock.Lock()
defer s.transactionsLock.Unlock()
tx.ResultMetaXDR = resultMetaXDR
}

func (s *StellarTxm) incrementTransactionAttempt(tx *StellarTx) {
s.transactionsLock.Lock()
defer s.transactionsLock.Unlock()
tx.Attempt++
}

func (s *StellarTxm) getTransactionAttempt(tx *StellarTx) uint64 {
s.transactionsLock.RLock()
defer s.transactionsLock.RUnlock()
return tx.Attempt
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

These tx field value updates are too resource intensive, this same lock is used everywhere

Comment thread relayer/txm/txm.go
getClient func() (RPCClient, error)
}
transactions map[string]*StellarTx
transactionsLock sync.RWMutex
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This lock is used as a universal lock, please at least add a TODO here to make txm concurrent and improve how locks are handled

Comment thread relayer/txm/metrics.go Outdated
Comment thread relayer/txm/txm.go Outdated
Comment thread relayer/txm/txm.go
Comment thread relayer/txm/broadcast_test.go Outdated
Comment thread relayer/txm/broadcast_test.go
Comment thread relayer/txm/broadcast_test.go Outdated
Comment thread relayer/txm/config.go
@Krish-vemula Krish-vemula requested a review from amit-momin May 20, 2026 22:42
Comment thread relayer/txm/fee_tracker_test.go Outdated
Comment thread relayer/txm/fee_tracker.go Outdated
Comment thread relayer/chain/chain.go Outdated
Comment thread relayer/txm/txstore.go
Comment thread relayer/txm/txm_test.go
@ilija42 ilija42 requested a review from yashnevatia May 25, 2026 13:56
Comment thread relayer/txm/broadcast.go Outdated
Comment thread relayer/txm/broadcast.go Outdated
Comment thread relayer/txm/fee_tracker.go Outdated
resp, fetchErr := client.GetFeeStats(ctx)
if fetchErr != nil {
if t.haveData {
return t.p50, t.p90, true, nil
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

what if this call keeps failing ? do we keep returning stale data ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, by design. Once we have a successful GetFeeStats, repeated failures keep returning that last snapshot (err == nil) so we do not drop inclusion-fee seeding to baseline on every blip. There is no max staleness today; only a failed refresh before any success yields an error and the geometric baseline. Documented on feeTracker / sorobanInclusionPercentiles. If we want a cap or extra observability after prolonged failure, we can add a follow-up (e.g. max staleness or warn logs).
We have limits for max fees

)

var _ bindings.Invoker = (*InvokerAdapter)(nil)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

sorry what is InvokerAdapter ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

InvokerAdapter implements bindings.Invoker by sending writes through StellarTxm (EnqueueAndWait → full simulate/sign/send/confirm path) and simulations through Simulate; GetEvents goes straight to RPC (no sequence).

// InvokerAdapter bridges generated bindings clients to the TXM. State-changing
// calls go through EnqueueAndWait; read-only simulations go through Simulate;
// event reads delegate directly to the shared RPC client.
type InvokerAdapter struct {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Does each binding use the InvokerAdapter class ? Is this a cll concept ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

No. Each generated client takes a bindings.Invoker. InvokerAdapter is one implementation you can pass in when you want TXM-backed invocations. Elsewhere we use other Invokers (e.g. deployment.Deployer as the shared invoker in ccv/chain devenv wiring). invoker_adapter_test.go has tests that might be helpful. This is optional code for later

Comment thread relayer/txm/txm.go
Comment thread relayer/txm/txm.go Outdated
Comment thread relayer/txm/restore.go Outdated
},
}

sourceAccount := txnbuild.NewSimpleAccount(tx.FromAddress, seq-1)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

can explain why do -1 here ?
i see that we send in GetNextSequence().
then we do -1 here and then we do IncrementSequenceNum=true.
is this intentional ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Intentional - GetNextSequence() returns the sequence the restore tx will consume on-chain; txnbuild wants last-used seq in SimpleAccount, so we pass seq-1 and set IncrementSequenceNum: true to get seq on the wire (same as buildPreliminaryTx). After restore we resync and call GetNextSequence() again for the user invoke. Documented in restore.go.

Comment thread relayer/txm/txm.go
Comment thread relayer/txm/txm.go
Comment thread relayer/txm/config.go Outdated
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 2, 2026

Code coverage report:

Top package main feat/stellar-txm-lifecycle diff
github.com/smartcontractkit/chainlink-stellar/ccv 29.13% 29.13% +0.00%
github.com/smartcontractkit/chainlink-stellar/cmd 0.00% 0.00% +0.00%
github.com/smartcontractkit/chainlink-stellar/deployment 45.80% 45.80% +0.00%
github.com/smartcontractkit/chainlink-stellar/relayer 3.59% 70.50% +66.91%
github.com/smartcontractkit/chainlink-stellar/tests 0.00% 0.00% +0.00%

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants