- CCIP/trustless bridge contracts, GRU tokens, DEX/PMM tests, reserve vault. - Token-aggregation service routes, planner, chain config, relay env templates. - Config snapshots and multi-chain deployment markdown updates. - gitignore services/btc-intake/dist/ (tsc output); do not track dist. Run forge build && forge test before deploy (large solc graph). Made-with: Cursor
71 lines
2.7 KiB
Solidity
71 lines
2.7 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity ^0.8.20;
|
|
|
|
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
|
import {UniversalCCIPBridge} from "../bridge/UniversalCCIPBridge.sol";
|
|
import {ICrossChainFlashBridge} from "./interfaces/ICrossChainFlashBridge.sol";
|
|
|
|
/**
|
|
* @title UniversalCCIPFlashBridgeAdapter
|
|
* @notice Pulls `token` from the caller (e.g. `CrossChainFlashBorrower`) and forwards a `UniversalCCIPBridge.bridge` call.
|
|
* @dev `extraData` (see `ICrossChainFlashBridge`): if empty, uses `assetType = 0`, `usePMM/useVault = false`, empty proofs.
|
|
* If non-empty: `abi.encode(bytes32 assetType, bool usePMM, bool useVault, bytes complianceProof, bytes vaultInstructions)`.
|
|
* Native value is forwarded for CCIP fees on the underlying bridge.
|
|
*/
|
|
contract UniversalCCIPFlashBridgeAdapter is ICrossChainFlashBridge {
|
|
using SafeERC20 for IERC20;
|
|
|
|
UniversalCCIPBridge public immutable universalBridge;
|
|
|
|
constructor(address universalBridge_) {
|
|
require(universalBridge_ != address(0), "UniversalCCIPFlashBridgeAdapter: zero bridge");
|
|
universalBridge = UniversalCCIPBridge(payable(universalBridge_));
|
|
}
|
|
|
|
function bridgeTokensFrom(
|
|
address token,
|
|
uint256 amount,
|
|
uint64 destinationChainSelector,
|
|
address recipientOnDestination,
|
|
bytes calldata extraData
|
|
) external payable override returns (bytes32 messageId) {
|
|
IERC20(token).safeTransferFrom(msg.sender, address(this), amount);
|
|
IERC20(token).forceApprove(address(universalBridge), amount);
|
|
|
|
bytes32 assetType;
|
|
bool usePMM;
|
|
bool useVault;
|
|
bytes memory complianceProof;
|
|
bytes memory vaultInstructions;
|
|
|
|
if (extraData.length == 0) {
|
|
assetType = bytes32(0);
|
|
usePMM = false;
|
|
useVault = false;
|
|
complianceProof = "";
|
|
vaultInstructions = "";
|
|
} else {
|
|
(assetType, usePMM, useVault, complianceProof, vaultInstructions) =
|
|
abi.decode(extraData, (bytes32, bool, bool, bytes, bytes));
|
|
}
|
|
|
|
UniversalCCIPBridge.BridgeOperation memory op = UniversalCCIPBridge.BridgeOperation({
|
|
token: token,
|
|
amount: amount,
|
|
destinationChain: destinationChainSelector,
|
|
recipient: recipientOnDestination,
|
|
assetType: assetType,
|
|
usePMM: usePMM,
|
|
useVault: useVault,
|
|
complianceProof: complianceProof,
|
|
vaultInstructions: vaultInstructions
|
|
});
|
|
|
|
messageId = universalBridge.bridge{value: msg.value}(op);
|
|
IERC20(token).forceApprove(address(universalBridge), 0);
|
|
}
|
|
|
|
receive() external payable {}
|
|
}
|