amashukov/blockchain-context-bundle
## Getting Started
### Minimal Setup
1. **Install the Bundle**
```bash
composer require amashukov/blockchain-context-bundle
Symfony Flex auto-registers the bundle in config/bundles.php.
Configure Environment Variables
Add blockchain-related env vars to .env (e.g., ETH_RPC_URL, TONCENTER_API_KEY).
Example:
ETH_RPC_URL=https://mainnet.infura.io/v3/YOUR_KEY
TONCENTER_API_KEY=your_toncenter_key
DEPOSIT_WALLET_ENCRYPTION_KEY=$(openssl rand -hex 32) # Base64-encoded 32-byte key
Basic Configuration
Define chain-specific settings in config/packages/blockchain_context.yaml:
blockchain_context:
eth:
enabled: true
rpc_url: '%env(ETH_RPC_URL)%'
chain_id: '%env(int:ETH_CHAIN_ID)%'
ton:
enabled: true
toncenter_api_key: '%env(TONCENTER_API_KEY)%'
wallet_mnemonic: '%env(TON_WALLET_MNEMONIC)%'
deposit_wallet_encryption_key: '%env(DEPOSIT_WALLET_ENCRYPTION_KEY)%'
First Use Case: Verify a Signature
Inject SignatureVerifier and verify EIP-191 or TON Connect signatures:
use Amashukov\BlockchainContextBundle\Service\SignatureVerifier;
class DepositValidator {
public function __construct(
private SignatureVerifier $verifier
) {}
public function validateSignature(string $message, string $signature, string $address): bool {
return $this->verifier->verifyEip191($message, $signature, $address);
// OR for TON Connect:
// return $this->verifier->verifyTonConnect($message, $signature, $address);
}
}
Autowire typed clients for EVM (JsonRpcProviderInterface) or TON (ToncenterClientInterface):
use Amashukov\EthRpc\JsonRpcProviderInterface;
use Amashukov\Toncenter\ToncenterClientInterface;
class CryptoService {
public function __construct(
private JsonRpcProviderInterface $ethRpc,
private ToncenterClientInterface $toncenter
) {}
public function getEthBalance(string $address): string {
return $this->ethRpc->getBalance($address);
}
public function getTonWalletInfo(string $walletAddress): array {
return $this->toncenter->getWalletInfo($walletAddress);
}
}
Use the tagged-iterator chain (ChainDepositCheckChain) to aggregate deposit checks across chains:
use Amashukov\BlockchainContextBundle\Service\Detection\ChainDepositCheckChain;
class DepositDetector {
public function __construct(
private ChainDepositCheckChain $depositChecker
) {}
public function checkDeposits(): array {
$results = [];
foreach ($this->depositChecker as $checker) {
$results[$checker->getChain()] = $checker->check();
}
return $results;
}
}
Add a Custom Deposit Checker:
// src/Service/CustomEthDepositChecker.php
use Amashukov\BlockchainContextBundle\Service\Detection\DepositCheckerInterface;
class CustomEthDepositChecker implements DepositCheckerInterface {
public function getChain(): string { return 'eth'; }
public function check(): array { /* ... */ }
}
Register it as a service with the tag:
services:
App\Service\CustomEthDepositChecker:
tags: [blockchain_context.deposit_checker]
Use DepositTxBuilderChain to build chain-specific transactions:
use Amashukov\BlockchainContextBundle\Service\TxBuilder\DepositTxBuilderChain;
class TransactionBuilder {
public function __construct(
private DepositTxBuilderChain $txBuilders
) {}
public function buildTx(string $chain, array $params): string {
foreach ($this->txBuilders as $builder) {
if ($builder->supportsChain($chain)) {
return $builder->build($params);
}
}
throw new \RuntimeException("Unsupported chain: $chain");
}
}
Extend for a New Chain:
// src/Service/CustomChainTxBuilder.php
use Amashukov\BlockchainContextBundle\Service\TxBuilder\DepositTxBuilderInterface;
class CustomChainTxBuilder implements DepositTxBuilderInterface {
public function supportsChain(string $chain): bool { return $chain === 'custom'; }
public function build(array $params): string { /* ... */ }
}
Tag the service:
services:
App\Service\CustomChainTxBuilder:
tags: [blockchain_context.tx_builder]
Verify transaction finality using ConfirmationCheckChain:
use Amashukov\BlockchainContextBundle\Service\Finality\ConfirmationCheckChain;
class FinalityService {
public function __construct(
private ConfirmationCheckChain $confirmationChain
) {}
public function isConfirmed(string $txHash, string $chain): bool {
foreach ($this->confirmationChain as $checker) {
if ($checker->supportsChain($chain)) {
return $checker->isConfirmed($txHash);
}
}
return false;
}
}
Encrypt/decrypt private keys with PrivKeyEncrypter:
use Amashukov\BlockchainContextBundle\Service\PrivKeyEncrypter;
class KeyVault {
public function __construct(
private PrivKeyEncrypter $encrypter
) {}
public function encrypt(string $privateKey): string {
return $this->encrypter->encrypt($privateKey);
}
public function decrypt(string $encryptedKey): string {
return $this->encrypter->decrypt($encryptedKey);
}
}
Fetch gas prices dynamically:
use Amashukov\BlockchainContextBundle\Service\Gas\EthGasFetcher;
use Amashukov\BlockchainContextBundle\Service\Gas\TonGasFetcher;
class GasService {
public function __construct(
private EthGasFetcher $ethGasFetcher,
private TonGasFetcher $tonGasFetcher
) {}
public function getEthGas(): array {
return $this->ethGasFetcher->fetch();
}
public function getTonGas(): int {
return $this->tonGasFetcher->fetch();
}
}
%blockchain_context.*% parameters internally. Ensure your .env or parameters.yaml maps these to actual env vars:
parameters:
blockchain_context.eth.rpc_url: '%env(ETH_RPC_URL)%'
enabled: false for unused chains to avoid errors:
blockchain_context:
ton:
enabled: false # Disables TON-related services
explorer) use sensible defaults (e.g., Etherscan for ETH, Tonscan for TON).verifyEip191() for Ethereum-style signatures (e.g., from MetaMask).verifyTonConnect() for TON Connect signatures (Ed25519).keccak256("\x19Ethereum Signed Message:\n" . strlen($message) . $message) before verification.ToncenterClient includes built-in retries for HTTP 429 (rate-limited), 5xx, and 542 (web socket errors). Customize retry logic by overriding the HttpClient service:
services:
Amashukov\Toncenter\ToncenterClient:
arguments:
$httpClient: '@custom.http_client' # Your PSR-18 client with middleware
blockchain_context.deposit_checker). Custom tags won’t be auto-collected.How can I help you explore Laravel packages today?