Files
proxmox/docs/bridge/contracts/CCIPWETH9Bridge_standard_json_generated.json
defiQUG 8b67fcbda1 Organize docs directory: move 25 files to appropriate locations
- Created docs/00-meta/ for documentation meta files (11 files)
- Created docs/archive/reports/ for reports (5 files)
- Created docs/archive/issues/ for issue tracking (2 files)
- Created docs/bridge/contracts/ for Solidity contracts (3 files)
- Created docs/04-configuration/metamask/ for Metamask configs (3 files)
- Created docs/scripts/ for documentation scripts (2 files)
- Root directory now contains only 3 essential files (89.3% reduction)

All recommended actions from docs directory review complete.
2026-01-06 03:32:20 -08:00

28 lines
14 KiB
JSON

{
"language": "Solidity",
"sources": {
"CCIPWETH9Bridge.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.19;\n\n// contracts/ccip/IRouterClient.sol\n\n/**\n * @title Chainlink CCIP Router Client Interface\n * @notice Interface for Chainlink CCIP Router Client\n * @dev This interface is based on Chainlink CCIP Router Client specification\n */\ninterface IRouterClient {\n /// @notice Represents the router's fee token\n enum TokenAmountType {\n Fiat,\n Native\n }\n\n /// @notice Represents a token amount and its type\n struct TokenAmount {\n address token;\n uint256 amount;\n TokenAmountType amountType;\n }\n\n /// @notice Represents a CCIP message\n struct EVM2AnyMessage {\n bytes receiver;\n bytes data;\n TokenAmount[] tokenAmounts;\n address feeToken;\n bytes extraArgs;\n }\n\n /// @notice Represents a CCIP message with source chain information\n struct Any2EVMMessage {\n bytes32 messageId;\n uint64 sourceChainSelector;\n bytes sender;\n bytes data;\n TokenAmount[] tokenAmounts;\n }\n\n /// @notice Emitted when a message is sent\n event MessageSent(\n bytes32 indexed messageId,\n uint64 indexed destinationChainSelector,\n address indexed sender,\n bytes receiver,\n bytes data,\n TokenAmount[] tokenAmounts,\n address feeToken,\n bytes extraArgs\n );\n\n /// @notice Emitted when a message is received\n event MessageReceived(\n bytes32 indexed messageId,\n uint64 indexed sourceChainSelector,\n address indexed sender,\n bytes data,\n TokenAmount[] tokenAmounts\n );\n\n /// @notice Sends a message to a destination chain\n /// @param destinationChainSelector The chain selector of the destination chain\n /// @param message The message to send\n /// @return messageId The ID of the sent message\n /// @return fees The fees required for the message\n /// @dev If feeToken is zero address, fees are paid in native token (ETH) via msg.value\n function ccipSend(\n uint64 destinationChainSelector,\n EVM2AnyMessage memory message\n ) external payable returns (bytes32 messageId, uint256 fees);\n\n /// @notice Gets the fee for sending a message\n /// @param destinationChainSelector The chain selector of the destination chain\n /// @param message The message to send\n /// @return fee The fee required for the message\n function getFee(\n uint64 destinationChainSelector,\n EVM2AnyMessage memory message\n ) external view returns (uint256 fee);\n\n /// @notice Gets the supported tokens for a destination chain\n /// @param destinationChainSelector The chain selector of the destination chain\n /// @return tokens The list of supported tokens\n function getSupportedTokens(\n uint64 destinationChainSelector\n ) external view returns (address[] memory tokens);\n}\n\n// contracts/ccip/CCIPWETH9Bridge.sol\n\n// Minimal IERC20 interface for ERC20 tokens (WETH9 and LINK)\ninterface IERC20 {\n function transferFrom(address from, address to, uint256 amount) external returns (bool);\n function transfer(address to, uint256 amount) external returns (bool);\n function approve(address spender, uint256 amount) external returns (bool);\n function balanceOf(address account) external view returns (uint256);\n}\n\n/**\n * @title CCIP WETH9 Bridge\n * @notice Cross-chain WETH9 transfer bridge using Chainlink CCIP\n * @dev Enables users to send WETH9 tokens across chains via CCIP\n */\ncontract CCIPWETH9Bridge {\n \n IRouterClient public immutable ccipRouter;\n address public immutable weth9; // WETH9 contract address\n address public feeToken; // LINK token address\n address public admin;\n \n // Destination chain configurations\n struct DestinationChain {\n uint64 chainSelector;\n address receiverBridge; // Address of corresponding bridge on destination chain\n bool enabled;\n }\n \n mapping(uint64 => DestinationChain) public destinations;\n uint64[] public destinationChains;\n \n // Track cross-chain transfers for replay protection\n mapping(bytes32 => bool) public processedTransfers;\n mapping(address => uint256) public nonces;\n \n event CrossChainTransferInitiated(\n bytes32 indexed messageId,\n address indexed sender,\n uint64 indexed destinationChainSelector,\n address recipient,\n uint256 amount,\n uint256 nonce\n );\n \n event CrossChainTransferCompleted(\n bytes32 indexed messageId,\n uint64 indexed sourceChainSelector,\n address indexed recipient,\n uint256 amount\n );\n \n event DestinationAdded(uint64 chainSelector, address receiverBridge);\n event DestinationRemoved(uint64 chainSelector);\n event DestinationUpdated(uint64 chainSelector, address receiverBridge);\n \n modifier onlyAdmin() {\n require(msg.sender == admin, \"CCIPWETH9Bridge: only admin\");\n _;\n }\n \n modifier onlyRouter() {\n require(msg.sender == address(ccipRouter), \"CCIPWETH9Bridge: only router\");\n _;\n }\n \n constructor(address _ccipRouter, address _weth9, address _feeToken) {\n require(_ccipRouter != address(0), \"CCIPWETH9Bridge: zero router\");\n require(_weth9 != address(0), \"CCIPWETH9Bridge: zero WETH9\");\n require(_feeToken != address(0), \"CCIPWETH9Bridge: zero fee token\");\n \n ccipRouter = IRouterClient(_ccipRouter);\n weth9 = _weth9;\n feeToken = _feeToken;\n admin = msg.sender;\n }\n \n /**\n * @notice Send WETH9 tokens to another chain via CCIP\n * @param destinationChainSelector The chain selector of the destination chain\n * @param recipient The recipient address on the destination chain\n * @param amount The amount of WETH9 to send\n * @return messageId The CCIP message ID\n */\n function sendCrossChain(\n uint64 destinationChainSelector,\n address recipient,\n uint256 amount\n ) external returns (bytes32 messageId) {\n require(amount > 0, \"CCIPWETH9Bridge: invalid amount\");\n require(recipient != address(0), \"CCIPWETH9Bridge: zero recipient\");\n \n DestinationChain memory dest = destinations[destinationChainSelector];\n require(dest.enabled, \"CCIPWETH9Bridge: destination not enabled\");\n \n // Transfer WETH9 from user\n require(IERC20(weth9).transferFrom(msg.sender, address(this), amount), \"CCIPWETH9Bridge: transfer failed\");\n \n // Increment nonce for replay protection\n nonces[msg.sender]++;\n uint256 currentNonce = nonces[msg.sender];\n \n // Encode transfer data (recipient, amount, sender, nonce)\n bytes memory data = abi.encode(\n recipient,\n amount,\n msg.sender,\n currentNonce\n );\n \n // Prepare CCIP message with WETH9 tokens\n IRouterClient.EVM2AnyMessage memory message = IRouterClient.EVM2AnyMessage({\n receiver: abi.encode(dest.receiverBridge),\n data: data,\n tokenAmounts: new IRouterClient.TokenAmount[](1),\n feeToken: feeToken,\n extraArgs: \"\"\n });\n \n // Set token amount (WETH9)\n message.tokenAmounts[0] = IRouterClient.TokenAmount({\n token: weth9,\n amount: amount,\n amountType: IRouterClient.TokenAmountType.Fiat\n });\n \n // Calculate fee\n uint256 fee = ccipRouter.getFee(destinationChainSelector, message);\n \n // Approve and pay fee\n if (fee > 0) {\n require(IERC20(feeToken).transferFrom(msg.sender, address(this), fee), \"CCIPWETH9Bridge: fee transfer failed\");\n require(IERC20(feeToken).approve(address(ccipRouter), fee), \"CCIPWETH9Bridge: fee approval failed\");\n }\n \n // Send via CCIP\n (messageId, ) = ccipRouter.ccipSend(destinationChainSelector, message);\n \n emit CrossChainTransferInitiated(\n messageId,\n msg.sender,\n destinationChainSelector,\n recipient,\n amount,\n currentNonce\n );\n \n return messageId;\n }\n \n /**\n * @notice Receive WETH9 tokens from another chain via CCIP\n * @param message The CCIP message\n */\n function ccipReceive(\n IRouterClient.Any2EVMMessage calldata message\n ) external onlyRouter {\n // Replay protection: check if message already processed\n require(!processedTransfers[message.messageId], \"CCIPWETH9Bridge: transfer already processed\");\n \n // Mark as processed\n processedTransfers[message.messageId] = true;\n \n // Validate token amounts\n require(message.tokenAmounts.length > 0, \"CCIPWETH9Bridge: no tokens\");\n require(message.tokenAmounts[0].token == weth9, \"CCIPWETH9Bridge: invalid token\");\n \n uint256 amount = message.tokenAmounts[0].amount;\n require(amount > 0, \"CCIPWETH9Bridge: invalid amount\");\n \n // Decode transfer data (recipient, amount, sender, nonce)\n (address recipient, , , ) = abi.decode(\n message.data,\n (address, uint256, address, uint256)\n );\n \n require(recipient != address(0), \"CCIPWETH9Bridge: zero recipient\");\n \n // Transfer WETH9 to recipient\n require(IERC20(weth9).transfer(recipient, amount), \"CCIPWETH9Bridge: transfer failed\");\n \n emit CrossChainTransferCompleted(\n message.messageId,\n message.sourceChainSelector,\n recipient,\n amount\n );\n }\n \n /**\n * @notice Calculate fee for cross-chain transfer\n * @param destinationChainSelector The chain selector of the destination chain\n * @param amount The amount of WETH9 to send\n * @return fee The fee required for the transfer\n */\n function calculateFee(\n uint64 destinationChainSelector,\n uint256 amount\n ) external view returns (uint256 fee) {\n DestinationChain memory dest = destinations[destinationChainSelector];\n require(dest.enabled, \"CCIPWETH9Bridge: destination not enabled\");\n \n bytes memory data = abi.encode(address(0), amount, address(0), 0);\n \n IRouterClient.EVM2AnyMessage memory message = IRouterClient.EVM2AnyMessage({\n receiver: abi.encode(dest.receiverBridge),\n data: data,\n tokenAmounts: new IRouterClient.TokenAmount[](1),\n feeToken: feeToken,\n extraArgs: \"\"\n });\n \n message.tokenAmounts[0] = IRouterClient.TokenAmount({\n token: weth9,\n amount: amount,\n amountType: IRouterClient.TokenAmountType.Fiat\n });\n \n return ccipRouter.getFee(destinationChainSelector, message);\n }\n \n /**\n * @notice Add destination chain\n */\n function addDestination(\n uint64 chainSelector,\n address receiverBridge\n ) external onlyAdmin {\n require(receiverBridge != address(0), \"CCIPWETH9Bridge: zero address\");\n require(!destinations[chainSelector].enabled, \"CCIPWETH9Bridge: destination already exists\");\n \n destinations[chainSelector] = DestinationChain({\n chainSelector: chainSelector,\n receiverBridge: receiverBridge,\n enabled: true\n });\n destinationChains.push(chainSelector);\n \n emit DestinationAdded(chainSelector, receiverBridge);\n }\n \n /**\n * @notice Remove destination chain\n */\n function removeDestination(uint64 chainSelector) external onlyAdmin {\n require(destinations[chainSelector].enabled, \"CCIPWETH9Bridge: destination not found\");\n destinations[chainSelector].enabled = false;\n \n // Remove from array\n for (uint256 i = 0; i < destinationChains.length; i++) {\n if (destinationChains[i] == chainSelector) {\n destinationChains[i] = destinationChains[destinationChains.length - 1];\n destinationChains.pop();\n break;\n }\n }\n \n emit DestinationRemoved(chainSelector);\n }\n \n /**\n * @notice Update destination receiver bridge\n */\n function updateDestination(\n uint64 chainSelector,\n address receiverBridge\n ) external onlyAdmin {\n require(destinations[chainSelector].enabled, \"CCIPWETH9Bridge: destination not found\");\n require(receiverBridge != address(0), \"CCIPWETH9Bridge: zero address\");\n \n destinations[chainSelector].receiverBridge = receiverBridge;\n emit DestinationUpdated(chainSelector, receiverBridge);\n }\n \n /**\n * @notice Update fee token\n */\n function updateFeeToken(address newFeeToken) external onlyAdmin {\n require(newFeeToken != address(0), \"CCIPWETH9Bridge: zero address\");\n feeToken = newFeeToken;\n }\n \n /**\n * @notice Change admin\n */\n function changeAdmin(address newAdmin) external onlyAdmin {\n require(newAdmin != address(0), \"CCIPWETH9Bridge: zero address\");\n admin = newAdmin;\n }\n \n /**\n * @notice Get destination chains\n */\n function getDestinationChains() external view returns (uint64[] memory) {\n return destinationChains;\n }\n \n /**\n * @notice Get user nonce\n */\n function getUserNonce(address user) external view returns (uint256) {\n return nonces[user];\n }\n}\n"
}
},
"settings": {
"optimizer": {
"enabled": true,
"runs": 200
},
"viaIR": true,
"evmVersion": "london",
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.bytecode.sourceMap",
"evm.deployedBytecode.sourceMap"
]
}
}
}
}