Skip to main content

Send Universal Transaction

Overview

Universal transactions let you send native transactions from any Layer 1 chain—EVM or non-EVM, even Push Chain itself—without wrapping, bridging or extra tooling required.

Under the hood, the SDK automatically estimates gas, orchestrates signatures, and replays any EVM or non-EVM proofs, so you can focus on your app—not the network plumbing.

Sending Universal Transaction

pushChainClient.universal.sendTransaction({tx}): Promise<TransactionReceipt>

const txHash = await pushChainClient.universal.sendTransaction({
to: '0xa54E96d3fB93BD9f6cCEf87c2170aEdB1D47E1cF',
value: PushChain.utils.helpers.parseUnits('0.1', 18), // 0.1 PC in uPC
// value: BigInt('100000000000000000') is equivalent here
});

TheseArgumentsare mandatory

ArgumentsTypeDescription
tx.tostringThe address of the recipient.
tx.valueBigIntAmount of PC to send (in uPC, the smallest unit, like wei in ETH).
tx.datastringThe data to send.
tx.gasLimitBigIntThe gas limit for the transaction.
tx.maxFeePerGasBigIntThe maximum fee per gas for the transaction.
tx.maxPriorityFeePerGasBigIntThe maximum priority fee per gas for the transaction.
tx.funds{ amount: BigInt; token?: MoveableToken }Moves supported assets from the origin chain to Push Chain within the same call. If tx.data is provided, assets are moved and then the contract call is executed atomically.
Advanced Arguments
ArgumentsTypeDefaultDescription
tx.deadlineBigInt-The deadline for the transaction.
tx.progressHook(progress: ProgressHookType) => void-A callback function to receive progress updates during transaction lifecycle, especially useful for tracking cross-chain transactions.
ProgressHook Type and Response
FieldTypeDescription
progressObjectThe progress of the transaction.
progress.idstringUnique identifier for the progress event.
progress.titlestringBrief title of the progress event.
progress.messagestringDetailed message describing the event.
progress.levelINFO | SUCCESS | WARNING | ERRORSeverity level of the event.
progress.timestampstringISO-8601 timestamp when the event occurred (e.g. 2025-06-26T15:04:05.000Z).
IDTitleMessageLevel
SEND-TX-01Origin Chain DetectedOrigin chain: solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1INFO
SEND-TX-02-01Estimating GasEstimating and fetching gas limit, gas price for TX…INFO
SEND-TX-02-02Gas EstimatedTotal execution cost (Gas cost + value): 1011250000000000000 UPCSUCCESS
SEND-TX-03-01Resolving UEAResolving Execution Account (UEA) – computing address, checking deployment status and balanceINFO
SEND-TX-03-02UEA ResolvedUEA: 0x4f17B798A7d643d4F89cb2d8D42A72F84e83e566, Deployed: trueSUCCESS
SEND-TX-04-01Awaiting Signature for Tx ExecutionUniversal Payload Hash: 0x1a579f18…fabac4309INFO
SEND-TX-04-02Generated Universal PayloadSignature CompletedSUCCESS
SEND-TX-05-01Locking Origin Chain FeeLocking fee: 1000063864000000000 UPC on origin chainINFO
SEND-TX-05-02Awaiting Origin Chain ConfirmationsTx sent: 0xabc..234, waiting for 2 confirmations.INFO
SEND-TX-05-03Confirmations ReceivedRequired confirmations received.SUCCESS
SEND-TX-06Broadcasting to Push ChainSending Tx to Push Chain…INFO
SEND-TX-99-01Push Chain TX SuccessSUCCESS
SEND-TX-99-02Push Chain TX FailedERROR
Returns `TxResponse` <object>
{
hash: '0xe2302bd21ab0902f37cb605d491ce5f95ee35ce4083405dddf3657d782acae35',
origin: 'eip155:42101:0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9',
blockNumber: 0n,
blockHash: '',
transactionIndex: 0,
chainId: '42101',
from: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9',
to: '0x35B84d6848D16415177c64D64504663b998A6ab4',
nonce: 341,
data: '0x',
value: 1000n,
gasLimit: 21000n,
gasPrice: 1325000000n,
maxFeePerGas: 1325000000n,
maxPriorityFeePerGas: 125000000n,
accessList: [],
wait: [Function: wait],
type: '2',
typeVerbose: 'eip1559',
signature: {
r: '0x556566ba1304bf8e93025fc82daff32eb24b7ee9804a76d0baa0098dfa7237de',
s: '0x4495d7811d3dcb1beac16f29261903b542b0b65f51aa5942f65dbaf67e735724',
v: 1,
yParity: 1
},
raw: {
from: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9',
to: '0x35B84d6848D16415177c64D64504663b998A6ab4',
nonce: 341,
data: '0x',
value: 1000n
}
}
PropertyTypeDescription
hashstringUnique transaction hash identifier
originstringOrigin identifier in format "eip155:chainId:address" or "solana:chainId:address"
blockNumberBigIntBlock number where transaction was included
blockHashstringHash of the block containing this transaction
transactionIndexnumberPosition/index of transaction within the block
chainIdstringChain identifier (e.g. Push Chain = 42101)
fromstringUEA (Universal Execution Address) that executed the transaction
tostringTarget address the UEA executed against
noncenumberDerived nonce for the UEA
datastringPerceived calldata (transaction input data)
valueBigIntAmount of native tokens transferred (in wei)
gasLimitBigIntMaximum gas units allocated for transaction
gasPriceBigIntGas price for legacy transactions (in wei)
maxFeePerGasBigIntMaximum fee per gas for EIP-1559 transactions
maxPriorityFeePerGasBigIntMaximum priority fee (tip) per gas for EIP-1559
accessListarrayEIP-2930 access list for optimized storage access
typestringTransaction type identifier
typeVerbosestringHuman-readable transaction type
signatureobjectECDSA signature components
signature.rstringR component of ECDSA signature
signature.sstringS component of ECDSA signature
signature.vnumberRecovery ID (legacy format)
signature.yParitynumberY-parity for EIP-1559 (0 or 1)
rawobjectOriginal on-chain transaction data
raw.fromstringActual from address that went on chain
raw.tostringActual to address that went on chain
raw.noncenumberActual raw nonce used on chain
raw.datastringActual raw data that went on chain
raw.valueBigIntActual derived value that went on chain
waitfunctionAsync function that returns a Promise resolving to UniversalTxReceipt
Getting `txReceipt` <object> from `txResponse` <object>

