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>
131 lines
4.0 KiB
Solidity
131 lines
4.0 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity ^0.8.19;
|
|
|
|
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
|
|
|
interface IMintable {
|
|
function mint(address to, uint256 amount) external;
|
|
}
|
|
|
|
interface ICWMultiTokenBridgeL1 {
|
|
function lockAndSend(
|
|
address canonicalToken,
|
|
uint64 destinationChainSelector,
|
|
address recipient,
|
|
uint256 amount
|
|
) external payable returns (bytes32);
|
|
|
|
function calculateFee(
|
|
address canonicalToken,
|
|
uint64 destinationChainSelector,
|
|
address recipient,
|
|
uint256 amount
|
|
) external view returns (uint256);
|
|
}
|
|
|
|
/**
|
|
* @notice Batch mint + bridge for c* mirror mesh prep on Chain 138.
|
|
* @dev Called by the operator EOA. Grant IMintable.MINTER_ROLE to this contract on each c* token.
|
|
* Multicall3 cannot replace this: subcalls would see msg.sender = Multicall3, not the operator.
|
|
*/
|
|
contract CWMirrorMeshBatch {
|
|
using SafeERC20 for IERC20;
|
|
|
|
address public immutable bridge;
|
|
address public immutable link;
|
|
|
|
event MintMany(address indexed operator, uint256 callCount);
|
|
event BridgeMany(address indexed operator, address indexed token, uint256 chunkCount, uint256 totalAmount);
|
|
|
|
constructor(address bridge_, address link_) {
|
|
require(bridge_ != address(0), "zero bridge");
|
|
require(link_ != address(0), "zero link");
|
|
bridge = bridge_;
|
|
link = link_;
|
|
}
|
|
|
|
/// @dev Mint each amount to msg.sender (operator) in one transaction.
|
|
function mintMany(address[] calldata tokens, uint256[] calldata amounts) external {
|
|
uint256 n = tokens.length;
|
|
require(n == amounts.length, "length mismatch");
|
|
for (uint256 i; i < n; ) {
|
|
IMintable(tokens[i]).mint(msg.sender, amounts[i]);
|
|
unchecked {
|
|
++i;
|
|
}
|
|
}
|
|
emit MintMany(msg.sender, n);
|
|
}
|
|
|
|
/// @dev Mint one token repeatedly to msg.sender (same token, many chunks) in one transaction.
|
|
function mintChunks(address token, uint256[] calldata amounts) external {
|
|
uint256 n = amounts.length;
|
|
for (uint256 i; i < n; ) {
|
|
IMintable(token).mint(msg.sender, amounts[i]);
|
|
unchecked {
|
|
++i;
|
|
}
|
|
}
|
|
emit MintMany(msg.sender, n);
|
|
}
|
|
|
|
/**
|
|
* @dev Bridge one canonical token in multiple lockAndSend chunks from msg.sender.
|
|
* Pulls total token + total LINK fee upfront, then loops lockAndSend.
|
|
*/
|
|
function bridgeTokenChunks(
|
|
address canonicalToken,
|
|
uint64 destinationChainSelector,
|
|
address recipient,
|
|
uint256[] calldata amounts
|
|
) external payable {
|
|
uint256 n = amounts.length;
|
|
require(n > 0, "empty amounts");
|
|
|
|
uint256 totalAmount;
|
|
uint256 totalFee;
|
|
for (uint256 i; i < n; ) {
|
|
totalAmount += amounts[i];
|
|
totalFee += ICWMultiTokenBridgeL1(bridge).calculateFee(
|
|
canonicalToken,
|
|
destinationChainSelector,
|
|
recipient,
|
|
amounts[i]
|
|
);
|
|
unchecked {
|
|
++i;
|
|
}
|
|
}
|
|
|
|
IERC20(canonicalToken).safeTransferFrom(msg.sender, address(this), totalAmount);
|
|
IERC20(link).safeTransferFrom(msg.sender, address(this), totalFee);
|
|
|
|
for (uint256 i; i < n; ) {
|
|
uint256 amount = amounts[i];
|
|
uint256 fee = ICWMultiTokenBridgeL1(bridge).calculateFee(
|
|
canonicalToken,
|
|
destinationChainSelector,
|
|
recipient,
|
|
amount
|
|
);
|
|
|
|
IERC20(canonicalToken).forceApprove(bridge, amount);
|
|
IERC20(link).forceApprove(bridge, fee);
|
|
|
|
ICWMultiTokenBridgeL1(bridge).lockAndSend(
|
|
canonicalToken,
|
|
destinationChainSelector,
|
|
recipient,
|
|
amount
|
|
);
|
|
|
|
unchecked {
|
|
++i;
|
|
}
|
|
}
|
|
|
|
emit BridgeMany(msg.sender, canonicalToken, n, totalAmount);
|
|
}
|
|
}
|