name: 跨链开发 description: 跨链桥和多链开发专业知识。支持LayerZero、Chainlink CCIP、Wormhole和Axelar的全链消息传递、代币桥接和跨链状态验证。 allowed-tools: Read, Grep, Write, Bash, Edit, Glob, WebFetch
跨链开发技能
专业的跨链桥开发与多链集成。
能力
- LayerZero: 全链消息传递和OFT代币
- Chainlink CCIP: 跨链互操作性协议
- 桥接验证: 实现验证逻辑
- 最终性处理: 处理链间最终性差异
- Wormhole/Axelar: 替代桥接协议
- 标准桥接: 代币桥接实现
- 状态验证: 跨链状态证明
LayerZero集成
OFT代币(全链同质化代币)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import { OFT } from "@layerzerolabs/lz-evm-oapp-v2/contracts/oft/OFT.sol";
contract MyOFT is OFT {
constructor(
string memory _name,
string memory _symbol,
address _lzEndpoint,
address _delegate
) OFT(_name, _symbol, _lzEndpoint, _delegate) {
_mint(msg.sender, 1000000 * 10 ** decimals());
}
}
OApp(全链应用)
import { OApp } from "@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/OApp.sol";
import { Origin } from "@layerzerolabs/lz-evm-oapp-v2/contracts/oapp/interfaces/IOAppReceiver.sol";
contract CrossChainCounter is OApp {
uint256 public count;
constructor(address _endpoint, address _owner) OApp(_endpoint, _owner) {}
function increment(
uint32 _dstEid,
bytes calldata _options
) external payable {
bytes memory payload = abi.encode(count + 1);
_lzSend(
_dstEid,
payload,
_options,
MessagingFee(msg.value, 0),
payable(msg.sender)
);
count++;
}
function _lzReceive(
Origin calldata _origin,
bytes32 _guid,
bytes calldata _message,
address _executor,
bytes calldata _extraData
) internal override {
uint256 newCount = abi.decode(_message, (uint256));
count = newCount;
}
}
LayerZero配置
// hardhat.config.ts LayerZero设置
import { EndpointId } from "@layerzerolabs/lz-definitions";
const config = {
networks: {
ethereum: {
url: process.env.ETHEREUM_RPC,
accounts: [process.env.PRIVATE_KEY],
},
arbitrum: {
url: process.env.ARBITRUM_RPC,
accounts: [process.env.PRIVATE_KEY],
},
},
layerZero: {
ethereum: {
eid: EndpointId.ETHEREUM_V2_MAINNET,
endpoint: "0x1a44076050125825900e736c501f859c50fE728c",
},
arbitrum: {
eid: EndpointId.ARBITRUM_V2_MAINNET,
endpoint: "0x1a44076050125825900e736c501f859c50fE728c",
},
},
};
Chainlink CCIP
代币转移
import {IRouterClient} from "@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IRouterClient.sol";
import {Client} from "@chainlink/contracts-ccip/src/v0.8/ccip/libraries/Client.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract CCIPTokenTransfer {
IRouterClient public router;
address public linkToken;
constructor(address _router, address _link) {
router = IRouterClient(_router);
linkToken = _link;
}
function transferTokens(
uint64 destinationChainSelector,
address receiver,
address token,
uint256 amount
) external returns (bytes32 messageId) {
Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1);
tokenAmounts[0] = Client.EVMTokenAmount({
token: token,
amount: amount
});
Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
receiver: abi.encode(receiver),
data: "",
tokenAmounts: tokenAmounts,
extraArgs: "",
feeToken: linkToken
});
uint256 fee = router.getFee(destinationChainSelector, message);
IERC20(linkToken).approve(address(router), fee);
IERC20(token).approve(address(router), amount);
messageId = router.ccipSend(destinationChainSelector, message);
}
}
跨链消息
import {CCIPReceiver} from "@chainlink/contracts-ccip/src/v0.8/ccip/applications/CCIPReceiver.sol";
import {Client} from "@chainlink/contracts-ccip/src/v0.8/ccip/libraries/Client.sol";
contract CCIPReceiver is CCIPReceiver {
event MessageReceived(bytes32 messageId, bytes data);
constructor(address router) CCIPReceiver(router) {}
function _ccipReceive(
Client.Any2EVMMessage memory message
) internal override {
emit MessageReceived(message.messageId, message.data);
// 处理消息
(string memory text) = abi.decode(message.data, (string));
// 处理消息...
}
}
Wormhole集成
代币桥接
interface IWormholeTokenBridge {
function transferTokens(
address token,
uint256 amount,
uint16 recipientChain,
bytes32 recipient,
uint256 arbiterFee,
uint32 nonce
) external payable returns (uint64 sequence);
function completeTransfer(bytes memory encodedVm) external;
}
contract WormholeBridge {
IWormholeTokenBridge public bridge;
function bridgeTokens(
address token,
uint256 amount,
uint16 targetChain,
address recipient
) external payable {
IERC20(token).transferFrom(msg.sender, address(this), amount);
IERC20(token).approve(address(bridge), amount);
bytes32 recipientBytes = bytes32(uint256(uint160(recipient)));
bridge.transferTokens{value: msg.value}(
token,
amount,
targetChain,
recipientBytes,
0,
uint32(block.timestamp)
);
}
}
桥接安全模式
速率限制
contract RateLimitedBridge {
uint256 public constant RATE_LIMIT = 1000000 * 1e18;
uint256 public constant RATE_PERIOD = 1 hours;
uint256 public currentPeriodStart;
uint256 public currentPeriodTransferred;
modifier rateLimited(uint256 amount) {
if (block.timestamp >= currentPeriodStart + RATE_PERIOD) {
currentPeriodStart = block.timestamp;
currentPeriodTransferred = 0;
}
require(
currentPeriodTransferred + amount <= RATE_LIMIT,
"超出速率限制"
);
currentPeriodTransferred += amount;
_;
}
}
断路器
contract CircuitBreakerBridge {
bool public paused;
address public guardian;
uint256 public pauseThreshold;
modifier notPaused() {
require(!paused, "桥接已暂停");
_;
}
function pause() external {
require(msg.sender == guardian, "仅限守护者");
paused = true;
}
function unpause() external {
require(msg.sender == guardian, "仅限守护者");
paused = false;
}
function emergencyWithdraw(
address token,
address to,
uint256 amount
) external {
require(msg.sender == guardian, "仅限守护者");
require(paused, "必须处于暂停状态");
IERC20(token).transfer(to, amount);
}
}
消息验证
contract VerifiedBridge {
mapping(bytes32 => bool) public processedMessages;
mapping(uint256 => uint256) public chainConfirmations;
function processMessage(
bytes32 messageHash,
bytes[] calldata signatures,
uint256 sourceChain
) external {
require(!processedMessages[messageHash], "已处理");
require(
verifySignatures(messageHash, signatures),
"无效签名"
);
processedMessages[messageHash] = true;
// 处理消息...
}
function verifySignatures(
bytes32 messageHash,
bytes[] calldata signatures
) internal view returns (bool) {
// 验证验证者的阈值签名
uint256 validSigs = 0;
for (uint i = 0; i < signatures.length; i++) {
address signer = recoverSigner(messageHash, signatures[i]);
if (isValidator(signer)) {
validSigs++;
}
}
return validSigs >= threshold;
}
}
最终性处理
// TypeScript最终性处理
const CHAIN_FINALITY = {
ethereum: { blocks: 32, time: 384 }, // 384秒最终性
arbitrum: { blocks: 1, time: 0 }, // 继承ETH安全性
optimism: { blocks: 1, time: 0 }, // 继承ETH安全性
polygon: { blocks: 256, time: 512 }, // ~8.5分钟
bsc: { blocks: 15, time: 45 }, // ~45秒
avalanche: { blocks: 1, time: 2 }, // 2秒
};
async function waitForFinality(chainId: number, txHash: string) {
const finality = CHAIN_FINALITY[chainId];
const receipt = await provider.getTransactionReceipt(txHash);
while (true) {
const currentBlock = await provider.getBlockNumber();
if (currentBlock - receipt.blockNumber >= finality.blocks) {
return receipt;
}
await sleep(1000);
}
}
流程集成
| 流程 | 目的 |
|---|---|
cross-chain-bridge.js |
桥接开发 |
blockchain-node-setup.js |
多链基础设施 |
multi-signature-wallet.js |
跨链多重签名 |
最佳实践
- 在桥接上实现速率限制
- 紧急情况下使用断路器
- 按链处理最终性差异
- 彻底验证消息真实性
- 监控桥接TVL和异常情况
- 为链重组做好规划
另请参阅
skills/solidity-dev/SKILL.md- 合约开发agents/bridge-architect/AGENT.md- 桥接专家- LayerZero文档
- CCIP文档