Relay Signed Transactions
The Tachyon SDK provides a specialized method for submitting pre-signed transactions with automatic funding. This is useful when you need to execute transactions from a specific address while having Tachyon handle the gas payments and ensure the account has sufficient balance.
Overview
The relaySignedTx() method allows you to:
- Submit pre-signed transactions for execution
- Automatically fund the sender address with the minimum required balance
- Track transaction status using the same methods as regular relay transactions
- Maintain control over transaction signing while outsourcing gas payment
Use Cases:
- Executing transactions from deterministic addresses
- Managing multiple accounts with centralized funding
- Implementing account abstraction patterns
- Batch operations requiring specific signer addresses
Method Reference
relaySignedTx(params)
Submits a pre-signed transaction to the Tachyon relay network. Tachyon will ensure the sender address is funded with at least minBalanceRequired before broadcasting the signed transaction.
Parameters:
The SignedTransactionParams object defines the parameters required when calling the relaySignedTx() method.
| Name | Type | Required | Description |
|---|---|---|---|
chainId | number | Yes | The blockchain network ID where the transaction will be executed. Must be a supported chain. |
fromAddress | string | Yes | The address that signed the transaction. This address will be funded if needed. Must be a valid address for the specified chain. |
signedTx | string | Yes | The complete signed transaction data in hexadecimal format. This should be the raw signed transaction ready for broadcast. |
minBalanceRequired | string | Yes | The minimum balance required in the sender’s account to execute the transaction (in smallest unit - wei for EVM chains). Typically calculated as gasLimit * maxFeePerGas. |
label | string | No | Optional human-readable label for easier transaction identification and tracking. |
Returns: Promise<string> — A unique transaction ID that can be used to track the transaction status and execution.
Throws:
- Error if required parameters are missing
- Error if the from address is invalid for the specified chain
- Error if the funding cost exceeds account limits
- Error if the account has insufficient balance
- Error if the chain is disabled for the account
Complete Examples
Basic EVM Transaction
import { Tachyon, ChainId } from '@rathfi/tachyon'
import { ethers } from 'ethers'
async function relaySignedTransaction() {
// Initialize Tachyon
const tachyon = new Tachyon({
apiKey: 'YOUR_API_KEY',
})
// Create wallet
const wallet = new ethers.Wallet('YOUR_PRIVATE_KEY')
// Prepare transaction
const tx = {
to: '0x3dbE34f2C21b3B2980d4dc53f3c7E51e39663F49',
value: ethers.parseEther('0.01'),
data: '0x',
chainId: 8453, // Base
nonce: 0,
gasLimit: 21000,
maxFeePerGas: ethers.parseUnits('2', 'gwei'),
maxPriorityFeePerGas: ethers.parseUnits('1', 'gwei'),
}
// Sign transaction
const signedTx = await wallet.signTransaction(tx)
// Calculate minimum balance (gas cost)
const minBalance = (
BigInt(tx.gasLimit) * BigInt(tx.maxFeePerGas)
).toString()
// Submit to Tachyon
const txId = await tachyon.relaySignedTx({
chainId: tx.chainId,
fromAddress: wallet.address,
signedTx: signedTx,
minBalanceRequired: minBalance,
label: 'Transfer 0.01 ETH',
})
console.log('Transaction ID:', txId)
// Wait for execution
const result = await tachyon.waitForExecutionHash(txId, 60000)
console.log('Transaction executed:', result.executionTxHash)
return result
}
relaySignedTransaction()Smart Contract Interaction
import { Tachyon } from '@rathfi/tachyon'
import { ethers } from 'ethers'
async function callContract() {
const tachyon = new Tachyon({
apiKey: 'YOUR_API_KEY',
})
const wallet = new ethers.Wallet('YOUR_PRIVATE_KEY')
// Encode contract call
const contractAddress = '0x...'
const abi = ['function transfer(address to, uint256 amount)']
const iface = new ethers.Interface(abi)
const callData = iface.encodeFunctionData('transfer', [
'0x3dbE34f2C21b3B2980d4dc53f3c7E51e39663F49',
ethers.parseEther('100'),
])
// Prepare and sign transaction
const tx = {
to: contractAddress,
value: 0,
data: callData,
chainId: 8453,
nonce: 0,
gasLimit: 100000,
maxFeePerGas: ethers.parseUnits('2', 'gwei'),
maxPriorityFeePerGas: ethers.parseUnits('1', 'gwei'),
}
const signedTx = await wallet.signTransaction(tx)
const minBalance = (
BigInt(tx.gasLimit) * BigInt(tx.maxFeePerGas)
).toString()
// Submit signed transaction
const txId = await tachyon.relaySignedTx({
chainId: tx.chainId,
fromAddress: wallet.address,
signedTx: signedTx,
minBalanceRequired: minBalance,
label: 'Token Transfer',
})
return txId
}With Automatic Nonce Management
import { Tachyon } from '@rathfi/tachyon'
import { ethers } from 'ethers'
async function relayWithAutoNonce(provider) {
const tachyon = new Tachyon({
apiKey: 'YOUR_API_KEY',
})
const wallet = new ethers.Wallet('YOUR_PRIVATE_KEY', provider)
// Get current nonce from provider
const nonce = await provider.getTransactionCount(wallet.address)
// Get current gas prices
const feeData = await provider.getFeeData()
const tx = {
to: '0x3dbE34f2C21b3B2980d4dc53f3c7E51e39663F49',
value: ethers.parseEther('0.001'),
data: '0x',
chainId: 8453,
nonce: nonce,
gasLimit: 21000,
maxFeePerGas: feeData.maxFeePerGas,
maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
}
const signedTx = await wallet.signTransaction(tx)
const minBalance = (
BigInt(tx.gasLimit) * BigInt(tx.maxFeePerGas)
).toString()
const txId = await tachyon.relaySignedTx({
chainId: tx.chainId,
fromAddress: wallet.address,
signedTx: signedTx,
minBalanceRequired: minBalance,
})
return txId
}Batch Processing Multiple Signed Transactions
import { Tachyon } from '@rathfi/tachyon'
import { ethers } from 'ethers'
async function batchRelaySignedTransactions() {
const tachyon = new Tachyon({
apiKey: 'YOUR_API_KEY',
})
const wallet = new ethers.Wallet('YOUR_PRIVATE_KEY')
const recipients = [
'0x3dbE34f2C21b3B2980d4dc53f3c7E51e39663F49',
'0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb',
'0x8888888888888888888888888888888888888888',
]
const txIds = []
for (let i = 0; i < recipients.length; i++) {
const tx = {
to: recipients[i],
value: ethers.parseEther('0.001'),
data: '0x',
chainId: 8453,
nonce: i, // Sequential nonces
gasLimit: 21000,
maxFeePerGas: ethers.parseUnits('2', 'gwei'),
maxPriorityFeePerGas: ethers.parseUnits('1', 'gwei'),
}
const signedTx = await wallet.signTransaction(tx)
const minBalance = (
BigInt(tx.gasLimit) * BigInt(tx.maxFeePerGas)
).toString()
const txId = await tachyon.relaySignedTx({
chainId: tx.chainId,
fromAddress: wallet.address,
signedTx: signedTx,
minBalanceRequired: minBalance,
label: `Batch transfer ${i + 1}/${recipients.length}`,
})
txIds.push(txId)
console.log(`Submitted transaction ${i + 1}:`, txId)
}
// Wait for all transactions to execute
const results = await Promise.all(
txIds.map(txId => tachyon.waitForExecutionHash(txId))
)
return results
}How It Works
- Transaction Signing: You sign the transaction with your private key using your preferred wallet/signer
- Funding Check: Tachyon checks if the sender address has sufficient balance
- Automatic Funding: If needed, Tachyon funds the address with the
minBalanceRequiredamount - Transaction Broadcast: Once funded, Tachyon broadcasts your pre-signed transaction
- Execution: The transaction executes on-chain from your specified address
Cost Calculation
The cost for a signed transaction relay includes:
- Funding Cost: The
minBalanceRequiredamount needed to execute your transaction - Service Fee: A 8% service fee applied to the funding cost
Example:
// If minBalanceRequired = 0.001 ETH (in wei)
// Funding cost = 0.001 ETH
// Total cost = 0.001 ETH * 1.08 = 0.00108 ETHThe funding cost is deducted from your Tachyon account balance, not from the sender address.
Important Notes
- The
fromAddressmust be a valid address for the specified chain - The
signedTxmust be properly signed and ready for broadcast minBalanceRequiredshould cover the maximum possible gas cost (gasLimit × maxFeePerGas)- Tachyon will fund the address before broadcasting, so ensure your account has sufficient balance
- The transaction type is automatically set to
FUNDING_SIGNED - Once submitted, you can track the transaction using the same status methods as regular relay transactions
Error Handling
try {
const txId = await tachyon.relaySignedTx({
chainId: 8453,
fromAddress: wallet.address,
signedTx: signedTx,
minBalanceRequired: minBalance,
})
console.log('Success:', txId)
} catch (error) {
if (error.message.includes('Invalid from address')) {
console.error('Address validation failed')
} else if (error.message.includes('Insufficient balance')) {
console.error('Not enough balance in Tachyon account')
} else if (error.message.includes('Cost exceeded')) {
console.error('Transaction cost exceeds limits')
} else {
console.error('Submission failed:', error.message)
}
}