本文目录导读:

我将为您详细介绍PHP项目中如何集成Ethereum和ENS(以太坊域名服务)。
基础环境准备
安装依赖
composer require web3p/web3.php composer require kornrunner/keccak composer require phpseclib/phpseclib
Ethereum 基础交互
连接以太坊节点
<?php
require 'vendor/autoload.php';
use Web3\Web3;
use Web3\Providers\HttpProvider;
use Web3\RequestManagers\HttpRequestManager;
class EthereumClient
{
private $web3;
public function __construct($rpcUrl = 'https://mainnet.infura.io/v3/YOUR_PROJECT_ID')
{
$requestManager = new HttpRequestManager($rpcUrl);
$provider = new HttpProvider($requestManager);
$this->web3 = new Web3($provider);
}
// 获取账户余额
public function getBalance($address)
{
$balance = '0';
$this->web3->eth->getBalance($address, function($err, $result) use (&$balance) {
if ($err !== null) {
throw new Exception($err->getMessage());
}
$balance = $result->toString();
});
// 转换为ETH单位
$ethBalance = bcdiv($balance, '1000000000000000000', 18);
return $ethBalance;
}
// 获取最新区块号
public function getBlockNumber()
{
$blockNumber = '0';
$this->web3->eth->blockNumber(function($err, $result) use (&$blockNumber) {
if ($err !== null) {
throw new Exception($err->getMessage());
}
$blockNumber = $result->toString();
});
return $blockNumber;
}
}
发送交易
<?php
class TransactionManager
{
private $web3;
private $account;
public function __construct($privateKey, $rpcUrl)
{
// 初始化Web3连接
$requestManager = new HttpRequestManager($rpcUrl);
$provider = new HttpProvider($requestManager);
$this->web3 = new Web3($provider);
// 从私钥导入账户
$this->account = new \Web3\Account();
$this->account->privateKey = $privateKey;
}
public function sendETH($toAddress, $amountInETH)
{
$amountInWei = bcmul($amountInETH, '1000000000000000000', 0);
$transaction = [
'from' => $this->account->getAddress(),
'to' => $toAddress,
'value' => '0x' . dechex($amountInWei),
'gas' => '0x5208', // 21000 gas
'gasPrice' => '0x' . dechex($this->getGasPrice())
];
$txHash = '';
$this->web3->eth->sendTransaction($transaction, function($err, $result) use (&$txHash) {
if ($err !== null) {
throw new Exception($err->getMessage());
}
$txHash = $result;
});
return $txHash;
}
private function getGasPrice()
{
$gasPrice = '0';
$this->web3->eth->gasPrice(function($err, $result) use (&$gasPrice) {
if ($err !== null) {
throw new Exception($err->getMessage());
}
$gasPrice = $result->toString();
});
return $gasPrice;
}
}
ENS域名服务集成
ENS域名查询
<?php
use Web3\Web3;
use Web3\Contracts\Eth;
use Web3\Utils;
class ENSManager
{
private $web3;
private $ensContract;
// ENS 合约地址
const ENS_REGISTRY_ADDRESS = '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e';
const ENS_RESOLVER_ADDRESS = '0x4976fb03C32e5B8cfe2b6cCB31c09Ba78EBaBa41';
public function __construct($rpcUrl)
{
$requestManager = new HttpRequestManager($rpcUrl);
$provider = new HttpProvider($requestManager);
$this->web3 = new Web3($provider);
// 初始化ENS合约
$this->initENSContract();
}
private function initENSContract()
{
// ENS Registry ABI (简化版)
$ensAbi = json_decode('[
{
"constant": true,
"inputs": [{"name": "node", "type": "bytes32"}],
"name": "resolver",
"outputs": [{"name": "", "type": "address"}],
"type": "function"
}
]');
$this->ensContract = new Eth(
$this->web3->provider,
$ensAbi,
self::ENS_REGISTRY_ADDRESS
);
}
// 解析ENS域名
public function resolveName($domainName)
{
// 将域名转换为namehash
$nameHash = $this->namehash($domainName);
// 获取解析器地址
$resolverAddress = $this->getResolver($nameHash);
if ($resolverAddress === '0x0000000000000000000000000000000000000000') {
throw new Exception("No resolver found for domain");
}
// 获取解析的地址
return $this->getAddressFromResolver($resolverAddress, $nameHash);
}
// 反向解析:地址转ENS域名
public function reverseResolve($address)
{
// 构建反向查询的namehash
$reverseNode = $this->namehash(
strtolower(substr($address, 2)) . '.addr.reverse'
);
// 获取解析器
$resolverAddress = $this->getResolver($reverseNode);
if ($resolverAddress === '0x0000000000000000000000000000000000000000') {
return null;
}
// 获取ENS名称
return $this->getNameFromResolver($resolverAddress, $reverseNode);
}
// 计算namehash
private function namehash($name)
{
if (empty($name)) {
return '0x0000000000000000000000000000000000000000000000000000000000000000';
}
$labels = explode('.', $name);
$node = '0x0000000000000000000000000000000000000000000000000000000000000000';
foreach ($labels as $label) {
$labelHash = Utils::sha3($label);
$node = Utils::sha3($node . $labelHash);
}
return $node;
}
// 获取解析器
private function getResolver($nameHash)
{
$resolver = '0x0000000000000000000000000000000000000000';
$this->ensContract->call('resolver', $nameHash, function($err, $result) use (&$resolver) {
if ($err !== null) {
throw new Exception($err->getMessage());
}
$resolver = $result[0];
});
return $resolver;
}
// 从解析器获取地址
private function getAddressFromResolver($resolverAddress, $nameHash)
{
// 解析器ABI (简化版)
$resolverAbi = json_decode('[
{
"constant": true,
"inputs": [{"name": "node", "type": "bytes32"}],
"name": "addr",
"outputs": [{"name": "", "type": "address"}],
"type": "function"
}
]');
$resolver = new Eth(
$this->web3->provider,
$resolverAbi,
$resolverAddress
);
$address = '0x0000000000000000000000000000000000000000';
$resolver->call('addr', $nameHash, function($err, $result) use (&$address) {
if ($err !== null) {
throw new Exception($err->getMessage());
}
$address = $result[0];
});
return $address;
}
}
完整使用示例
<?php
require 'vendor/autoload.php';
class EthereumENSExample
{
private $ethClient;
private $ensManager;
private $txManager;
public function __construct()
{
$rpcUrl = 'https://mainnet.infura.io/v3/YOUR_PROJECT_ID';
$this->ethClient = new EthereumClient($rpcUrl);
$this->ensManager = new ENSManager($rpcUrl);
}
public function demoENSResolver()
{
try {
// 解析ENS域名
$domain = 'vitalik.eth';
$resolvedAddress = $this->ensManager->resolveName($domain);
echo "Domain: {$domain}\n";
echo "Resolved Address: {$resolvedAddress}\n";
// 获取余额
$balance = $this->ethClient->getBalance($resolvedAddress);
echo "Balance: {$balance} ETH\n";
// 反向解析
$reverseName = $this->ensManager->reverseResolve($resolvedAddress);
if ($reverseName) {
echo "Reverse Resolution: {$reverseName}\n";
}
} catch (Exception $e) {
echo "Error: " . $e->getMessage() . "\n";
}
}
}
// 运行示例
$example = new EthereumENSExample();
$example->demoENSResolver();
错误处理和最佳实践
<?php
class EthereumService
{
private $cache;
public function __construct()
{
// 使用缓存减少RPC调用
$this->cache = new \Redis();
}
public function safeResolveName($domainName)
{
// 缓存检查
$cacheKey = "ens_resolve_{$domainName}";
$cachedResult = $this->cache->get($cacheKey);
if ($cachedResult !== false) {
return $cachedResult;
}
try {
$address = $this->ensManager->resolveName($domainName);
// 缓存结果(缓存1小时)
$this->cache->setex($cacheKey, 3600, $address);
return $address;
} catch (Exception $e) {
// 记录错误日志
error_log("ENS resolution failed: " . $e->getMessage());
throw $e;
}
}
public function batchResolveNames(array $domainNames)
{
$results = [];
foreach ($domainNames as $domain) {
try {
$results[$domain] = $this->safeResolveName($domain);
} catch (Exception $e) {
$results[$domain] = null;
}
}
return $results;
}
}
配置文件
<?php
// config/ethereum.php
return [
'rpc_url' => env('ETHEREUM_RPC_URL', 'https://mainnet.infura.io/v3/YOUR_PROJECT_ID'),
'chain_id' => env('ETHEREUM_CHAIN_ID', 1), // 1: Mainnet, 4: Rinkeby, 5: Goerli
'gas_limit' => env('ETHEREUM_GAS_LIMIT', 21000),
'gas_price_multiplier' => env('ETHEREUM_GAS_PRICE_MULTIPLIER', 1.1),
'ens' => [
'enabled' => true,
'cache_ttl' => 3600, // 缓存时间(秒)
'default_resolver' => '0x4976fb03C32e5B8cfe2b6cCB31c09Ba78EBaBa41'
]
];
注意事项
-
安全考虑:
- 永远不要在代码中硬编码私钥
- 使用环境变量或安全的密钥管理服务
- 限制RPC调用的频率和数量
-
性能优化:
- 实现缓存机制减少RPC调用
- 使用批量查询减少网络开销
- 考虑使用WebSocket连接实时数据
-
错误处理:
- 妥善处理网络超时
- 验证输入数据的有效性
- 记录详细的错误日志
-
ENS相关:
- ENS解析可能需要多个RPC调用
- 考虑使用ENS子图(The Graph)提高查询效率
- 注意ENS域名的过期和更新
这个实现提供了PHP项目中集成Ethereum和ENS的基础框架,您可以根据实际需求进行扩展和优化。