Calling the wait() function from txResponse object will give you a Promise<UniversalTxReceipt> once the transaction is confirmed on-chain.


const txReceipt = await txResponse.wait(1); // number of blocks confirmations to wait for
{
hash: '0xb52706db4116dd6bbea87be5142ac2c69b17fe8ccf8e2b88ac176adb30b90dd6',
blockNumber: 3413247n,
blockHash: '0x5a7b6e2716f7d4450b6ca08aebfe74cea3d876367a8afe6f603196ba8c346a2d',
transactionIndex: 0,
from: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9',
to: '0x35B84d6848D16415177c64D64504663b998A6ab4',
contractAddress: null,
gasPrice: 1325000000n,
gasUsed: 21000n,
cumulativeGasUsed: 21000n,
logs: [],
logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
status: 1,
raw: {
from: '0xFd6C2fE69bE13d8bE379CCB6c9306e74193EC1A9',
to: '0x35B84d6848D16415177c64D64504663b998A6ab4',
nonce: 342,
data: '0x',
value: 1000n
}
}
PropertyTypeDescription
hashstringTransaction hash (same as in transaction response)
blockNumberBigIntBlock number where transaction was confirmed
blockHashstringHash of the block containing the transaction
transactionIndexnumberPosition/index of transaction within the block
fromstringExecutor account address (UEA on Push Chain)
tostringActual intended target address of the transaction
contractAddressstring | nullAddress of deployed contract (null for regular transfers)
gasPriceBigIntGas price used for the transaction (in wei)
gasUsedBigIntActual gas consumed by the transaction
cumulativeGasUsedBigIntTotal gas used by all transactions in the block up to this one
logsarrayArray of log objects emitted by the transaction
logsBloomstringBloom filter for efficient log searching
statusnumberTransaction status (1 = success, 0 = failure)
rawobjectRaw on-chain transaction data
raw.fromstringActual from address that executed on chain
raw.tostringActual to address that was called on chain
raw.noncenumberActual nonce used on chain
raw.datastringActual calldata sent on chain
raw.valueBigIntActual value transferred on chain

