web3p/ethereum-tx
Sign and serialize Ethereum transactions in PHP. web3p/ethereum-tx builds raw TX payloads for legacy and EIP-155 transactions, handling nonce, gas, to/value/data, and chain IDs—ideal for creating offline-signed transactions and broadcasting via any JSON-RPC provider.
## Getting Started
### Minimal Setup
1. **Installation**
```bash
composer require web3p/ethereum-tx:^0.4.3
Add to composer.json if using a monorepo or custom package manager.
First Transaction (Legacy)
use Web3p\EthereumTx\Transaction;
$tx = new Transaction();
$tx->setFrom('0x123...')
->setTo('0x456...')
->setValue(1000000000000000000) // 1 ETH in wei
->setGasPrice(20000000000) // 20 Gwei
->setGas(21000)
->setData('0x...');
$signedTx = $tx->sign('private_key_here');
$rawTx = $signedTx->getRaw();
First Transaction (EIP-1559)
$tx = new Transaction();
$tx->setFrom('0x123...')
->setTo('0x456...')
->setValue(1000000000000000000)
->setMaxFeePerGas(30000000000) // 30 Gwei max
->setMaxPriorityFeePerGas(2000000000) // 2 Gwei tip
->setGas(21000)
->setData('0x...')
->setChainId(1); // Required for EIP-1559/EIP-2930
First Transaction (EIP-2930 - Access List)
$tx = new Transaction();
$tx->setFrom('0x123...')
->setTo('0x456...')
->setValue(1000000000000000000)
->setGasPrice(20000000000) // Legacy gas price (EIP-2930 supports both)
->setGas(21000)
->setData('0x...')
->setChainId(1)
->setAccessList([ // EIP-2930 feature
['address' => '0xContractAddress', 'storageKeys' => ['0x00...', '0x01...']]
]);
Sending via Provider
Use with web3p/ethereum-rpc or ethereumjs:
$client = new \Web3p\EthereumRpc\Client('https://mainnet.infura.io/v3/...');
$client->sendRawTransaction($rawTx);
src/Transaction.php – Core transaction builder (now supports EIP-1559, EIP-2930, and legacy types with fixed RLP encoding).src/Signer.php – Updated signing logic for all transaction types.tests/Eip1559Test.php – Test cases for EIP-1559 transactions.tests/Eip2930Test.php – Test cases for EIP-2930 (access list) transactions.src/Exceptions/ – New exceptions for invalid transaction configurations (e.g., missing chainId for EIP-1559).src/Utils/Rlp.php – Updated RLP library for accurate transaction encoding.Batch Transactions (Legacy)
$txs = [];
foreach ($addresses as $to) {
$tx = (new Transaction())
->setFrom($from)
->setTo($to)
->setValue($amount)
->setGasPrice($gasPrice)
->setGas(21000);
$txs[] = $tx->sign($privateKey)->getRaw();
}
Batch Transactions (EIP-1559)
$txs = [];
foreach ($addresses as $to) {
$tx = (new Transaction())
->setFrom($from)
->setTo($to)
->setValue($amount)
->setMaxFeePerGas($maxFee)
->setMaxPriorityFeePerGas($priorityFee)
->setGas(21000)
->setChainId(1);
$txs[] = $tx->sign($privateKey)->getRaw();
}
Batch Transactions (EIP-2930)
$txs = [];
foreach ($addresses as $to) {
$tx = (new Transaction())
->setFrom($from)
->setTo($to)
->setValue($amount)
->setGasPrice($gasPrice) // Legacy gas price (optional for EIP-2930)
->setGas(21000)
->setChainId(1)
->setAccessList([ // EIP-2930 access list
['address' => '0xContractAddress', 'storageKeys' => ['0x00...']]
]);
$txs[] = $tx->sign($privateKey)->getRaw();
}
Gas Estimation (EIP-1559)
$client = new \Web3p\EthereumRpc\Client('...');
$gasLimit = $client->estimateGas([
'from' => $from,
'to' => $to,
'value' => $value,
'data' => $data,
]);
$tx->setGas($gasLimit);
// Fetch dynamic fees for EIP-1559
$fees = $client->getFeeHistory();
$tx->setMaxFeePerGas($fees['recommendedMaxFeePerGas'])
->setMaxPriorityFeePerGas($fees['recommendedMaxPriorityFeePerGas']);
Contract Interactions (EIP-2930)
$abi = '...'; // ABI string
$contract = new \Web3p\EthereumTx\Contract($abi, '0xContractAddress');
$tx = $contract->call('transfer', [$to, $amount], $from, $privateKey, [
'chainId' => 1,
'accessList' => [['address' => '0xContractAddress', 'storageKeys' => ['0x00...']]],
'gasPrice' => 20000000000, // Optional: Legacy gas price fallback
]);
Nonce Management
$nonce = $client->getTransactionCount($from, 'pending');
$tx->setNonce($nonce);
Laravel Service Provider Bind the package to the container for dependency injection:
$this->app->singleton(Transaction::class, function ($app) {
return new Transaction();
});
Environment Config
Store RPC endpoints, private keys, and chain IDs in .env:
ETH_RPC_URL=https://mainnet.infura.io/v3/...
ETH_PRIVATE_KEY=your_private_key_here
ETH_CHAIN_ID=1
Logging Use Laravel’s logging to track transaction hashes and types:
\Log::info('Sent TX', [
'hash' => $txHash,
'type' => $tx->getType(), // 0 (legacy), 1 (EIP-1559), 2 (EIP-2930)
]);
Transaction Type Detection Automatically detect transaction type based on method calls:
if ($tx->hasMaxFeePerGas()) {
// EIP-1559 transaction
} elseif ($tx->hasAccessList()) {
// EIP-2930 transaction
} else {
// Legacy transaction
}
RLP Encoding Validation Verify RLP-encoded transactions with:
$rlpEncoded = $tx->getRaw();
$decoded = \Web3p\EthereumTx\Utils\Rlp::decode($rlpEncoded);
Private Key Security
Gas Limits & Fees
estimateGas.How can I help you explore Laravel packages today?