Интеграция с CCIP (Chainlink Cross-Chain)
Chainlink CCIP (Cross-Chain Interoperability Protocol) — это мост и messaging протокол от Chainlink, построенный поверх их децентрализованной oracle сети. Главное позиционирование: enterprise-grade безопасность с независимым Risk Management Network поверх основной сети DON.
Архитектура безопасности
CCIP использует два независимых слоя валидации:
- Primary DON — Chainlink oracle сеть, передаёт и валидирует сообщения
- Risk Management Network (ARM) — независимая сеть нод, которая мониторит аномалии и может заблокировать подозрительные сообщения
Это двойная защита: даже если Primary DON скомпрометирован, ARM может остановить вредоносную транзакцию. Такой дизайн позиционирует CCIP для финансовых институтов с высокими security требованиями.
Отправка сообщений и токенов
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
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 "@chainlink/contracts-ccip/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
import {LinkTokenInterface} from "@chainlink/contracts/src/v0.8/shared/interfaces/LinkTokenInterface.sol";
contract CCIPSender {
IRouterClient public router;
LinkTokenInterface public linkToken;
constructor(address _router, address _link) {
router = IRouterClient(_router);
linkToken = LinkTokenInterface(_link);
}
// Отправка сообщения с оплатой в LINK
function sendMessage(
uint64 destinationChainSelector, // Chainlink chain selector
address receiver,
bytes calldata data,
address tokenAddress,
uint256 tokenAmount
) external returns (bytes32 messageId) {
Client.EVMTokenAmount[] memory tokenAmounts = new Client.EVMTokenAmount[](1);
tokenAmounts[0] = Client.EVMTokenAmount({
token: tokenAddress,
amount: tokenAmount,
});
Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
receiver: abi.encode(receiver),
data: data,
tokenAmounts: tokenAmounts,
extraArgs: Client._argsToBytes(
Client.EVMExtraArgsV1({ gasLimit: 200_000 })
),
feeToken: address(linkToken),
});
// Получаем стоимость
uint256 fee = router.getFee(destinationChainSelector, message);
linkToken.approve(address(router), fee);
// Одобряем токены для router
IERC20(tokenAddress).approve(address(router), tokenAmount);
// Отправляем
messageId = router.ccipSend(destinationChainSelector, message);
emit MessageSent(messageId, destinationChainSelector, receiver, fee);
}
}
Получение сообщений
import {CCIPReceiver} from "@chainlink/contracts-ccip/src/v0.8/ccip/applications/CCIPReceiver.sol";
contract CCIPReceiver is CCIPReceiver {
// Разрешённые отправители
mapping(uint64 => address) public allowedSenders;
constructor(address router) CCIPReceiver(router) {}
function _ccipReceive(
Client.Any2EVMMessage memory message
) internal override {
address sender = abi.decode(message.sender, (address));
// Проверяем отправителя
require(
allowedSenders[message.sourceChainSelector] == sender,
"Unknown sender"
);
// Обрабатываем полученные токены
for (uint i = 0; i < message.destTokenAmounts.length; i++) {
address token = message.destTokenAmounts[i].token;
uint256 amount = message.destTokenAmounts[i].amount;
// токены уже на этом контракте
}
// Обрабатываем данные
(address recipient, uint256 action) = abi.decode(
message.data,
(address, uint256)
);
_executeAction(recipient, action, message.destTokenAmounts);
}
}
Chain Selectors
CCIP использует собственные chain selectors (не chainId):
| Chain | Selector |
|---|---|
| Ethereum Mainnet | 5009297550715157269 |
| Polygon | 4051577828743386545 |
| Avalanche | 6433500567565415381 |
| Arbitrum | 4949039107694359620 |
| Optimism | 3734403246176062136 |
| Base | 15971525489660198786 |
Оплата нативным токеном вместо LINK
// Оплата ETH/MATIC вместо LINK
Client.EVM2AnyMessage memory message = Client.EVM2AnyMessage({
receiver: abi.encode(receiver),
data: data,
tokenAmounts: tokenAmounts,
extraArgs: Client._argsToBytes(Client.EVMExtraArgsV1({ gasLimit: 200_000 })),
feeToken: address(0), // нативный токен
});
uint256 fee = router.getFee(destinationChainSelector, message);
messageId = router.ccipSend{value: fee}(destinationChainSelector, message);
CCIP — хороший выбор для: enterprise проектов с требованиями к security audit trail; DeFi протоколов с большими TVL где важна reputation Chainlink; случаев когда уже используется Chainlink Price Feeds и Data Feeds — CCIP хорошо интегрируется в существующий стек.
Интеграция CCIP — 2-3 недели. Официальная документация и примеры хорошего качества, Chainlink поддерживает работу с enterprise клиентами.







