编译器
0.8.17+commit.8df45f5f
文件 1 的 31:Address.sol
pragma solidity ^0.8.1;
library Address {
function isContract(address account) internal view returns (bool) {
return account.code.length > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
文件 2 的 31:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 3 的 31:CrossChainERC20.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract CrossChainERC20 is IERC20 {
struct CrossChainERC20Config {
string name;
string symbol;
uint8 decimals;
uint64 originalChainId;
address originalAddress;
}
mapping(address => uint256) internal _balances;
mapping(address => mapping(address => uint256)) internal _allowances;
string public name;
string public symbol;
uint8 public decimals;
address public originalAddress;
uint64 public originalChainId;
address public immutable deployer;
uint256 public totalSupply;
constructor(CrossChainERC20Config memory _config) {
name = _config.name;
symbol = _config.symbol;
decimals = _config.decimals;
originalChainId = _config.originalChainId;
originalAddress = _config.originalAddress;
deployer = msg.sender;
}
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
function _approve(
address owner,
address spender,
uint256 amount
) internal {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
}
function approve(address spender, uint256 amount) public virtual override returns (bool) {
address owner = msg.sender;
_approve(owner, spender, amount);
return true;
}
function _spendAllowance(
address owner,
address spender,
uint256 amount
) internal virtual {
uint256 currentAllowance = _allowances[owner][spender];
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
function _transfer(
address from,
address to,
uint256 amount
) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
}
_balances[to] += amount;
}
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = msg.sender;
_transfer(owner, to, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public virtual override returns (bool) {
address spender = msg.sender;
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
function mint(address to, uint256 amount) public {
require(msg.sender == deployer);
_balances[to] += amount;
totalSupply += amount;
}
function burn(address from, uint256 amount) public {
require(msg.sender == deployer);
_balances[from] -= amount;
totalSupply -= amount;
}
}
文件 4 的 31:CrossChainVaultApp.sol
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "./CrossChainERC20.sol";
import "./ICrossChainVault.sol";
import "../op/IMultichainEndpoint.sol";
import "../op/celer/message/framework/MessageApp.sol";
contract CrossChainVaultApp is MessageApp, Ownable {
using SafeERC20 for ERC20;
enum CrossChainVaultMessageType {
LockAndMint,
BurnAndUnlock
}
struct SetAllowedSender {
address sender;
uint64 srcChainId;
bool isAllowed;
}
struct CrossChainAssetData {
bool isDataSet;
address token;
string name;
string symbol;
uint8 decimals;
uint64 chainId;
}
event SetAuthorisedSender(address indexed sender, uint64 indexed chainId, bool isSet);
event ActualEndpointChange(address prev, address updated);
event EndpointExecutionReverted(bytes reason);
ICrossChainVault public immutable vault;
IMultichainEndpoint public endpoint;
mapping(uint64 => mapping(address => CrossChainERC20)) public mintedTokenByOriginal;
mapping(uint64 => mapping(CrossChainERC20 => address)) public originalTokenByMinted;
mapping(address => mapping(uint64 => bool)) public allowedSenders;
mapping(uint64 => bool) public allowedSenderSetup;
mapping(address => mapping(uint64 => CrossChainAssetData)) public crossChainAssetsData;
constructor(address _vault, address _messageBus) MessageApp(_messageBus) {
vault = ICrossChainVault(_vault);
}
function setActualEndpoint(address _endpoint) public onlyOwner {
require(address(endpoint) == address(0), "The endpoint is already configured");
emit ActualEndpointChange(address(endpoint), _endpoint);
endpoint = IMultichainEndpoint(_endpoint);
}
function setCrossChainAssets(CrossChainAssetData[] calldata assets) public onlyOwner {
for (uint i = 0; i < assets.length; i++) {
crossChainAssetsData[assets[i].token][assets[i].chainId] = assets[i];
}
}
function setAllowedSenders(SetAllowedSender[] calldata senders) public onlyOwner {
for (uint i = 0; i < senders.length; i++) {
require(!allowedSenderSetup[senders[i].srcChainId], "Sender is already setup");
emit SetAuthorisedSender(senders[i].sender, senders[i].srcChainId, senders[i].isAllowed);
allowedSenders[senders[i].sender][senders[i].srcChainId] = senders[i].isAllowed;
allowedSenderSetup[senders[i].srcChainId] = true;
}
}
function executeMessage(
address srcContract,
uint64 _srcChainId,
bytes calldata _message,
address
) external payable override onlyMessageBus returns (ExecutionStatus) {
require(allowedSenders[srcContract][_srcChainId], "Unauthorised sender");
(bytes memory lockData, bytes memory _data) = abi.decode(_message, (bytes, bytes));
(address token, uint256 amount) = _processVaultCommand(_srcChainId, lockData);
ERC20(token).safeTransfer(address(endpoint), amount);
IMultichainEndpoint.CallbackExecutionStatus status = IMultichainEndpoint.CallbackExecutionStatus.Failed;
try endpoint.executeMessageWithTransfer(
token,
amount,
_srcChainId,
_data
) returns (IMultichainEndpoint.CallbackExecutionStatus _status) {
status = _status;
} catch (bytes memory reason) {
emit EndpointExecutionReverted(reason);
status = endpoint.executeMessageWithTransferFallback(
token,
amount,
_data
);
}
if (status == IMultichainEndpoint.CallbackExecutionStatus.Success) {
return ExecutionStatus.Success;
} else if (status == IMultichainEndpoint.CallbackExecutionStatus.Failed) {
return ExecutionStatus.Fail;
} else if (status == IMultichainEndpoint.CallbackExecutionStatus.Retry) {
return ExecutionStatus.Retry;
}
return ExecutionStatus.Fail;
}
function _processVaultCommand(uint64 srcChainId, bytes memory rawCommand) private returns (address token, uint256 amt) {
(uint8 _type, address srcAddress, uint256 amount) = abi.decode(rawCommand, (uint8, address, uint256));
CrossChainVaultMessageType cmdType = CrossChainVaultMessageType(_type);
amt = amount;
if (cmdType == CrossChainVaultMessageType.LockAndMint) {
CrossChainAssetData memory data = crossChainAssetsData[srcAddress][srcChainId];
require(data.isDataSet, "Metadata is not set");
token = _mintTokens(CrossChainERC20.CrossChainERC20Config(
data.name,
data.symbol,
data.decimals,
srcChainId,
srcAddress
), amount);
} else if (cmdType == CrossChainVaultMessageType.BurnAndUnlock) {
vault.unlock(srcAddress, amount);
token = srcAddress;
} else {
revert();
}
}
function _mintTokens(CrossChainERC20.CrossChainERC20Config memory originalTokenDetails, uint256 amount) private returns (address) {
CrossChainERC20 minted = mintedTokenByOriginal[originalTokenDetails.originalChainId][originalTokenDetails.originalAddress];
if (address(minted) == address(0)) {
minted = new CrossChainERC20(originalTokenDetails);
mintedTokenByOriginal[originalTokenDetails.originalChainId][originalTokenDetails.originalAddress] = minted;
originalTokenByMinted[originalTokenDetails.originalChainId][minted] = originalTokenDetails.originalAddress;
}
minted.mint(address(this), amount);
return address(minted);
}
receive() external payable {}
function lockAndMint(address to, uint64 chainId, address token, uint256 amount, bytes memory message) public payable {
require(msg.sender == address(endpoint), "Invalid endpoint");
ERC20(token).safeTransferFrom(msg.sender, address(this), amount);
ERC20(token).safeIncreaseAllowance(address(vault), amount);
amount = vault.lock(token, amount);
bytes memory lockData = abi.encode(uint8(CrossChainVaultMessageType.LockAndMint), token, amount);
bytes memory payload = abi.encode(lockData, message);
sendMessage(to, chainId, payload, IMessageBus(messageBus).calcFee(payload));
}
function burnAndUnlock(address to, uint64 chainId, address token, uint256 amount, bytes memory message) public payable {
require(msg.sender == address(endpoint), "Invalid endpoint");
require(originalTokenByMinted[chainId][CrossChainERC20(token)] != address(0), "Invalid cross-chain token");
ERC20(token).safeTransferFrom(msg.sender, address(this), amount);
CrossChainERC20 crossChainToken = CrossChainERC20(token);
crossChainToken.burn(address(this), amount);
bytes memory unlockData = abi.encode(uint8(CrossChainVaultMessageType.BurnAndUnlock), crossChainToken.originalAddress(), amount);
bytes memory payload = abi.encode(unlockData, message);
sendMessage(to, chainId, payload, IMessageBus(messageBus).calcFee(payload));
}
}
文件 5 的 31:ERC20.sol
pragma solidity ^0.8.0;
import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";
contract ERC20 is Context, IERC20, IERC20Metadata {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
function name() public view virtual override returns (string memory) {
return _name;
}
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
function decimals() public view virtual override returns (uint8) {
return 18;
}
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
function approve(address spender, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, allowance(owner, spender) + addedValue);
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = allowance(owner, spender);
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
function _transfer(address from, address to, uint256 amount) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
_balances[to] += amount;
}
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
unchecked {
_balances[account] += amount;
}
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
_totalSupply -= amount;
}
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
function _approve(address owner, address spender, uint256 amount) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}
function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}
}
文件 6 的 31:IBridge.sol
pragma solidity >=0.8.0;
interface IBridge {
function send(
address _receiver,
address _token,
uint256 _amount,
uint64 _dstChainId,
uint64 _nonce,
uint32 _maxSlippage
) external;
function sendNative(
address _receiver,
uint256 _amount,
uint64 _dstChainId,
uint64 _nonce,
uint32 _maxSlippage
) external payable;
function relay(
bytes calldata _relayRequest,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers
) external;
function transfers(bytes32 transferId) external view returns (bool);
function withdraws(bytes32 withdrawId) external view returns (bool);
function withdraw(
bytes calldata _wdmsg,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers
) external;
function verifySigs(
bytes memory _msg,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers
) external view;
}
文件 7 的 31:ICrossChainVault.sol
pragma solidity ^0.8.0;
interface ICrossChainVault {
function lock(address asset, uint256 amount) external returns (uint256);
function unlock(address asset, uint256 amount) external;
}
文件 8 的 31:IDelayedTransfer.sol
pragma solidity >=0.8.17;
interface IDelayedTransfer {
struct delayedTransfer {
address receiver;
address token;
uint256 amount;
uint256 timestamp;
}
function delayedTransfers(bytes32 transferId) external view returns (delayedTransfer memory);
}
文件 9 的 31:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}
文件 10 的 31:IERC20Metadata.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
interface IERC20Metadata is IERC20 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
}
文件 11 的 31:IERC20Permit.sol
pragma solidity ^0.8.0;
interface IERC20Permit {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
文件 12 的 31:IMessageBus.sol
pragma solidity >=0.8.0;
import "../libraries/MsgDataTypes.sol";
interface IMessageBus {
function sendMessage(
address _receiver,
uint256 _dstChainId,
bytes calldata _message
) external payable;
function sendMessage(
bytes calldata _receiver,
uint256 _dstChainId,
bytes calldata _message
) external payable;
function sendMessageWithTransfer(
address _receiver,
uint256 _dstChainId,
address _srcBridge,
bytes32 _srcTransferId,
bytes calldata _message
) external payable;
function executeMessage(
bytes calldata _message,
MsgDataTypes.RouteInfo calldata _route,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers
) external payable;
function executeMessageWithTransfer(
bytes calldata _message,
MsgDataTypes.TransferInfo calldata _transfer,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers
) external payable;
function executeMessageWithTransferRefund(
bytes calldata _message,
MsgDataTypes.TransferInfo calldata _transfer,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers
) external payable;
function withdrawFee(
address _account,
uint256 _cumulativeFee,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers
) external;
function calcFee(bytes calldata _message) external view returns (uint256);
function liquidityBridge() external view returns (address);
function pegBridge() external view returns (address);
function pegBridgeV2() external view returns (address);
function pegVault() external view returns (address);
function pegVaultV2() external view returns (address);
}
文件 13 的 31:IMessageReceiverApp.sol
pragma solidity >=0.8.0;
interface IMessageReceiverApp {
enum ExecutionStatus {
Fail,
Success,
Retry
}
function executeMessage(
address _sender,
uint64 _srcChainId,
bytes calldata _message,
address _executor
) external payable returns (ExecutionStatus);
function executeMessage(
bytes calldata _sender,
uint64 _srcChainId,
bytes calldata _message,
address _executor
) external payable returns (ExecutionStatus);
function executeMessageWithTransfer(
address _sender,
address _token,
uint256 _amount,
uint64 _srcChainId,
bytes calldata _message,
address _executor
) external payable returns (ExecutionStatus);
function executeMessageWithTransferFallback(
address _sender,
address _token,
uint256 _amount,
uint64 _srcChainId,
bytes calldata _message,
address _executor
) external payable returns (ExecutionStatus);
function executeMessageWithTransferRefund(
address _token,
uint256 _amount,
bytes calldata _message,
address _executor
) external payable returns (ExecutionStatus);
}
文件 14 的 31:IMultichainEndpoint.sol
pragma solidity ^0.8.0;
interface IMultichainEndpoint {
enum CallbackExecutionStatus {
Success,
Failed,
Retry
}
function executeMessageWithTransfer(
address _token,
uint256 _amount,
uint64 srcChainId,
bytes memory _message
) external payable returns (CallbackExecutionStatus);
function executeMessageWithTransferFallback(
address _token,
uint256 _amount,
bytes calldata _message
) external payable returns (CallbackExecutionStatus);
}
文件 15 的 31:IOriginalTokenVault.sol
pragma solidity >=0.8.0;
interface IOriginalTokenVault {
function deposit(
address _token,
uint256 _amount,
uint64 _mintChainId,
address _mintAccount,
uint64 _nonce
) external;
function depositNative(
uint256 _amount,
uint64 _mintChainId,
address _mintAccount,
uint64 _nonce
) external payable;
function withdraw(
bytes calldata _request,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers
) external;
function records(bytes32 recordId) external view returns (bool);
}
文件 16 的 31:IOriginalTokenVaultV2.sol
pragma solidity >=0.8.0;
interface IOriginalTokenVaultV2 {
function deposit(
address _token,
uint256 _amount,
uint64 _mintChainId,
address _mintAccount,
uint64 _nonce
) external returns (bytes32);
function depositNative(
uint256 _amount,
uint64 _mintChainId,
address _mintAccount,
uint64 _nonce
) external payable returns (bytes32);
function withdraw(
bytes calldata _request,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers
) external returns (bytes32);
function records(bytes32 recordId) external view returns (bool);
}
文件 17 的 31:IPeggedTokenBridge.sol
pragma solidity >=0.8.0;
interface IPeggedTokenBridge {
function burn(
address _token,
uint256 _amount,
address _withdrawAccount,
uint64 _nonce
) external;
function mint(
bytes calldata _request,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers
) external;
function records(bytes32 recordId) external view returns (bool);
}
文件 18 的 31:IPeggedTokenBridgeV2.sol
pragma solidity >=0.8.0;
interface IPeggedTokenBridgeV2 {
function burn(
address _token,
uint256 _amount,
uint64 _toChainId,
address _toAccount,
uint64 _nonce
) external returns (bytes32);
function burnFrom(
address _token,
uint256 _amount,
uint64 _toChainId,
address _toAccount,
uint64 _nonce
) external returns (bytes32);
function mint(
bytes calldata _request,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers
) external returns (bytes32);
function records(bytes32 recordId) external view returns (bool);
}
文件 19 的 31:ISigsVerifier.sol
pragma solidity >=0.8.0;
interface ISigsVerifier {
function verifySigs(
bytes memory _msg,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers
) external view;
}
文件 20 的 31:MessageApp.sol
pragma solidity >=0.8.0;
import "./MessageSenderApp.sol";
import "./MessageReceiverApp.sol";
abstract contract MessageApp is MessageSenderApp, MessageReceiverApp {
constructor(address _messageBus) {
messageBus = _messageBus;
}
}
文件 21 的 31:MessageBus.sol
pragma solidity 0.8.17;
import "./MessageBusSender.sol";
import "./MessageBusReceiver.sol";
contract MessageBus is MessageBusSender, MessageBusReceiver {
constructor(
ISigsVerifier _sigsVerifier,
address _liquidityBridge,
address _pegBridge,
address _pegVault,
address _pegBridgeV2,
address _pegVaultV2
)
MessageBusSender(_sigsVerifier)
MessageBusReceiver(_liquidityBridge, _pegBridge, _pegVault, _pegBridgeV2, _pegVaultV2)
{}
function init(
address _liquidityBridge,
address _pegBridge,
address _pegVault,
address _pegBridgeV2,
address _pegVaultV2
) external {
initOwner();
initReceiver(_liquidityBridge, _pegBridge, _pegVault, _pegBridgeV2, _pegVaultV2);
}
}
文件 22 的 31:MessageBusAddress.sol
pragma solidity >=0.8.0;
abstract contract MessageBusAddress {
address public messageBus;
}
文件 23 的 31:MessageBusReceiver.sol
pragma solidity >=0.8.17;
import "../libraries/MsgDataTypes.sol";
import "../interfaces/IMessageReceiverApp.sol";
import "../../interfaces/IBridge.sol";
import "../../interfaces/IOriginalTokenVault.sol";
import "../../interfaces/IOriginalTokenVaultV2.sol";
import "../../interfaces/IPeggedTokenBridge.sol";
import "../../interfaces/IPeggedTokenBridgeV2.sol";
import "../../interfaces/IDelayedTransfer.sol";
import "../../safeguard/Ownable.sol";
import "../../libraries/Utils.sol";
contract MessageBusReceiver is Ownable {
mapping(bytes32 => MsgDataTypes.TxStatus) public executedMessages;
address public liquidityBridge;
address public pegBridge;
address public pegVault;
address public pegBridgeV2;
address public pegVaultV2;
uint256 public preExecuteMessageGasUsage;
event Executed(
MsgDataTypes.MsgType msgType,
bytes32 msgId,
MsgDataTypes.TxStatus status,
address indexed receiver,
uint64 srcChainId,
bytes32 srcTxHash
);
event NeedRetry(MsgDataTypes.MsgType msgType, bytes32 msgId, uint64 srcChainId, bytes32 srcTxHash);
event CallReverted(string reason);
event LiquidityBridgeUpdated(address liquidityBridge);
event PegBridgeUpdated(address pegBridge);
event PegVaultUpdated(address pegVault);
event PegBridgeV2Updated(address pegBridgeV2);
event PegVaultV2Updated(address pegVaultV2);
constructor(
address _liquidityBridge,
address _pegBridge,
address _pegVault,
address _pegBridgeV2,
address _pegVaultV2
) {
liquidityBridge = _liquidityBridge;
pegBridge = _pegBridge;
pegVault = _pegVault;
pegBridgeV2 = _pegBridgeV2;
pegVaultV2 = _pegVaultV2;
}
function initReceiver(
address _liquidityBridge,
address _pegBridge,
address _pegVault,
address _pegBridgeV2,
address _pegVaultV2
) internal {
require(liquidityBridge == address(0), "liquidityBridge already set");
liquidityBridge = _liquidityBridge;
pegBridge = _pegBridge;
pegVault = _pegVault;
pegBridgeV2 = _pegBridgeV2;
pegVaultV2 = _pegVaultV2;
}
function executeMessageWithTransfer(
bytes calldata _message,
MsgDataTypes.TransferInfo calldata _transfer,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers
) public payable {
bytes32 messageId = verifyTransfer(_transfer);
require(executedMessages[messageId] == MsgDataTypes.TxStatus.Null, "transfer already executed");
executedMessages[messageId] = MsgDataTypes.TxStatus.Pending;
bytes32 domain = keccak256(abi.encodePacked(block.chainid, address(this), "MessageWithTransfer"));
IBridge(liquidityBridge).verifySigs(
abi.encodePacked(domain, messageId, _message, _transfer.srcTxHash),
_sigs,
_signers,
_powers
);
MsgDataTypes.TxStatus status;
IMessageReceiverApp.ExecutionStatus est = executeMessageWithTransfer(_transfer, _message);
if (est == IMessageReceiverApp.ExecutionStatus.Success) {
status = MsgDataTypes.TxStatus.Success;
} else if (est == IMessageReceiverApp.ExecutionStatus.Retry) {
executedMessages[messageId] = MsgDataTypes.TxStatus.Null;
emit NeedRetry(
MsgDataTypes.MsgType.MessageWithTransfer,
messageId,
_transfer.srcChainId,
_transfer.srcTxHash
);
return;
} else {
est = executeMessageWithTransferFallback(_transfer, _message);
if (est == IMessageReceiverApp.ExecutionStatus.Success) {
status = MsgDataTypes.TxStatus.Fallback;
} else {
status = MsgDataTypes.TxStatus.Fail;
}
}
executedMessages[messageId] = status;
emitMessageWithTransferExecutedEvent(messageId, status, _transfer);
}
function executeMessageWithTransferRefund(
bytes calldata _message,
MsgDataTypes.TransferInfo calldata _transfer,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers
) public payable {
bytes32 messageId = verifyTransfer(_transfer);
require(executedMessages[messageId] == MsgDataTypes.TxStatus.Null, "transfer already executed");
executedMessages[messageId] = MsgDataTypes.TxStatus.Pending;
bytes32 domain = keccak256(abi.encodePacked(block.chainid, address(this), "MessageWithTransferRefund"));
IBridge(liquidityBridge).verifySigs(
abi.encodePacked(domain, messageId, _message, _transfer.srcTxHash),
_sigs,
_signers,
_powers
);
MsgDataTypes.TxStatus status;
IMessageReceiverApp.ExecutionStatus est = executeMessageWithTransferRefund(_transfer, _message);
if (est == IMessageReceiverApp.ExecutionStatus.Success) {
status = MsgDataTypes.TxStatus.Success;
} else if (est == IMessageReceiverApp.ExecutionStatus.Retry) {
executedMessages[messageId] = MsgDataTypes.TxStatus.Null;
emit NeedRetry(
MsgDataTypes.MsgType.MessageWithTransfer,
messageId,
_transfer.srcChainId,
_transfer.srcTxHash
);
return;
} else {
status = MsgDataTypes.TxStatus.Fail;
}
executedMessages[messageId] = status;
emitMessageWithTransferExecutedEvent(messageId, status, _transfer);
}
function executeMessage(
bytes calldata _message,
MsgDataTypes.RouteInfo calldata _route,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers
) external payable {
MsgDataTypes.Route memory route = getRouteInfo(_route);
executeMessage(_message, route, _sigs, _signers, _powers, "Message");
}
function executeMessage(
bytes calldata _message,
MsgDataTypes.RouteInfo2 calldata _route,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers
) external payable {
MsgDataTypes.Route memory route = getRouteInfo(_route);
executeMessage(_message, route, _sigs, _signers, _powers, "Message2");
}
function executeMessage(
bytes calldata _message,
MsgDataTypes.Route memory _route,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers,
string memory domainName
) private {
bytes32 messageId = computeMessageOnlyId(_route, _message);
require(executedMessages[messageId] == MsgDataTypes.TxStatus.Null, "message already executed");
executedMessages[messageId] = MsgDataTypes.TxStatus.Pending;
bytes32 domain = keccak256(abi.encodePacked(block.chainid, address(this), domainName));
IBridge(liquidityBridge).verifySigs(abi.encodePacked(domain, messageId), _sigs, _signers, _powers);
MsgDataTypes.TxStatus status;
IMessageReceiverApp.ExecutionStatus est = executeMessage(_route, _message);
if (est == IMessageReceiverApp.ExecutionStatus.Success) {
status = MsgDataTypes.TxStatus.Success;
} else if (est == IMessageReceiverApp.ExecutionStatus.Retry) {
executedMessages[messageId] = MsgDataTypes.TxStatus.Null;
emit NeedRetry(MsgDataTypes.MsgType.MessageOnly, messageId, _route.srcChainId, _route.srcTxHash);
return;
} else {
status = MsgDataTypes.TxStatus.Fail;
}
executedMessages[messageId] = status;
emitMessageOnlyExecutedEvent(messageId, status, _route);
}
function emitMessageWithTransferExecutedEvent(
bytes32 _messageId,
MsgDataTypes.TxStatus _status,
MsgDataTypes.TransferInfo calldata _transfer
) private {
emit Executed(
MsgDataTypes.MsgType.MessageWithTransfer,
_messageId,
_status,
_transfer.receiver,
_transfer.srcChainId,
_transfer.srcTxHash
);
}
function emitMessageOnlyExecutedEvent(
bytes32 _messageId,
MsgDataTypes.TxStatus _status,
MsgDataTypes.Route memory _route
) private {
emit Executed(
MsgDataTypes.MsgType.MessageOnly,
_messageId,
_status,
_route.receiver,
_route.srcChainId,
_route.srcTxHash
);
}
function executeMessageWithTransfer(MsgDataTypes.TransferInfo calldata _transfer, bytes calldata _message)
private
returns (IMessageReceiverApp.ExecutionStatus)
{
uint256 gasLeftBeforeExecution = gasleft();
(bool ok, bytes memory res) = address(_transfer.receiver).call{value: msg.value}(
abi.encodeWithSelector(
IMessageReceiverApp.executeMessageWithTransfer.selector,
_transfer.sender,
_transfer.token,
_transfer.amount,
_transfer.srcChainId,
_message,
msg.sender
)
);
if (ok) {
return abi.decode((res), (IMessageReceiverApp.ExecutionStatus));
}
handleExecutionRevert(gasLeftBeforeExecution, res);
return IMessageReceiverApp.ExecutionStatus.Fail;
}
function executeMessageWithTransferFallback(MsgDataTypes.TransferInfo calldata _transfer, bytes calldata _message)
private
returns (IMessageReceiverApp.ExecutionStatus)
{
uint256 gasLeftBeforeExecution = gasleft();
(bool ok, bytes memory res) = address(_transfer.receiver).call{value: msg.value}(
abi.encodeWithSelector(
IMessageReceiverApp.executeMessageWithTransferFallback.selector,
_transfer.sender,
_transfer.token,
_transfer.amount,
_transfer.srcChainId,
_message,
msg.sender
)
);
if (ok) {
return abi.decode((res), (IMessageReceiverApp.ExecutionStatus));
}
handleExecutionRevert(gasLeftBeforeExecution, res);
return IMessageReceiverApp.ExecutionStatus.Fail;
}
function executeMessageWithTransferRefund(MsgDataTypes.TransferInfo calldata _transfer, bytes calldata _message)
private
returns (IMessageReceiverApp.ExecutionStatus)
{
uint256 gasLeftBeforeExecution = gasleft();
(bool ok, bytes memory res) = address(_transfer.receiver).call{value: msg.value}(
abi.encodeWithSelector(
IMessageReceiverApp.executeMessageWithTransferRefund.selector,
_transfer.token,
_transfer.amount,
_message,
msg.sender
)
);
if (ok) {
return abi.decode((res), (IMessageReceiverApp.ExecutionStatus));
}
handleExecutionRevert(gasLeftBeforeExecution, res);
return IMessageReceiverApp.ExecutionStatus.Fail;
}
function verifyTransfer(MsgDataTypes.TransferInfo calldata _transfer) private view returns (bytes32) {
bytes32 transferId;
address bridgeAddr;
MsgDataTypes.TransferType t = _transfer.t;
if (t == MsgDataTypes.TransferType.LqRelay) {
bridgeAddr = liquidityBridge;
transferId = keccak256(
abi.encodePacked(
_transfer.sender,
_transfer.receiver,
_transfer.token,
_transfer.amount,
_transfer.srcChainId,
uint64(block.chainid),
_transfer.refId
)
);
require(IBridge(bridgeAddr).transfers(transferId) == true, "relay not exist");
} else if (t == MsgDataTypes.TransferType.LqWithdraw) {
bridgeAddr = liquidityBridge;
transferId = keccak256(
abi.encodePacked(
uint64(block.chainid),
_transfer.wdseq,
_transfer.receiver,
_transfer.token,
_transfer.amount
)
);
require(IBridge(bridgeAddr).withdraws(transferId) == true, "withdraw not exist");
} else {
if (t == MsgDataTypes.TransferType.PegMint || t == MsgDataTypes.TransferType.PegWithdraw) {
bridgeAddr = (t == MsgDataTypes.TransferType.PegMint) ? pegBridge : pegVault;
transferId = keccak256(
abi.encodePacked(
_transfer.receiver,
_transfer.token,
_transfer.amount,
_transfer.sender,
_transfer.srcChainId,
_transfer.refId
)
);
} else {
bridgeAddr = (t == MsgDataTypes.TransferType.PegV2Mint) ? pegBridgeV2 : pegVaultV2;
transferId = keccak256(
abi.encodePacked(
_transfer.receiver,
_transfer.token,
_transfer.amount,
_transfer.sender,
_transfer.srcChainId,
_transfer.refId,
bridgeAddr
)
);
}
require(IPeggedTokenBridge(bridgeAddr).records(transferId) == true, "record not exist");
}
require(IDelayedTransfer(bridgeAddr).delayedTransfers(transferId).timestamp == 0, "transfer delayed");
return keccak256(abi.encodePacked(MsgDataTypes.MsgType.MessageWithTransfer, bridgeAddr, transferId));
}
function computeMessageOnlyId(MsgDataTypes.Route memory _route, bytes calldata _message)
private
view
returns (bytes32)
{
bytes memory sender = _route.senderBytes;
if (sender.length == 0) {
sender = abi.encodePacked(_route.sender);
}
return
keccak256(
abi.encodePacked(
MsgDataTypes.MsgType.MessageOnly,
sender,
_route.receiver,
_route.srcChainId,
_route.srcTxHash,
uint64(block.chainid),
_message
)
);
}
function executeMessage(MsgDataTypes.Route memory _route, bytes calldata _message)
private
returns (IMessageReceiverApp.ExecutionStatus)
{
uint256 gasLeftBeforeExecution = gasleft();
bool ok;
bytes memory res;
if (_route.senderBytes.length == 0) {
(ok, res) = address(_route.receiver).call{value: msg.value}(
abi.encodeWithSelector(
bytes4(keccak256(bytes("executeMessage(address,uint64,bytes,address)"))),
_route.sender,
_route.srcChainId,
_message,
msg.sender
)
);
} else {
(ok, res) = address(_route.receiver).call{value: msg.value}(
abi.encodeWithSelector(
bytes4(keccak256(bytes("executeMessage(bytes,uint64,bytes,address)"))),
_route.senderBytes,
_route.srcChainId,
_message,
msg.sender
)
);
}
if (ok) {
return abi.decode((res), (IMessageReceiverApp.ExecutionStatus));
}
handleExecutionRevert(gasLeftBeforeExecution, res);
return IMessageReceiverApp.ExecutionStatus.Fail;
}
function handleExecutionRevert(uint256 _gasLeftBeforeExecution, bytes memory _returnData) private {
uint256 gasLeftAfterExecution = gasleft();
uint256 maxTargetGasLimit = block.gaslimit - preExecuteMessageGasUsage;
if (_gasLeftBeforeExecution < maxTargetGasLimit && gasLeftAfterExecution <= _gasLeftBeforeExecution / 64) {
assembly {
invalid()
}
}
string memory revertMsg = Utils.getRevertMsg(_returnData);
checkAbortPrefix(revertMsg);
emit CallReverted(revertMsg);
}
function checkAbortPrefix(string memory _revertMsg) private pure {
bytes memory prefixBytes = bytes(MsgDataTypes.ABORT_PREFIX);
bytes memory msgBytes = bytes(_revertMsg);
if (msgBytes.length >= prefixBytes.length) {
for (uint256 i = 0; i < prefixBytes.length; i++) {
if (msgBytes[i] != prefixBytes[i]) {
return;
}
}
revert(_revertMsg);
}
}
function getRouteInfo(MsgDataTypes.RouteInfo calldata _route) private pure returns (MsgDataTypes.Route memory) {
return MsgDataTypes.Route(_route.sender, "", _route.receiver, _route.srcChainId, _route.srcTxHash);
}
function getRouteInfo(MsgDataTypes.RouteInfo2 calldata _route) private pure returns (MsgDataTypes.Route memory) {
return MsgDataTypes.Route(address(0), _route.sender, _route.receiver, _route.srcChainId, _route.srcTxHash);
}
function transferAndExecuteMsg(
MsgDataTypes.BridgeTransferParams calldata _tp,
MsgDataTypes.MsgWithTransferExecutionParams calldata _mp
) external {
_bridgeTransfer(_mp.transfer.t, _tp);
executeMessageWithTransfer(_mp.message, _mp.transfer, _mp.sigs, _mp.signers, _mp.powers);
}
function refundAndExecuteMsg(
MsgDataTypes.BridgeTransferParams calldata _tp,
MsgDataTypes.MsgWithTransferExecutionParams calldata _mp
) external {
_bridgeTransfer(_mp.transfer.t, _tp);
executeMessageWithTransferRefund(_mp.message, _mp.transfer, _mp.sigs, _mp.signers, _mp.powers);
}
function _bridgeTransfer(MsgDataTypes.TransferType t, MsgDataTypes.BridgeTransferParams calldata _params) private {
if (t == MsgDataTypes.TransferType.LqRelay) {
IBridge(liquidityBridge).relay(_params.request, _params.sigs, _params.signers, _params.powers);
} else if (t == MsgDataTypes.TransferType.LqWithdraw) {
IBridge(liquidityBridge).withdraw(_params.request, _params.sigs, _params.signers, _params.powers);
} else if (t == MsgDataTypes.TransferType.PegMint) {
IPeggedTokenBridge(pegBridge).mint(_params.request, _params.sigs, _params.signers, _params.powers);
} else if (t == MsgDataTypes.TransferType.PegV2Mint) {
IPeggedTokenBridgeV2(pegBridgeV2).mint(_params.request, _params.sigs, _params.signers, _params.powers);
} else if (t == MsgDataTypes.TransferType.PegWithdraw) {
IOriginalTokenVault(pegVault).withdraw(_params.request, _params.sigs, _params.signers, _params.powers);
} else if (t == MsgDataTypes.TransferType.PegV2Withdraw) {
IOriginalTokenVaultV2(pegVaultV2).withdraw(_params.request, _params.sigs, _params.signers, _params.powers);
}
}
function setLiquidityBridge(address _addr) public onlyOwner {
require(_addr != address(0), "invalid address");
liquidityBridge = _addr;
emit LiquidityBridgeUpdated(liquidityBridge);
}
function setPegBridge(address _addr) public onlyOwner {
require(_addr != address(0), "invalid address");
pegBridge = _addr;
emit PegBridgeUpdated(pegBridge);
}
function setPegVault(address _addr) public onlyOwner {
require(_addr != address(0), "invalid address");
pegVault = _addr;
emit PegVaultUpdated(pegVault);
}
function setPegBridgeV2(address _addr) public onlyOwner {
require(_addr != address(0), "invalid address");
pegBridgeV2 = _addr;
emit PegBridgeV2Updated(pegBridgeV2);
}
function setPegVaultV2(address _addr) public onlyOwner {
require(_addr != address(0), "invalid address");
pegVaultV2 = _addr;
emit PegVaultV2Updated(pegVaultV2);
}
function setPreExecuteMessageGasUsage(uint256 _usage) public onlyOwner {
preExecuteMessageGasUsage = _usage;
}
}
文件 24 的 31:MessageBusSender.sol
pragma solidity 0.8.17;
import "../../safeguard/Ownable.sol";
import "../../interfaces/ISigsVerifier.sol";
contract MessageBusSender is Ownable {
ISigsVerifier public immutable sigsVerifier;
uint256 public feeBase;
uint256 public feePerByte;
mapping(address => uint256) public withdrawnFees;
event Message(address indexed sender, address receiver, uint256 dstChainId, bytes message, uint256 fee);
event Message2(address indexed sender, bytes receiver, uint256 dstChainId, bytes message, uint256 fee);
event MessageWithTransfer(
address indexed sender,
address receiver,
uint256 dstChainId,
address bridge,
bytes32 srcTransferId,
bytes message,
uint256 fee
);
event FeeWithdrawn(address receiver, uint256 amount);
event FeeBaseUpdated(uint256 feeBase);
event FeePerByteUpdated(uint256 feePerByte);
constructor(ISigsVerifier _sigsVerifier) {
sigsVerifier = _sigsVerifier;
}
function sendMessage(
address _receiver,
uint256 _dstChainId,
bytes calldata _message
) external payable {
_sendMessage(_dstChainId, _message);
emit Message(msg.sender, _receiver, _dstChainId, _message, msg.value);
}
function sendMessage(
bytes calldata _receiver,
uint256 _dstChainId,
bytes calldata _message
) external payable {
_sendMessage(_dstChainId, _message);
emit Message2(msg.sender, _receiver, _dstChainId, _message, msg.value);
}
function _sendMessage(uint256 _dstChainId, bytes calldata _message) private {
require(_dstChainId != block.chainid, "Invalid chainId");
uint256 minFee = calcFee(_message);
require(msg.value >= minFee, "Insufficient fee");
}
function sendMessageWithTransfer(
address _receiver,
uint256 _dstChainId,
address _srcBridge,
bytes32 _srcTransferId,
bytes calldata _message
) external payable {
require(_dstChainId != block.chainid, "Invalid chainId");
uint256 minFee = calcFee(_message);
require(msg.value >= minFee, "Insufficient fee");
emit MessageWithTransfer(msg.sender, _receiver, _dstChainId, _srcBridge, _srcTransferId, _message, msg.value);
}
function withdrawFee(
address _account,
uint256 _cumulativeFee,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers
) external {
bytes32 domain = keccak256(abi.encodePacked(block.chainid, address(this), "withdrawFee"));
sigsVerifier.verifySigs(abi.encodePacked(domain, _account, _cumulativeFee), _sigs, _signers, _powers);
uint256 amount = _cumulativeFee - withdrawnFees[_account];
require(amount > 0, "No new amount to withdraw");
withdrawnFees[_account] = _cumulativeFee;
(bool sent, ) = _account.call{value: amount, gas: 50000}("");
require(sent, "failed to withdraw fee");
emit FeeWithdrawn(_account, amount);
}
function calcFee(bytes calldata _message) public view returns (uint256) {
return feeBase + _message.length * feePerByte;
}
function setFeePerByte(uint256 _fee) external onlyOwner {
feePerByte = _fee;
emit FeePerByteUpdated(feePerByte);
}
function setFeeBase(uint256 _fee) external onlyOwner {
feeBase = _fee;
emit FeeBaseUpdated(feeBase);
}
}
文件 25 的 31:MessageReceiverApp.sol
pragma solidity >=0.8.0;
import "../interfaces/IMessageReceiverApp.sol";
import "../libraries/MsgDataTypes.sol";
import "./MessageBusAddress.sol";
abstract contract MessageReceiverApp is IMessageReceiverApp, MessageBusAddress {
modifier onlyMessageBus() {
require(msg.sender == messageBus, "caller is not message bus");
_;
}
function _abortReason(string memory reason) internal pure returns (string memory) {
return MsgDataTypes.abortReason(reason);
}
function executeMessage(
address _sender,
uint64 _srcChainId,
bytes calldata _message,
address _executor
) external payable virtual override onlyMessageBus returns (ExecutionStatus) {}
function executeMessage(
bytes calldata _sender,
uint64 _srcChainId,
bytes calldata _message,
address _executor
) external payable virtual override onlyMessageBus returns (ExecutionStatus) {}
function executeMessageWithTransfer(
address _sender,
address _token,
uint256 _amount,
uint64 _srcChainId,
bytes calldata _message,
address _executor
) external payable virtual override onlyMessageBus returns (ExecutionStatus) {}
function executeMessageWithTransferFallback(
address _sender,
address _token,
uint256 _amount,
uint64 _srcChainId,
bytes calldata _message,
address _executor
) external payable virtual override onlyMessageBus returns (ExecutionStatus) {}
function executeMessageWithTransferRefund(
address _token,
uint256 _amount,
bytes calldata _message,
address _executor
) external payable virtual override onlyMessageBus returns (ExecutionStatus) {}
}
文件 26 的 31:MessageSenderApp.sol
pragma solidity >=0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "../libraries/MsgDataTypes.sol";
import "../libraries/MessageSenderLib.sol";
import "../messagebus/MessageBus.sol";
import "./MessageBusAddress.sol";
abstract contract MessageSenderApp is MessageBusAddress {
using SafeERC20 for IERC20;
function sendMessage(
address _receiver,
uint64 _dstChainId,
bytes memory _message,
uint256 _fee
) internal {
MessageSenderLib.sendMessage(_receiver, _dstChainId, _message, messageBus, _fee);
}
function sendMessage(
bytes calldata _receiver,
uint64 _dstChainId,
bytes memory _message,
uint256 _fee
) internal {
MessageSenderLib.sendMessage(_receiver, _dstChainId, _message, messageBus, _fee);
}
function sendMessageWithTransfer(
address _receiver,
address _token,
uint256 _amount,
uint64 _dstChainId,
uint64 _nonce,
uint32 _maxSlippage,
bytes memory _message,
MsgDataTypes.BridgeSendType _bridgeSendType,
uint256 _fee
) internal returns (bytes32) {
return
MessageSenderLib.sendMessageWithTransfer(
_receiver,
_token,
_amount,
_dstChainId,
_nonce,
_maxSlippage,
_message,
_bridgeSendType,
messageBus,
_fee
);
}
function sendTokenTransfer(
address _receiver,
address _token,
uint256 _amount,
uint64 _dstChainId,
uint64 _nonce,
uint32 _maxSlippage,
MsgDataTypes.BridgeSendType _bridgeSendType
) internal returns (bytes32) {
return
MessageSenderLib.sendMessageWithTransfer(
_receiver,
_token,
_amount,
_dstChainId,
_nonce,
_maxSlippage,
"",
_bridgeSendType,
messageBus,
0
);
}
}
文件 27 的 31:MessageSenderLib.sol
pragma solidity >=0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "../../interfaces/IBridge.sol";
import "../../interfaces/IOriginalTokenVault.sol";
import "../../interfaces/IOriginalTokenVaultV2.sol";
import "../../interfaces/IPeggedTokenBridge.sol";
import "../../interfaces/IPeggedTokenBridgeV2.sol";
import "../interfaces/IMessageBus.sol";
import "./MsgDataTypes.sol";
library MessageSenderLib {
using SafeERC20 for IERC20;
function sendMessage(
address _receiver,
uint64 _dstChainId,
bytes memory _message,
address _messageBus,
uint256 _fee
) internal {
IMessageBus(_messageBus).sendMessage{value: _fee}(_receiver, _dstChainId, _message);
}
function sendMessage(
bytes calldata _receiver,
uint64 _dstChainId,
bytes memory _message,
address _messageBus,
uint256 _fee
) internal {
IMessageBus(_messageBus).sendMessage{value: _fee}(_receiver, _dstChainId, _message);
}
function sendMessageWithTransfer(
address _receiver,
address _token,
uint256 _amount,
uint64 _dstChainId,
uint64 _nonce,
uint32 _maxSlippage,
bytes memory _message,
MsgDataTypes.BridgeSendType _bridgeSendType,
address _messageBus,
uint256 _fee
) internal returns (bytes32) {
(bytes32 transferId, address bridge) = sendTokenTransfer(
_receiver,
_token,
_amount,
_dstChainId,
_nonce,
_maxSlippage,
_bridgeSendType,
_messageBus
);
if (_message.length > 0) {
IMessageBus(_messageBus).sendMessageWithTransfer{value: _fee}(
_receiver,
_dstChainId,
bridge,
transferId,
_message
);
}
return transferId;
}
function sendTokenTransfer(
address _receiver,
address _token,
uint256 _amount,
uint64 _dstChainId,
uint64 _nonce,
uint32 _maxSlippage,
MsgDataTypes.BridgeSendType _bridgeSendType,
address _messageBus
) internal returns (bytes32 transferId, address bridge) {
if (_bridgeSendType == MsgDataTypes.BridgeSendType.Liquidity) {
bridge = IMessageBus(_messageBus).liquidityBridge();
IERC20(_token).safeIncreaseAllowance(bridge, _amount);
IBridge(bridge).send(_receiver, _token, _amount, _dstChainId, _nonce, _maxSlippage);
transferId = computeLiqBridgeTransferId(_receiver, _token, _amount, _dstChainId, _nonce);
} else if (_bridgeSendType == MsgDataTypes.BridgeSendType.PegDeposit) {
bridge = IMessageBus(_messageBus).pegVault();
IERC20(_token).safeIncreaseAllowance(bridge, _amount);
IOriginalTokenVault(bridge).deposit(_token, _amount, _dstChainId, _receiver, _nonce);
transferId = computePegV1DepositId(_receiver, _token, _amount, _dstChainId, _nonce);
} else if (_bridgeSendType == MsgDataTypes.BridgeSendType.PegBurn) {
bridge = IMessageBus(_messageBus).pegBridge();
IERC20(_token).safeIncreaseAllowance(bridge, _amount);
IPeggedTokenBridge(bridge).burn(_token, _amount, _receiver, _nonce);
IERC20(_token).safeApprove(bridge, 0);
transferId = computePegV1BurnId(_receiver, _token, _amount, _nonce);
} else if (_bridgeSendType == MsgDataTypes.BridgeSendType.PegV2Deposit) {
bridge = IMessageBus(_messageBus).pegVaultV2();
IERC20(_token).safeIncreaseAllowance(bridge, _amount);
transferId = IOriginalTokenVaultV2(bridge).deposit(_token, _amount, _dstChainId, _receiver, _nonce);
} else if (_bridgeSendType == MsgDataTypes.BridgeSendType.PegV2Burn) {
bridge = IMessageBus(_messageBus).pegBridgeV2();
IERC20(_token).safeIncreaseAllowance(bridge, _amount);
transferId = IPeggedTokenBridgeV2(bridge).burn(_token, _amount, _dstChainId, _receiver, _nonce);
IERC20(_token).safeApprove(bridge, 0);
} else if (_bridgeSendType == MsgDataTypes.BridgeSendType.PegV2BurnFrom) {
bridge = IMessageBus(_messageBus).pegBridgeV2();
IERC20(_token).safeIncreaseAllowance(bridge, _amount);
transferId = IPeggedTokenBridgeV2(bridge).burnFrom(_token, _amount, _dstChainId, _receiver, _nonce);
IERC20(_token).safeApprove(bridge, 0);
} else {
revert("bridge type not supported");
}
}
function computeLiqBridgeTransferId(
address _receiver,
address _token,
uint256 _amount,
uint64 _dstChainId,
uint64 _nonce
) internal view returns (bytes32) {
return
keccak256(
abi.encodePacked(address(this), _receiver, _token, _amount, _dstChainId, _nonce, uint64(block.chainid))
);
}
function computePegV1DepositId(
address _receiver,
address _token,
uint256 _amount,
uint64 _dstChainId,
uint64 _nonce
) internal view returns (bytes32) {
return
keccak256(
abi.encodePacked(address(this), _token, _amount, _dstChainId, _receiver, _nonce, uint64(block.chainid))
);
}
function computePegV1BurnId(
address _receiver,
address _token,
uint256 _amount,
uint64 _nonce
) internal view returns (bytes32) {
return keccak256(abi.encodePacked(address(this), _token, _amount, _receiver, _nonce, uint64(block.chainid)));
}
}
文件 28 的 31:MsgDataTypes.sol
pragma solidity >=0.8.0;
library MsgDataTypes {
string constant ABORT_PREFIX = "MSG::ABORT:";
function abortReason(string memory reason) internal pure returns (string memory) {
return string.concat(MsgDataTypes.ABORT_PREFIX, reason);
}
enum BridgeSendType {
Null,
Liquidity,
PegDeposit,
PegBurn,
PegV2Deposit,
PegV2Burn,
PegV2BurnFrom
}
enum TransferType {
Null,
LqRelay,
LqWithdraw,
PegMint,
PegWithdraw,
PegV2Mint,
PegV2Withdraw
}
enum MsgType {
MessageWithTransfer,
MessageOnly
}
enum TxStatus {
Null,
Success,
Fail,
Fallback,
Pending
}
struct TransferInfo {
TransferType t;
address sender;
address receiver;
address token;
uint256 amount;
uint64 wdseq;
uint64 srcChainId;
bytes32 refId;
bytes32 srcTxHash;
}
struct RouteInfo {
address sender;
address receiver;
uint64 srcChainId;
bytes32 srcTxHash;
}
struct RouteInfo2 {
bytes sender;
address receiver;
uint64 srcChainId;
bytes32 srcTxHash;
}
struct Route {
address sender;
bytes senderBytes;
address receiver;
uint64 srcChainId;
bytes32 srcTxHash;
}
struct MsgWithTransferExecutionParams {
bytes message;
TransferInfo transfer;
bytes[] sigs;
address[] signers;
uint256[] powers;
}
struct BridgeTransferParams {
bytes request;
bytes[] sigs;
address[] signers;
uint256[] powers;
}
}
文件 29 的 31:Ownable.sol
pragma solidity ^0.8.0;
abstract contract Ownable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor() {
_setOwner(msg.sender);
}
function initOwner() internal {
require(_owner == address(0), "owner already set");
_setOwner(msg.sender);
}
function owner() public view virtual returns (address) {
return _owner;
}
modifier onlyOwner() {
require(owner() == msg.sender, "Ownable: caller is not the owner");
_;
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_setOwner(newOwner);
}
function _setOwner(address newOwner) private {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
文件 30 的 31:SafeERC20.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";
library SafeERC20 {
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(IERC20 token, address spender, uint256 value) internal {
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}
文件 31 的 31:Utils.sol
pragma solidity >=0.8.0;
library Utils {
function getRevertMsg(bytes memory _returnData) internal pure returns (string memory) {
if (_returnData.length < 68) return "Transaction reverted silently";
assembly {
_returnData := add(_returnData, 0x04)
}
return abi.decode(_returnData, (string));
}
}
{
"compilationTarget": {
"contracts/illuminex/chainvault/CrossChainVaultApp.sol": "CrossChainVaultApp"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 300
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_vault","type":"address"},{"internalType":"address","name":"_messageBus","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"prev","type":"address"},{"indexed":false,"internalType":"address","name":"updated","type":"address"}],"name":"ActualEndpointChange","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"reason","type":"bytes"}],"name":"EndpointExecutionReverted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"uint64","name":"chainId","type":"uint64"},{"indexed":false,"internalType":"bool","name":"isSet","type":"bool"}],"name":"SetAuthorisedSender","type":"event"},{"inputs":[{"internalType":"uint64","name":"","type":"uint64"}],"name":"allowedSenderSetup","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint64","name":"","type":"uint64"}],"name":"allowedSenders","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint64","name":"chainId","type":"uint64"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"message","type":"bytes"}],"name":"burnAndUnlock","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint64","name":"","type":"uint64"}],"name":"crossChainAssetsData","outputs":[{"internalType":"bool","name":"isDataSet","type":"bool"},{"internalType":"address","name":"token","type":"address"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint64","name":"chainId","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"endpoint","outputs":[{"internalType":"contract IMultichainEndpoint","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_sender","type":"bytes"},{"internalType":"uint64","name":"_srcChainId","type":"uint64"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"address","name":"_executor","type":"address"}],"name":"executeMessage","outputs":[{"internalType":"enum IMessageReceiverApp.ExecutionStatus","name":"","type":"uint8"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"srcContract","type":"address"},{"internalType":"uint64","name":"_srcChainId","type":"uint64"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"address","name":"","type":"address"}],"name":"executeMessage","outputs":[{"internalType":"enum IMessageReceiverApp.ExecutionStatus","name":"","type":"uint8"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint64","name":"_srcChainId","type":"uint64"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"address","name":"_executor","type":"address"}],"name":"executeMessageWithTransfer","outputs":[{"internalType":"enum IMessageReceiverApp.ExecutionStatus","name":"","type":"uint8"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint64","name":"_srcChainId","type":"uint64"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"address","name":"_executor","type":"address"}],"name":"executeMessageWithTransferFallback","outputs":[{"internalType":"enum IMessageReceiverApp.ExecutionStatus","name":"","type":"uint8"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"address","name":"_executor","type":"address"}],"name":"executeMessageWithTransferRefund","outputs":[{"internalType":"enum IMessageReceiverApp.ExecutionStatus","name":"","type":"uint8"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint64","name":"chainId","type":"uint64"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"message","type":"bytes"}],"name":"lockAndMint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"messageBus","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"","type":"uint64"},{"internalType":"address","name":"","type":"address"}],"name":"mintedTokenByOriginal","outputs":[{"internalType":"contract CrossChainERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"","type":"uint64"},{"internalType":"contract CrossChainERC20","name":"","type":"address"}],"name":"originalTokenByMinted","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_endpoint","type":"address"}],"name":"setActualEndpoint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint64","name":"srcChainId","type":"uint64"},{"internalType":"bool","name":"isAllowed","type":"bool"}],"internalType":"struct CrossChainVaultApp.SetAllowedSender[]","name":"senders","type":"tuple[]"}],"name":"setAllowedSenders","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bool","name":"isDataSet","type":"bool"},{"internalType":"address","name":"token","type":"address"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint64","name":"chainId","type":"uint64"}],"internalType":"struct CrossChainVaultApp.CrossChainAssetData[]","name":"assets","type":"tuple[]"}],"name":"setCrossChainAssets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"contract ICrossChainVault","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]