Send Transaction with Contract Interaction

When calling a smart contract method via sendTransaction, supply the ABI-encoded function call as a hex string in the data field. You can choose ethers or viem or any of your favorite libraries to encode the function data. Or, use our utility function PushChain.utils.helpers.encodeTxData to encode the function data.

// Define the ABI for the ERC20 transfer function
const erc20Abi = [
'function transfer(address to, uint256 amount) returns (bool)',
];

// Generate the encoded function data using viem
const data = PushChain.utils.helpers.encodeTxData({
abi: erc20Abi,
functionName: 'transfer',
// Transfer 10 tokens, converted to 18 decimal places
args: ['0xRecipientAddress', PushChain.utils.helpers.parseUnits('10', 18)],
});

// Send the transaction using Push Chain SDK
const txHash = await pushChainClient.universal.sendTransaction({
to: '0xTokenContractAddress', // The smart contract address on Push Chain
value: BigInt('0'), // No $PC being sent, just contract interaction
data: data, // The encoded function call
});

Send Transaction with Funds

You can move supported assets (e.g., USDT, USDC, or other tokens) from your origin chain to Push Chain and execute your call in a single transaction.

Use the funds field to specify the amount of assets to move, and optionally the data field to specify the function call to execute on Push Chain.

Note: funds transactions are only supported from external origin chains.
Native Push Chain users should call ERC-20 transfer or transferFrom directly (instead of using funds).

// Send 1 USDT to the recipient address
const txHash = await pushChainClient.universal.sendTransaction({
to: '0xRecipientAddress', // The recipient address on Push Chain
data: data, // pass this if you want to execute a function on Push Chain as well
funds: {
amount: PushChain.utils.helpers.parseUnits('1', 6), // 1 USDT
token: client.moveable.token.USDT, // MoveableToken accessor from client
},
});

Send Batch Transactions (Multicall)

You can batch multiple calls into a single transaction on Push Chain. This pattern is commonly referred to as Multicall in EVM ecosystems.

To do so, instead of passing a single data field, supply an array of calls (each with to, value, and data) to sendTransaction.

Note: Batch transactions are only supported from external origin chains.
Native Push Chain users cannot use batch mode.

// Execute two increment() calls atomically
const incrementData = PushChain.utils.helpers.encodeTxData({
abi: CounterABI,
functionName: "increment",
});

await client.universal.sendTransaction({
// Must be the Universal Execution Account (UEA) for this signer
to: client.universal.account,
data: [
{ to: "0xCounterContract", value: 0n, data: incrementData },
{ to: "0xCounterContract", value: 0n, data: incrementData },
],
});
Multicall requirements

For multicall, the to field must always be set to the Universal Execution Account (UEA) of the signer. You can access it with client.universal.account. The SDK will throw an error if you pass any other address.

Live Playground

VIRTUAL NODE IDE
Live Playground: Interact with Smart Contract

VIRTUAL NODE IDE
Live Playground: Move Funds to Push Chain
VIRTUAL NODE IDE
Live Playground: Do Batch Transactions in a Single Universal Transaction
VIRTUAL NODE IDE
Live Playground: (Advanced) Track the progress lifecycle of a transaction
VIRTUAL NODE IDE

Next Steps

  • Sign arbitrary data with Sign Universal Message
  • Surface live feedback in your UI by handling the progressHook events
  • Leverage pre-built utilities in Contract Helpers
  • Integrate transaction flows into your frontend app using the UI Kit