Some checks failed
CI/CD Pipeline / Solidity Contracts (push) Failing after 1m3s
CI/CD Pipeline / Security Scanning (push) Successful in 2m18s
CI/CD Pipeline / Lint and Format (push) Failing after 34s
CI/CD Pipeline / Terraform Validation (push) Failing after 20s
CI/CD Pipeline / Kubernetes Validation (push) Successful in 22s
Deploy ChainID 138 / Deploy ChainID 138 (push) Failing after 40s
HYBX OMNL TypeScript & anchor / token-aggregation build + reconcile artifact (push) Failing after 49s
OMNL reconcile anchor / Run omnl:reconcile and upload artifacts (push) Failing after 21s
Validation / validate-genesis (push) Successful in 25s
Validation / validate-terraform (push) Failing after 21s
Validation / validate-kubernetes (push) Failing after 8s
Validation / validate-smart-contracts (push) Failing after 8s
Validation / validate-security (push) Failing after 1m11s
Validation / validate-documentation (push) Failing after 14s
Verify Deployment / Verify Deployment (push) Failing after 45s
Ship AddressActivityRegistry V1/V2, ISO20022IntakeGateway, Chain138ParticipantSurface, checkpoint hub contracts, checkpoint-core package, aggregator/indexer/sdk services, relay profile guards, M00 diamond bridge facet, and OMNL compliance contracts. Co-authored-by: Cursor <cursoragent@cursor.com>
69 lines
2.7 KiB
Solidity
69 lines
2.7 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity ^0.8.19;
|
|
|
|
import "../ccip/IRouterClient.sol";
|
|
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
import "@openzeppelin/contracts/access/AccessControl.sol";
|
|
|
|
/**
|
|
* @title CCIP Relay Bridge (LINK)
|
|
* @notice Accepts relayed CCIP messages carrying canonical LINK on the destination chain.
|
|
* @dev Companion to CCIPRelayBridge (WETH9-only). Grant ROUTER_ROLE to the same CCIPRelayRouter.
|
|
*/
|
|
contract CCIPRelayBridgeLINK is AccessControl {
|
|
bytes32 public constant ROUTER_ROLE = keccak256("ROUTER_ROLE");
|
|
|
|
address public immutable link;
|
|
address public relayRouter;
|
|
|
|
mapping(bytes32 => bool) public processedTransfers;
|
|
|
|
event CrossChainTransferCompleted(
|
|
bytes32 indexed messageId,
|
|
uint64 indexed sourceChainSelector,
|
|
address indexed recipient,
|
|
uint256 amount
|
|
);
|
|
|
|
constructor(address _link, address _relayRouter) {
|
|
require(_link != address(0), "CCIPRelayBridgeLINK: zero LINK");
|
|
require(_relayRouter != address(0), "CCIPRelayBridgeLINK: zero router");
|
|
link = _link;
|
|
relayRouter = _relayRouter;
|
|
_grantRole(ROUTER_ROLE, _relayRouter);
|
|
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
|
|
}
|
|
|
|
function updateRelayRouter(address newRelayRouter) external onlyRole(DEFAULT_ADMIN_ROLE) {
|
|
require(newRelayRouter != address(0), "CCIPRelayBridgeLINK: zero address");
|
|
_revokeRole(ROUTER_ROLE, relayRouter);
|
|
relayRouter = newRelayRouter;
|
|
_grantRole(ROUTER_ROLE, newRelayRouter);
|
|
}
|
|
|
|
function ccipReceive(IRouterClient.Any2EVMMessage calldata message) external onlyRole(ROUTER_ROLE) {
|
|
require(!processedTransfers[message.messageId], "CCIPRelayBridgeLINK: already processed");
|
|
processedTransfers[message.messageId] = true;
|
|
|
|
require(message.tokenAmounts.length > 0, "CCIPRelayBridgeLINK: no tokens");
|
|
require(message.tokenAmounts[0].token == link, "CCIPRelayBridgeLINK: invalid token");
|
|
|
|
uint256 amount = message.tokenAmounts[0].amount;
|
|
require(amount > 0, "CCIPRelayBridgeLINK: invalid amount");
|
|
|
|
address recipient;
|
|
if (message.data.length == 64) {
|
|
(recipient, ) = abi.decode(message.data, (address, uint256));
|
|
} else if (message.data.length >= 128) {
|
|
(recipient, , , ) = abi.decode(message.data, (address, uint256, address, uint256));
|
|
} else {
|
|
revert("CCIPRelayBridgeLINK: invalid data");
|
|
}
|
|
require(recipient != address(0), "CCIPRelayBridgeLINK: zero recipient");
|
|
|
|
require(IERC20(link).transfer(recipient, amount), "CCIPRelayBridgeLINK: transfer failed");
|
|
|
|
emit CrossChainTransferCompleted(message.messageId, message.sourceChainSelector, recipient, amount);
|
|
}
|
|
}
|