Send Multichain Transactions
Overview
Multichain transactions let you compose multiple universal transactions into a single ordered flow across different routes.
This allows you to submit a single user-signed transaction to Push Chain that coordinates execution across Push Chain, external chains, or both.
Prerequisite: Familiarize yourself with Send Universal Transaction before reading this page.
Mental Model
- Prepare each transaction step with
prepareTransaction - Execute all steps together with
executeTransactions
Prepare Transaction
pushChainClient.universal.prepareTransaction({tx}): Promise<PreparedUniversalTx>
Prepares a transaction without executing it. Returns a PreparedUniversalTx object that you pass to executeTransactions.
const preparedTx = await pushChainClient.universal.prepareTransaction({
to: '0xContractAddress',
value: BigInt(0),
data: PushChain.utils.helpers.encodeTxData({
abi: MyABI,
functionName: 'myFunction',
args: [arg1, arg2],
}),
});
PreparedUniversalTx is an intermediate object that you pass to executeTransactions. Most apps do not need to manually inspect or modify its fields.
TheseArgumentsare mandatory
| Arguments | Type | Description |
|---|---|---|
tx.to | string | { address: string; chain: CHAIN } | Target address on Push Chain (plain string), or { address, chain } for an external chain via CEA. PushChain.CONSTANTS.CHAINPushChain.CONSTANTS.CHAIN.PUSH_TESTNETPushChain.CONSTANTS.CHAIN.PUSH_TESTNET_DONUTPushChain.CONSTANTS.CHAIN.ETHEREUM_SEPOLIAPushChain.CONSTANTS.CHAIN.BNB_TESTNETPushChain.CONSTANTS.CHAIN.BASE_SEPOLIAPushChain.CONSTANTS.CHAIN.ARBITRUM_SEPOLIAPushChain.CONSTANTS.CHAIN.SOLANA_DEVNET |
tx.from | { chain: CHAIN } | Optional. When set, originates from the CEA on that chain. |
tx.value | BigInt | Native value to send in the smallest unit of the execution context. |
tx.data | string | Array<{ to: string; value: bigint; data: string }> | ABI-encoded calldata, or an array of calls for multicall mode. |
tx.funds | { amount: bigint; token?: MoveableToken } | Move tokens from origin chain atomically with the call. Use PushChain.CONSTANTS.MOVEABLE.TOKEN.<CHAIN>.<TOKEN>. |
prepareTransactionaccepts the same transaction arguments as Send Universal Transaction.
Returns `PreparedUniversalTx` <object>
| Property | Type | Description |
|---|---|---|
route | 'UOA_TO_PUSH' | 'UOA_TO_CEA' | 'CEA_TO_PUSH' | 'CEA_TO_CEA' | Detected routing mode for this transaction. |
estimatedGas | bigint | Estimated gas units for execution. |
nonce | bigint | Nonce to use for submission. |
deadline | bigint | Signature expiry deadline. |
payload | string | Encoded payload ready for submission. |
gatewayRequest | object | Gateway request object (inbound or outbound). |
Live Playground: Inspect PreparedUniversalTx
Execute Transactions
pushChainClient.universal.executeTransactions(txs: PreparedUniversalTx[]): Promise<CascadedTxResponse>
Executes an ordered array of prepared transactions as a multichain flow. This is submitted and handled as a single transaction. You sign once, and the SDK coordinates execution across Push Chain and supported external chains automatically.
Each prepared transaction becomes one ordered step in the multichain flow.
const step1 = await pushChainClient.universal.prepareTransaction({...}); // Push Chain
const step2 = await pushChainClient.universal.prepareTransaction({...}); // BNB
const result = await pushChainClient.universal.executeTransactions([step1, step2]);
TheseArgumentsare mandatory
| Arguments | Type | Description |
|---|---|---|
txs | PreparedUniversalTx[] | Ordered array of prepared transactions from prepareTransaction. |
In the API response, each executed step is reported as a hop.
Returns `CascadedTxResponse` <object>
| Property | Type | Description |
|---|---|---|
initialTxHash | string | Hash of the user-signed Push Chain transaction that kicked off the cascade. |
initialTxResponse | UniversalTxResponse | Full response object for the initial Push Chain transaction. |
hops | CascadeHopInfo[] | Ordered list of all hops with routing and status information. |
hopCount | number | Total number of hops in the cascade. |
wait(opts?) | Promise<CascadeCompletionResult> | Alias for waitForAll. Waits for all hops to complete. |
waitForAll(opts?) | Promise<CascadeCompletionResult> | Waits for all hops to complete across all chains. |
CascadeHopInfo fields:
| Property | Type | Description |
|---|---|---|
hopIndex | number | Position in the cascade (0-indexed). |
route | string | Routing mode for this hop (UOA_TO_PUSH, UOA_TO_CEA, etc.). |
executionChain | CHAIN | Chain where this hop executes. |
status | 'pending' | 'submitted' | 'confirmed' | 'failed' | Current hop status. |
txHash | string | Resolved transaction hash once available. |
outboundDetails | object | External chain tx details for outbound hops, including hash, explorer URL, recipient, and amount. |
CascadeCompletionResult fields:
| Property | Type | Description |
|---|---|---|
success | boolean | Whether all hops completed successfully. |
hops | CascadeHopInfo[] | Final state of all hops. |
failedAt | number | Index of first failed hop, if any. |
waitForAll options:
| Option | Type | Default | Description |
|---|---|---|---|
pollingIntervalMs | number | 5000 | Polling interval in milliseconds. |
timeout | number | 600000 | Total timeout in milliseconds (10 min). |
progressHook | (event: CascadeProgressEvent) => void | - | Progress callback per hop. Reports hopIndex, route, chain, status, txHash, elapsed. |
Live Playground: Execute Multiple Transactions in One Flow
More Examples
Cross-Chain AMM Swap: ETH → pSOL via Push Chain AMM
Pull ETH from an Ethereum Sepolia CEA into Push Chain, swap pETH → pSOL on the Push Chain AMM (Uniswap V3 fork), then bridge the pSOL out to the user's Solana Devnet CEA. All three hops execute under a single user signature.
Live Playground: ETH → pSOL Swap → Solana
Fund BNB CEA then Increment Counter on BNB Testnet
Increment a counter on Push Chain, then use the CEA on BNB Testnet to increment a counter there as well. Both hops are composed into a single signature, and the playground reads the counter values before and after to confirm the changes.
Live Playground: Increment on Push Chain → BNB via CEA
Batch Contract Calls: Push Chain + BNB + Solana in One Signature
Increment counters on Push Chain and BNB Testnet, then trigger a call on Solana Devnet. Three independent contract interactions across three chains, all composed into a single user signature.
Live Playground: Batch Cross-Chain Contract Calls
Key Considerations
- Single signature:
executeTransactionssubmits one transaction to Push Chain. You sign once, and the SDK coordinates the full multichain execution automatically. - No atomicity guarantee: If a downstream hop fails, earlier hops are already on-chain. Design contracts to handle partial execution.
- Gas per hop: Each hop has its own estimated gas. Ensure gas is properly funded.
- Tracking: Use
cascade.wait({ progressHook })to receive live status updates per hop as they propagate across chains.
Next Steps
- Track Universal Transaction to monitor individual transaction confirmation status
- Contract Initiated Multichain Execution to trigger multichain flows from on-chain contracts
- Sign Universal Message to sign typed messages across chains with a universal signer
- Utility Functions for
encodeTxData,parseUnits, and other helpers used in this page