文件 1 的 102: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 functionCall(target, data, "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");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(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) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(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) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 2 的 102:BatchTransfer.sol
pragma solidity 0.8.9;
import "../framework/MessageSenderApp.sol";
import "../framework/MessageReceiverApp.sol";
contract BatchTransfer is MessageSenderApp, MessageReceiverApp {
using SafeERC20 for IERC20;
struct TransferRequest {
uint64 nonce;
address[] accounts;
uint256[] amounts;
address sender;
}
enum TransferStatus {
Null,
Success,
Fail
}
struct TransferReceipt {
uint64 nonce;
TransferStatus status;
}
constructor(address _messageBus) {
messageBus = _messageBus;
}
uint64 nonce;
struct BatchTransferStatus {
bytes32 h;
TransferStatus status;
}
mapping(uint64 => BatchTransferStatus) public status;
modifier onlyEOA() {
require(msg.sender == tx.origin, "Not EOA");
_;
}
function batchTransfer(
address _receiver,
address _token,
uint256 _amount,
uint64 _dstChainId,
uint32 _maxSlippage,
MsgDataTypes.BridgeSendType _bridgeSendType,
address[] calldata _accounts,
uint256[] calldata _amounts
) external payable onlyEOA {
uint256 totalAmt;
for (uint256 i = 0; i < _amounts.length; i++) {
totalAmt += _amounts[i];
}
nonce += 1;
status[nonce] = BatchTransferStatus({
h: keccak256(abi.encodePacked(_receiver, _dstChainId)),
status: TransferStatus.Null
});
IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);
bytes memory message = abi.encode(
TransferRequest({nonce: nonce, accounts: _accounts, amounts: _amounts, sender: msg.sender})
);
sendMessageWithTransfer(
_receiver,
_token,
_amount,
_dstChainId,
nonce,
_maxSlippage,
message,
_bridgeSendType,
msg.value
);
}
function executeMessageWithTransferRefund(
address _token,
uint256 _amount,
bytes calldata _message,
address
) external payable override onlyMessageBus returns (ExecutionStatus) {
TransferRequest memory transfer = abi.decode((_message), (TransferRequest));
IERC20(_token).safeTransfer(transfer.sender, _amount);
return ExecutionStatus.Success;
}
function executeMessage(
address _sender,
uint64 _srcChainId,
bytes memory _message,
address
) external payable override onlyMessageBus returns (ExecutionStatus) {
TransferReceipt memory receipt = abi.decode((_message), (TransferReceipt));
require(status[receipt.nonce].h == keccak256(abi.encodePacked(_sender, _srcChainId)), "invalid message");
status[receipt.nonce].status = receipt.status;
return ExecutionStatus.Success;
}
function executeMessageWithTransfer(
address _sender,
address _token,
uint256 _amount,
uint64 _srcChainId,
bytes memory _message,
address
) external payable override onlyMessageBus returns (ExecutionStatus) {
TransferRequest memory transfer = abi.decode((_message), (TransferRequest));
uint256 totalAmt;
for (uint256 i = 0; i < transfer.accounts.length; i++) {
IERC20(_token).safeTransfer(transfer.accounts[i], transfer.amounts[i]);
totalAmt += transfer.amounts[i];
}
uint256 remainder = _amount - totalAmt;
if (_amount > totalAmt) {
IERC20(_token).safeTransfer(transfer.sender, remainder);
}
bytes memory message = abi.encode(TransferReceipt({nonce: transfer.nonce, status: TransferStatus.Success}));
sendMessage(_sender, _srcChainId, message, msg.value);
return ExecutionStatus.Success;
}
function executeMessageWithTransferFallback(
address _sender,
address _token,
uint256 _amount,
uint64 _srcChainId,
bytes memory _message,
address
) external payable override onlyMessageBus returns (ExecutionStatus) {
TransferRequest memory transfer = abi.decode((_message), (TransferRequest));
IERC20(_token).safeTransfer(transfer.sender, _amount);
bytes memory message = abi.encode(TransferReceipt({nonce: transfer.nonce, status: TransferStatus.Fail}));
sendMessage(_sender, _srcChainId, message, msg.value);
return ExecutionStatus.Success;
}
}
文件 3 的 102:Bridge.sol
pragma solidity 0.8.9;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "../libraries/PbBridge.sol";
import "./Pool.sol";
contract Bridge is Pool {
using SafeERC20 for IERC20;
event Send(
bytes32 transferId,
address sender,
address receiver,
address token,
uint256 amount,
uint64 dstChainId,
uint64 nonce,
uint32 maxSlippage
);
event Relay(
bytes32 transferId,
address sender,
address receiver,
address token,
uint256 amount,
uint64 srcChainId,
bytes32 srcTransferId
);
event MinSendUpdated(address token, uint256 amount);
event MaxSendUpdated(address token, uint256 amount);
mapping(bytes32 => bool) public transfers;
mapping(address => uint256) public minSend;
mapping(address => uint256) public maxSend;
uint32 public minimalMaxSlippage;
function send(
address _receiver,
address _token,
uint256 _amount,
uint64 _dstChainId,
uint64 _nonce,
uint32 _maxSlippage
) external nonReentrant whenNotPaused {
bytes32 transferId = _send(_receiver, _token, _amount, _dstChainId, _nonce, _maxSlippage);
IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);
emit Send(transferId, msg.sender, _receiver, _token, _amount, _dstChainId, _nonce, _maxSlippage);
}
function sendNative(
address _receiver,
uint256 _amount,
uint64 _dstChainId,
uint64 _nonce,
uint32 _maxSlippage
) external payable nonReentrant whenNotPaused {
require(msg.value == _amount, "Amount mismatch");
require(nativeWrap != address(0), "Native wrap not set");
bytes32 transferId = _send(_receiver, nativeWrap, _amount, _dstChainId, _nonce, _maxSlippage);
IWETH(nativeWrap).deposit{value: _amount}();
emit Send(transferId, msg.sender, _receiver, nativeWrap, _amount, _dstChainId, _nonce, _maxSlippage);
}
function _send(
address _receiver,
address _token,
uint256 _amount,
uint64 _dstChainId,
uint64 _nonce,
uint32 _maxSlippage
) private returns (bytes32) {
require(_amount > minSend[_token], "amount too small");
require(maxSend[_token] == 0 || _amount <= maxSend[_token], "amount too large");
require(_maxSlippage > minimalMaxSlippage, "max slippage too small");
bytes32 transferId = keccak256(
abi.encodePacked(msg.sender, _receiver, _token, _amount, _dstChainId, _nonce, uint64(block.chainid))
);
require(transfers[transferId] == false, "transfer exists");
transfers[transferId] = true;
return transferId;
}
function relay(
bytes calldata _relayRequest,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers
) external whenNotPaused {
bytes32 domain = keccak256(abi.encodePacked(block.chainid, address(this), "Relay"));
verifySigs(abi.encodePacked(domain, _relayRequest), _sigs, _signers, _powers);
PbBridge.Relay memory request = PbBridge.decRelay(_relayRequest);
bytes32 transferId = keccak256(
abi.encodePacked(
request.sender,
request.receiver,
request.token,
request.amount,
request.srcChainId,
request.dstChainId,
request.srcTransferId
)
);
require(transfers[transferId] == false, "transfer exists");
transfers[transferId] = true;
_updateVolume(request.token, request.amount);
uint256 delayThreshold = delayThresholds[request.token];
if (delayThreshold > 0 && request.amount > delayThreshold) {
_addDelayedTransfer(transferId, request.receiver, request.token, request.amount);
} else {
_sendToken(request.receiver, request.token, request.amount);
}
emit Relay(
transferId,
request.sender,
request.receiver,
request.token,
request.amount,
request.srcChainId,
request.srcTransferId
);
}
function setMinSend(address[] calldata _tokens, uint256[] calldata _amounts) external onlyGovernor {
require(_tokens.length == _amounts.length, "length mismatch");
for (uint256 i = 0; i < _tokens.length; i++) {
minSend[_tokens[i]] = _amounts[i];
emit MinSendUpdated(_tokens[i], _amounts[i]);
}
}
function setMaxSend(address[] calldata _tokens, uint256[] calldata _amounts) external onlyGovernor {
require(_tokens.length == _amounts.length, "length mismatch");
for (uint256 i = 0; i < _tokens.length; i++) {
maxSend[_tokens[i]] = _amounts[i];
emit MaxSendUpdated(_tokens[i], _amounts[i]);
}
}
function setMinimalMaxSlippage(uint32 _minimalMaxSlippage) external onlyGovernor {
minimalMaxSlippage = _minimalMaxSlippage;
}
receive() external payable {}
}
文件 4 的 102:BridgeTransferLib.sol
pragma solidity >=0.8.0;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "./PbBridge.sol";
import "./PbPegged.sol";
import "./PbPool.sol";
import "../interfaces/IBridge.sol";
import "../interfaces/IOriginalTokenVault.sol";
import "../interfaces/IOriginalTokenVaultV2.sol";
import "../interfaces/IPeggedTokenBridge.sol";
import "../interfaces/IPeggedTokenBridgeV2.sol";
library BridgeTransferLib {
using SafeERC20 for IERC20;
enum BridgeSendType {
Null,
Liquidity,
PegDeposit,
PegBurn,
PegV2Deposit,
PegV2Burn,
PegV2BurnFrom
}
enum BridgeReceiveType {
Null,
LqRelay,
LqWithdraw,
PegMint,
PegWithdraw,
PegV2Mint,
PegV2Withdraw
}
struct ReceiveInfo {
bytes32 transferId;
address receiver;
address token;
uint256 amount;
bytes32 refid;
}
function sendTransfer(
address _receiver,
address _token,
uint256 _amount,
uint64 _dstChainId,
uint64 _nonce,
uint32 _maxSlippage,
BridgeSendType _bridgeSendType,
address _bridgeAddr
) internal returns (bytes32) {
bytes32 transferId;
IERC20(_token).safeIncreaseAllowance(_bridgeAddr, _amount);
if (_bridgeSendType == BridgeSendType.Liquidity) {
IBridge(_bridgeAddr).send(_receiver, _token, _amount, _dstChainId, _nonce, _maxSlippage);
transferId = keccak256(
abi.encodePacked(address(this), _receiver, _token, _amount, _dstChainId, _nonce, uint64(block.chainid))
);
} else if (_bridgeSendType == BridgeSendType.PegDeposit) {
IOriginalTokenVault(_bridgeAddr).deposit(_token, _amount, _dstChainId, _receiver, _nonce);
transferId = keccak256(
abi.encodePacked(address(this), _token, _amount, _dstChainId, _receiver, _nonce, uint64(block.chainid))
);
} else if (_bridgeSendType == BridgeSendType.PegBurn) {
IPeggedTokenBridge(_bridgeAddr).burn(_token, _amount, _receiver, _nonce);
transferId = keccak256(
abi.encodePacked(address(this), _token, _amount, _receiver, _nonce, uint64(block.chainid))
);
IERC20(_token).safeApprove(_bridgeAddr, 0);
} else if (_bridgeSendType == BridgeSendType.PegV2Deposit) {
transferId = IOriginalTokenVaultV2(_bridgeAddr).deposit(_token, _amount, _dstChainId, _receiver, _nonce);
} else if (_bridgeSendType == BridgeSendType.PegV2Burn) {
transferId = IPeggedTokenBridgeV2(_bridgeAddr).burn(_token, _amount, _dstChainId, _receiver, _nonce);
IERC20(_token).safeApprove(_bridgeAddr, 0);
} else if (_bridgeSendType == BridgeSendType.PegV2BurnFrom) {
transferId = IPeggedTokenBridgeV2(_bridgeAddr).burnFrom(_token, _amount, _dstChainId, _receiver, _nonce);
IERC20(_token).safeApprove(_bridgeAddr, 0);
} else {
revert("bridge send type not supported");
}
return transferId;
}
function receiveTransfer(
bytes calldata _request,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers,
BridgeReceiveType _bridgeReceiveType,
address _bridgeAddr
) internal returns (ReceiveInfo memory) {
if (_bridgeReceiveType == BridgeReceiveType.LqRelay) {
return receiveLiquidityRelay(_request, _sigs, _signers, _powers, _bridgeAddr);
} else if (_bridgeReceiveType == BridgeReceiveType.LqWithdraw) {
return receiveLiquidityWithdraw(_request, _sigs, _signers, _powers, _bridgeAddr);
} else if (_bridgeReceiveType == BridgeReceiveType.PegWithdraw) {
return receivePegWithdraw(_request, _sigs, _signers, _powers, _bridgeAddr);
} else if (_bridgeReceiveType == BridgeReceiveType.PegMint) {
return receivePegMint(_request, _sigs, _signers, _powers, _bridgeAddr);
} else if (_bridgeReceiveType == BridgeReceiveType.PegV2Withdraw) {
return receivePegV2Withdraw(_request, _sigs, _signers, _powers, _bridgeAddr);
} else if (_bridgeReceiveType == BridgeReceiveType.PegV2Mint) {
return receivePegV2Mint(_request, _sigs, _signers, _powers, _bridgeAddr);
} else {
revert("bridge receive type not supported");
}
}
function receiveLiquidityRelay(
bytes calldata _request,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers,
address _bridgeAddr
) internal returns (ReceiveInfo memory) {
ReceiveInfo memory recv;
PbBridge.Relay memory request = PbBridge.decRelay(_request);
recv.transferId = keccak256(
abi.encodePacked(
request.sender,
request.receiver,
request.token,
request.amount,
request.srcChainId,
uint64(block.chainid),
request.srcTransferId
)
);
recv.refid = request.srcTransferId;
recv.receiver = request.receiver;
recv.token = request.token;
recv.amount = request.amount;
if (!IBridge(_bridgeAddr).transfers(recv.transferId)) {
IBridge(_bridgeAddr).relay(_request, _sigs, _signers, _powers);
}
return recv;
}
function receiveLiquidityWithdraw(
bytes calldata _request,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers,
address _bridgeAddr
) internal returns (ReceiveInfo memory) {
ReceiveInfo memory recv;
PbPool.WithdrawMsg memory request = PbPool.decWithdrawMsg(_request);
recv.transferId = keccak256(
abi.encodePacked(request.chainid, request.seqnum, request.receiver, request.token, request.amount)
);
recv.refid = request.refid;
recv.receiver = request.receiver;
recv.token = request.token;
recv.amount = request.amount;
if (!IBridge(_bridgeAddr).withdraws(recv.transferId)) {
IBridge(_bridgeAddr).withdraw(_request, _sigs, _signers, _powers);
}
return recv;
}
function receivePegWithdraw(
bytes calldata _request,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers,
address _bridgeAddr
) internal returns (ReceiveInfo memory) {
ReceiveInfo memory recv;
PbPegged.Withdraw memory request = PbPegged.decWithdraw(_request);
recv.transferId = keccak256(
abi.encodePacked(
request.receiver,
request.token,
request.amount,
request.burnAccount,
request.refChainId,
request.refId
)
);
recv.refid = request.refId;
recv.receiver = request.receiver;
recv.token = request.token;
recv.amount = request.amount;
if (!IOriginalTokenVault(_bridgeAddr).records(recv.transferId)) {
IOriginalTokenVault(_bridgeAddr).withdraw(_request, _sigs, _signers, _powers);
}
return recv;
}
function receivePegMint(
bytes calldata _request,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers,
address _bridgeAddr
) internal returns (ReceiveInfo memory) {
ReceiveInfo memory recv;
PbPegged.Mint memory request = PbPegged.decMint(_request);
recv.transferId = keccak256(
abi.encodePacked(
request.account,
request.token,
request.amount,
request.depositor,
request.refChainId,
request.refId
)
);
recv.refid = request.refId;
recv.receiver = request.account;
recv.token = request.token;
recv.amount = request.amount;
if (!IPeggedTokenBridge(_bridgeAddr).records(recv.transferId)) {
IPeggedTokenBridge(_bridgeAddr).mint(_request, _sigs, _signers, _powers);
}
return recv;
}
function receivePegV2Withdraw(
bytes calldata _request,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers,
address _bridgeAddr
) internal returns (ReceiveInfo memory) {
ReceiveInfo memory recv;
PbPegged.Withdraw memory request = PbPegged.decWithdraw(_request);
if (IOriginalTokenVaultV2(_bridgeAddr).records(request.refId)) {
recv.transferId = keccak256(
abi.encodePacked(
request.receiver,
request.token,
request.amount,
request.burnAccount,
request.refChainId,
request.refId,
_bridgeAddr
)
);
} else {
recv.transferId = IOriginalTokenVaultV2(_bridgeAddr).withdraw(_request, _sigs, _signers, _powers);
}
recv.refid = request.refId;
recv.receiver = request.receiver;
recv.token = request.token;
recv.amount = request.amount;
return recv;
}
function receivePegV2Mint(
bytes calldata _request,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers,
address _bridgeAddr
) internal returns (ReceiveInfo memory) {
ReceiveInfo memory recv;
PbPegged.Mint memory request = PbPegged.decMint(_request);
if (IPeggedTokenBridgeV2(_bridgeAddr).records(request.refId)) {
recv.transferId = keccak256(
abi.encodePacked(
request.account,
request.token,
request.amount,
request.depositor,
request.refChainId,
request.refId,
_bridgeAddr
)
);
} else {
recv.transferId = IPeggedTokenBridgeV2(_bridgeAddr).mint(_request, _sigs, _signers, _powers);
}
recv.refid = request.refId;
recv.receiver = request.account;
recv.token = request.token;
recv.amount = request.amount;
return recv;
}
function bridgeRefundType(BridgeSendType _bridgeSendType) internal pure returns (BridgeReceiveType) {
if (_bridgeSendType == BridgeSendType.Liquidity) {
return BridgeReceiveType.LqWithdraw;
}
if (_bridgeSendType == BridgeSendType.PegDeposit) {
return BridgeReceiveType.PegWithdraw;
}
if (_bridgeSendType == BridgeSendType.PegBurn) {
return BridgeReceiveType.PegMint;
}
if (_bridgeSendType == BridgeSendType.PegV2Deposit) {
return BridgeReceiveType.PegV2Withdraw;
}
if (_bridgeSendType == BridgeSendType.PegV2Burn || _bridgeSendType == BridgeSendType.PegV2BurnFrom) {
return BridgeReceiveType.PegV2Mint;
}
return BridgeReceiveType.Null;
}
}
文件 5 的 102: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;
}
}
文件 6 的 102:ContractAsLP.sol
pragma solidity 0.8.9;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "../interfaces/IPool.sol";
import "../interfaces/IWithdrawInbox.sol";
import "../safeguard/Pauser.sol";
contract ContractAsLP is ReentrancyGuard, Pauser {
using SafeERC20 for IERC20;
address public bridge;
address public inbox;
event Deposited(address depositor, address token, uint256 amount);
constructor(address _bridge, address _inbox) {
bridge = _bridge;
inbox = _inbox;
}
function deposit(address _token, uint256 _amount) external nonReentrant whenNotPaused onlyOwner {
IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);
emit Deposited(msg.sender, _token, _amount);
}
function addLiquidity(address _token, uint256 _amount) external whenNotPaused onlyOwner {
require(IERC20(_token).balanceOf(address(this)) >= _amount, "insufficient balance");
IERC20(_token).safeIncreaseAllowance(bridge, _amount);
IPool(bridge).addLiquidity(_token, _amount);
}
function withdraw(
uint64 _wdSeq,
address _receiver,
uint64 _toChain,
uint64[] calldata _fromChains,
address[] calldata _tokens,
uint32[] calldata _ratios,
uint32[] calldata _slippages
) external whenNotPaused onlyOwner {
IWithdrawInbox(inbox).withdraw(_wdSeq, _receiver, _toChain, _fromChains, _tokens, _ratios, _slippages);
}
}
文件 7 的 102:ContractAsSender.sol
pragma solidity 0.8.9;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "../libraries/BridgeTransferLib.sol";
import "../safeguard/Pauser.sol";
contract ContractAsSender is ReentrancyGuard, Pauser {
using SafeERC20 for IERC20;
mapping(BridgeTransferLib.BridgeSendType => address) public bridges;
mapping(bytes32 => address) public records;
event Deposited(address depositor, address token, uint256 amount);
event BridgeUpdated(BridgeTransferLib.BridgeSendType bridgeSendType, address bridgeAddr);
function transfer(
address _receiver,
address _token,
uint256 _amount,
uint64 _dstChainId,
uint64 _nonce,
uint32 _maxSlippage,
BridgeTransferLib.BridgeSendType _bridgeSendType
) external nonReentrant whenNotPaused onlyOwner returns (bytes32) {
address _bridgeAddr = bridges[_bridgeSendType];
require(_bridgeAddr != address(0), "unknown bridge type");
bytes32 transferId = BridgeTransferLib.sendTransfer(
_receiver,
_token,
_amount,
_dstChainId,
_nonce,
_maxSlippage,
_bridgeSendType,
_bridgeAddr
);
require(records[transferId] == address(0), "record exists");
records[transferId] = msg.sender;
return transferId;
}
function refund(
bytes calldata _request,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers,
BridgeTransferLib.BridgeSendType _bridgeSendType
) external nonReentrant whenNotPaused onlyOwner returns (bytes32) {
address _bridgeAddr = bridges[_bridgeSendType];
require(_bridgeAddr != address(0), "unknown bridge type");
BridgeTransferLib.ReceiveInfo memory refundInfo = BridgeTransferLib.receiveTransfer(
_request,
_sigs,
_signers,
_powers,
BridgeTransferLib.bridgeRefundType(_bridgeSendType),
_bridgeAddr
);
require(refundInfo.receiver == address(this), "invalid refund");
address _receiver = records[refundInfo.refid];
require(_receiver != address(0), "unknown transfer id or already refunded");
delete records[refundInfo.refid];
IERC20(refundInfo.token).safeTransfer(_receiver, refundInfo.amount);
return refundInfo.transferId;
}
function deposit(address _token, uint256 _amount) external nonReentrant whenNotPaused onlyOwner {
IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);
emit Deposited(msg.sender, _token, _amount);
}
function setBridgeAddress(BridgeTransferLib.BridgeSendType _bridgeSendType, address _addr) public onlyOwner {
require(_addr != address(0), "invalid address");
bridges[_bridgeSendType] = _addr;
emit BridgeUpdated(_bridgeSendType, _addr);
}
}
文件 8 的 102:Counters.sol
pragma solidity ^0.8.0;
library Counters {
struct Counter {
uint256 _value;
}
function current(Counter storage counter) internal view returns (uint256) {
return counter._value;
}
function increment(Counter storage counter) internal {
unchecked {
counter._value += 1;
}
}
function decrement(Counter storage counter) internal {
uint256 value = counter._value;
require(value > 0, "Counter: decrement overflow");
unchecked {
counter._value = value - 1;
}
}
function reset(Counter storage counter) internal {
counter._value = 0;
}
}
文件 9 的 102:DataTypes.sol
pragma solidity 0.8.9;
library DataTypes {
uint256 constant CELR_DECIMAL = 1e18;
uint256 constant MAX_INT = 2**256 - 1;
uint256 constant COMMISSION_RATE_BASE = 10000;
uint256 constant MAX_UNDELEGATION_ENTRIES = 10;
uint256 constant SLASH_FACTOR_DECIMAL = 1e6;
enum ValidatorStatus {
Null,
Unbonded,
Unbonding,
Bonded
}
enum ParamName {
ProposalDeposit,
VotingPeriod,
UnbondingPeriod,
MaxBondedValidators,
MinValidatorTokens,
MinSelfDelegation,
AdvanceNoticePeriod,
ValidatorBondInterval,
MaxSlashFactor
}
struct Undelegation {
uint256 shares;
uint256 creationBlock;
}
struct Undelegations {
mapping(uint256 => Undelegation) queue;
uint32 head;
uint32 tail;
}
struct Delegator {
uint256 shares;
Undelegations undelegations;
}
struct Validator {
ValidatorStatus status;
address signer;
uint256 tokens;
uint256 shares;
uint256 undelegationTokens;
uint256 undelegationShares;
mapping(address => Delegator) delegators;
uint256 minSelfDelegation;
uint64 bondBlock;
uint64 unbondBlock;
uint64 commissionRate;
}
struct ValidatorTokens {
address valAddr;
uint256 tokens;
}
struct ValidatorInfo {
address valAddr;
ValidatorStatus status;
address signer;
uint256 tokens;
uint256 shares;
uint256 minSelfDelegation;
uint64 commissionRate;
}
struct DelegatorInfo {
address valAddr;
uint256 tokens;
uint256 shares;
Undelegation[] undelegations;
uint256 undelegationTokens;
uint256 withdrawableUndelegationTokens;
}
}
文件 10 的 102:DelayedTransfer.sol
pragma solidity 0.8.9;
import "./Governor.sol";
abstract contract DelayedTransfer is Governor {
struct delayedTransfer {
address receiver;
address token;
uint256 amount;
uint256 timestamp;
}
mapping(bytes32 => delayedTransfer) public delayedTransfers;
mapping(address => uint256) public delayThresholds;
uint256 public delayPeriod;
event DelayedTransferAdded(bytes32 id);
event DelayedTransferExecuted(bytes32 id, address receiver, address token, uint256 amount);
event DelayPeriodUpdated(uint256 period);
event DelayThresholdUpdated(address token, uint256 threshold);
function setDelayThresholds(address[] calldata _tokens, uint256[] calldata _thresholds) external onlyGovernor {
require(_tokens.length == _thresholds.length, "length mismatch");
for (uint256 i = 0; i < _tokens.length; i++) {
delayThresholds[_tokens[i]] = _thresholds[i];
emit DelayThresholdUpdated(_tokens[i], _thresholds[i]);
}
}
function setDelayPeriod(uint256 _period) external onlyGovernor {
delayPeriod = _period;
emit DelayPeriodUpdated(_period);
}
function _addDelayedTransfer(
bytes32 id,
address receiver,
address token,
uint256 amount
) internal {
require(delayedTransfers[id].timestamp == 0, "delayed transfer already exists");
delayedTransfers[id] = delayedTransfer({
receiver: receiver,
token: token,
amount: amount,
timestamp: block.timestamp
});
emit DelayedTransferAdded(id);
}
function _executeDelayedTransfer(bytes32 id) internal returns (delayedTransfer memory) {
delayedTransfer memory transfer = delayedTransfers[id];
require(transfer.timestamp > 0, "delayed transfer not exist");
require(block.timestamp > transfer.timestamp + delayPeriod, "delayed transfer still locked");
delete delayedTransfers[id];
emit DelayedTransferExecuted(id, transfer.receiver, transfer.token, transfer.amount);
return transfer;
}
}
文件 11 的 102:DummySwap.sol
pragma solidity >=0.8.9;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
contract DummySwap {
using SafeERC20 for IERC20;
uint256 fakeSlippage;
uint256 hundredPercent = 100 * 1e4;
constructor(uint256 _fakeSlippage) {
fakeSlippage = _fakeSlippage;
}
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts) {
require(deadline != 0 && deadline > block.timestamp, "deadline exceeded");
require(path.length > 1, "path must have more than 1 token in it");
IERC20(path[0]).transferFrom(msg.sender, address(this), amountIn);
uint256 amountAfterSlippage = (amountIn * (hundredPercent - fakeSlippage)) / hundredPercent;
require(amountAfterSlippage > amountOutMin, "bad slippage");
IERC20(path[path.length - 1]).safeTransfer(to, amountAfterSlippage);
uint256[] memory ret = new uint256[](2);
ret[0] = amountIn;
ret[1] = amountAfterSlippage;
return ret;
}
function setFakeSlippage(uint256 _fakeSlippage) public {
fakeSlippage = _fakeSlippage;
}
}
文件 12 的 102:ECDSA.sol
pragma solidity ^0.8.0;
import "../Strings.sol";
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS,
InvalidSignatureV
}
function _throwError(RecoverError error) private pure {
if (error == RecoverError.NoError) {
return;
} else if (error == RecoverError.InvalidSignature) {
revert("ECDSA: invalid signature");
} else if (error == RecoverError.InvalidSignatureLength) {
revert("ECDSA: invalid signature length");
} else if (error == RecoverError.InvalidSignatureS) {
revert("ECDSA: invalid signature 's' value");
} else if (error == RecoverError.InvalidSignatureV) {
revert("ECDSA: invalid signature 'v' value");
}
}
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else if (signature.length == 64) {
bytes32 r;
bytes32 vs;
assembly {
r := mload(add(signature, 0x20))
vs := mload(add(signature, 0x40))
}
return tryRecover(hash, r, vs);
} else {
return (address(0), RecoverError.InvalidSignatureLength);
}
}
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, signature);
_throwError(error);
return recovered;
}
function tryRecover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address, RecoverError) {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
function recover(
bytes32 hash,
bytes32 r,
bytes32 vs
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, r, vs);
_throwError(error);
return recovered;
}
function tryRecover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address, RecoverError) {
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS);
}
if (v != 27 && v != 28) {
return (address(0), RecoverError.InvalidSignatureV);
}
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature);
}
return (signer, RecoverError.NoError);
}
function recover(
bytes32 hash,
uint8 v,
bytes32 r,
bytes32 s
) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, v, r, s);
_throwError(error);
return recovered;
}
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
}
function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
}
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
}
}
文件 13 的 102:ERC165.sol
pragma solidity ^0.8.0;
import "./IERC165.sol";
abstract contract ERC165 is IERC165 {
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
文件 14 的 102: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, _allowances[owner][spender] + addedValue);
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = _allowances[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;
_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 {}
}
文件 15 的 102:ERC20Burnable.sol
pragma solidity ^0.8.0;
import "../ERC20.sol";
import "../../../utils/Context.sol";
abstract contract ERC20Burnable is Context, ERC20 {
function burn(uint256 amount) public virtual {
_burn(_msgSender(), amount);
}
function burnFrom(address account, uint256 amount) public virtual {
_spendAllowance(account, _msgSender(), amount);
_burn(account, amount);
}
}
文件 16 的 102:ERC721.sol
pragma solidity ^0.8.0;
import "./IERC721.sol";
import "./IERC721Receiver.sol";
import "./extensions/IERC721Metadata.sol";
import "../../utils/Address.sol";
import "../../utils/Context.sol";
import "../../utils/Strings.sol";
import "../../utils/introspection/ERC165.sol";
contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
using Address for address;
using Strings for uint256;
string private _name;
string private _symbol;
mapping(uint256 => address) private _owners;
mapping(address => uint256) private _balances;
mapping(uint256 => address) private _tokenApprovals;
mapping(address => mapping(address => bool)) private _operatorApprovals;
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return
interfaceId == type(IERC721).interfaceId ||
interfaceId == type(IERC721Metadata).interfaceId ||
super.supportsInterface(interfaceId);
}
function balanceOf(address owner) public view virtual override returns (uint256) {
require(owner != address(0), "ERC721: balance query for the zero address");
return _balances[owner];
}
function ownerOf(uint256 tokenId) public view virtual override returns (address) {
address owner = _owners[tokenId];
require(owner != address(0), "ERC721: owner query for nonexistent token");
return owner;
}
function name() public view virtual override returns (string memory) {
return _name;
}
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
string memory baseURI = _baseURI();
return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
}
function _baseURI() internal view virtual returns (string memory) {
return "";
}
function approve(address to, uint256 tokenId) public virtual override {
address owner = ERC721.ownerOf(tokenId);
require(to != owner, "ERC721: approval to current owner");
require(
_msgSender() == owner || isApprovedForAll(owner, _msgSender()),
"ERC721: approve caller is not owner nor approved for all"
);
_approve(to, tokenId);
}
function getApproved(uint256 tokenId) public view virtual override returns (address) {
require(_exists(tokenId), "ERC721: approved query for nonexistent token");
return _tokenApprovals[tokenId];
}
function setApprovalForAll(address operator, bool approved) public virtual override {
_setApprovalForAll(_msgSender(), operator, approved);
}
function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
return _operatorApprovals[owner][operator];
}
function transferFrom(
address from,
address to,
uint256 tokenId
) public virtual override {
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
_transfer(from, to, tokenId);
}
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) public virtual override {
safeTransferFrom(from, to, tokenId, "");
}
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes memory _data
) public virtual override {
require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
_safeTransfer(from, to, tokenId, _data);
}
function _safeTransfer(
address from,
address to,
uint256 tokenId,
bytes memory _data
) internal virtual {
_transfer(from, to, tokenId);
require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
}
function _exists(uint256 tokenId) internal view virtual returns (bool) {
return _owners[tokenId] != address(0);
}
function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
require(_exists(tokenId), "ERC721: operator query for nonexistent token");
address owner = ERC721.ownerOf(tokenId);
return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
}
function _safeMint(address to, uint256 tokenId) internal virtual {
_safeMint(to, tokenId, "");
}
function _safeMint(
address to,
uint256 tokenId,
bytes memory _data
) internal virtual {
_mint(to, tokenId);
require(
_checkOnERC721Received(address(0), to, tokenId, _data),
"ERC721: transfer to non ERC721Receiver implementer"
);
}
function _mint(address to, uint256 tokenId) internal virtual {
require(to != address(0), "ERC721: mint to the zero address");
require(!_exists(tokenId), "ERC721: token already minted");
_beforeTokenTransfer(address(0), to, tokenId);
_balances[to] += 1;
_owners[tokenId] = to;
emit Transfer(address(0), to, tokenId);
_afterTokenTransfer(address(0), to, tokenId);
}
function _burn(uint256 tokenId) internal virtual {
address owner = ERC721.ownerOf(tokenId);
_beforeTokenTransfer(owner, address(0), tokenId);
_approve(address(0), tokenId);
_balances[owner] -= 1;
delete _owners[tokenId];
emit Transfer(owner, address(0), tokenId);
_afterTokenTransfer(owner, address(0), tokenId);
}
function _transfer(
address from,
address to,
uint256 tokenId
) internal virtual {
require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner");
require(to != address(0), "ERC721: transfer to the zero address");
_beforeTokenTransfer(from, to, tokenId);
_approve(address(0), tokenId);
_balances[from] -= 1;
_balances[to] += 1;
_owners[tokenId] = to;
emit Transfer(from, to, tokenId);
_afterTokenTransfer(from, to, tokenId);
}
function _approve(address to, uint256 tokenId) internal virtual {
_tokenApprovals[tokenId] = to;
emit Approval(ERC721.ownerOf(tokenId), to, tokenId);
}
function _setApprovalForAll(
address owner,
address operator,
bool approved
) internal virtual {
require(owner != operator, "ERC721: approve to caller");
_operatorApprovals[owner][operator] = approved;
emit ApprovalForAll(owner, operator, approved);
}
function _checkOnERC721Received(
address from,
address to,
uint256 tokenId,
bytes memory _data
) private returns (bool) {
if (to.isContract()) {
try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) {
return retval == IERC721Receiver.onERC721Received.selector;
} catch (bytes memory reason) {
if (reason.length == 0) {
revert("ERC721: transfer to non ERC721Receiver implementer");
} else {
assembly {
revert(add(32, reason), mload(reason))
}
}
}
} else {
return true;
}
}
function _beforeTokenTransfer(
address from,
address to,
uint256 tokenId
) internal virtual {}
function _afterTokenTransfer(
address from,
address to,
uint256 tokenId
) internal virtual {}
}
文件 17 的 102:ERC721URIStorage.sol
pragma solidity ^0.8.0;
import "../ERC721.sol";
abstract contract ERC721URIStorage is ERC721 {
using Strings for uint256;
mapping(uint256 => string) private _tokenURIs;
function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
require(_exists(tokenId), "ERC721URIStorage: URI query for nonexistent token");
string memory _tokenURI = _tokenURIs[tokenId];
string memory base = _baseURI();
if (bytes(base).length == 0) {
return _tokenURI;
}
if (bytes(_tokenURI).length > 0) {
return string(abi.encodePacked(base, _tokenURI));
}
return super.tokenURI(tokenId);
}
function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual {
require(_exists(tokenId), "ERC721URIStorage: URI set of nonexistent token");
_tokenURIs[tokenId] = _tokenURI;
}
function _burn(uint256 tokenId) internal virtual override {
super._burn(tokenId);
if (bytes(_tokenURIs[tokenId]).length != 0) {
delete _tokenURIs[tokenId];
}
}
}
文件 18 的 102:FarmingRewards.sol
pragma solidity 0.8.9;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "../interfaces/ISigsVerifier.sol";
import "../libraries/PbFarming.sol";
import "../safeguard/Pauser.sol";
contract FarmingRewards is Pauser {
using SafeERC20 for IERC20;
ISigsVerifier public immutable sigsVerifier;
mapping(address => mapping(address => uint256)) public claimedRewardAmounts;
event FarmingRewardClaimed(address indexed recipient, address indexed token, uint256 reward);
event FarmingRewardContributed(address indexed contributor, address indexed token, uint256 contribution);
constructor(ISigsVerifier _sigsVerifier) {
sigsVerifier = _sigsVerifier;
}
function claimRewards(
bytes calldata _rewardsRequest,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers
) external whenNotPaused {
bytes32 domain = keccak256(abi.encodePacked(block.chainid, address(this), "FarmingRewards"));
sigsVerifier.verifySigs(abi.encodePacked(domain, _rewardsRequest), _sigs, _signers, _powers);
PbFarming.FarmingRewards memory rewards = PbFarming.decFarmingRewards(_rewardsRequest);
bool hasNewReward;
for (uint256 i = 0; i < rewards.tokenAddresses.length; i++) {
address token = rewards.tokenAddresses[i];
uint256 cumulativeRewardAmount = rewards.cumulativeRewardAmounts[i];
uint256 newReward = cumulativeRewardAmount - claimedRewardAmounts[rewards.recipient][token];
if (newReward > 0) {
hasNewReward = true;
claimedRewardAmounts[rewards.recipient][token] = cumulativeRewardAmount;
IERC20(token).safeTransfer(rewards.recipient, newReward);
emit FarmingRewardClaimed(rewards.recipient, token, newReward);
}
}
require(hasNewReward, "No new reward");
}
function contributeToRewardPool(address _token, uint256 _amount) external whenNotPaused {
address contributor = msg.sender;
IERC20(_token).safeTransferFrom(contributor, address(this), _amount);
emit FarmingRewardContributed(contributor, _token, _amount);
}
function drainToken(address _token, uint256 _amount) external whenPaused onlyOwner {
IERC20(_token).safeTransfer(msg.sender, _amount);
}
}
文件 19 的 102:Faucet.sol
pragma solidity 0.8.9;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
contract Faucet is Ownable {
using SafeERC20 for IERC20;
uint256 public minDripBlkInterval;
mapping(address => uint256) public lastDripBlk;
function drip(address[] calldata tokens) public {
require(block.number - lastDripBlk[msg.sender] >= minDripBlkInterval, "too frequent");
for (uint256 i = 0; i < tokens.length; i++) {
IERC20 token = IERC20(tokens[i]);
uint256 balance = token.balanceOf(address(this));
require(balance > 0, "Faucet is empty");
token.safeTransfer(msg.sender, balance / 10000);
}
lastDripBlk[msg.sender] = block.number;
}
function setMinDripBlkInterval(uint256 _interval) external onlyOwner {
minDripBlkInterval = _interval;
}
function drainToken(address _asset, uint256 _amount) external onlyOwner {
IERC20(_asset).safeTransfer(msg.sender, _amount);
}
}
文件 20 的 102:FraxBridgeToken.sol
pragma solidity >=0.8.9;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
interface IFraxCanoToken {
function exchangeOldForCanonical(address, uint256) external returns (uint256);
function exchangeCanonicalForOld(address, uint256) external returns (uint256);
}
contract FraxBridgeToken is ERC20, Ownable {
using SafeERC20 for IERC20;
address public bridge;
address public immutable canonical;
event BridgeUpdated(address bridge);
modifier onlyBridge() {
require(msg.sender == bridge, "caller is not bridge");
_;
}
constructor(
string memory name_,
string memory symbol_,
address bridge_,
address canonical_
) ERC20(name_, symbol_) {
bridge = bridge_;
canonical = canonical_;
}
function mint(address _to, uint256 _amount) external onlyBridge returns (bool) {
_mint(address(this), _amount);
_approve(address(this), canonical, _amount);
uint256 got = IFraxCanoToken(canonical).exchangeOldForCanonical(address(this), _amount);
IERC20(canonical).safeTransfer(_to, got);
return true;
}
function burn(address _from, uint256 _amount) external onlyBridge returns (bool) {
IERC20(canonical).safeTransferFrom(_from, address(this), _amount);
uint256 got = IFraxCanoToken(canonical).exchangeCanonicalForOld(address(this), _amount);
_burn(address(this), got);
return true;
}
function updateBridge(address _bridge) external onlyOwner {
bridge = _bridge;
emit BridgeUpdated(bridge);
}
function decimals() public view virtual override returns (uint8) {
return ERC20(canonical).decimals();
}
function getOwner() external view returns (address) {
return owner();
}
}
文件 21 的 102:Freezable.sol
pragma solidity 0.8.9;
abstract contract Freezable {
event Frozen(address account);
event Unfrozen(address account);
mapping(address => bool) internal freezes;
function isFrozen(address _account) public view virtual returns (bool) {
return freezes[_account];
}
modifier whenAccountNotFrozen(address _account) {
require(!isFrozen(_account), "Freezable: frozen");
_;
}
modifier whenAccountFrozen(address _account) {
require(isFrozen(_account), "Freezable: not frozen");
_;
}
}
文件 22 的 102:Govern.sol
pragma solidity 0.8.9;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {DataTypes as dt} from "./DataTypes.sol";
import "./Staking.sol";
contract Govern {
using SafeERC20 for IERC20;
Staking public immutable staking;
IERC20 public immutable celerToken;
enum ProposalStatus {
Uninitiated,
Voting,
Closed
}
enum VoteOption {
Null,
Yes,
Abstain,
No
}
struct ParamProposal {
address proposer;
uint256 deposit;
uint256 voteDeadline;
dt.ParamName name;
uint256 newValue;
ProposalStatus status;
mapping(address => VoteOption) votes;
}
mapping(uint256 => ParamProposal) public paramProposals;
uint256 public nextParamProposalId;
uint256 public forfeiture;
address public immutable collector;
event CreateParamProposal(
uint256 proposalId,
address proposer,
uint256 deposit,
uint256 voteDeadline,
dt.ParamName name,
uint256 newValue
);
event VoteParam(uint256 proposalId, address voter, VoteOption vote);
event ConfirmParamProposal(uint256 proposalId, bool passed, dt.ParamName name, uint256 newValue);
constructor(
Staking _staking,
address _celerTokenAddress,
address _collector
) {
staking = _staking;
celerToken = IERC20(_celerTokenAddress);
collector = _collector;
}
function getParamProposalVote(uint256 _proposalId, address _voter) public view returns (VoteOption) {
return paramProposals[_proposalId].votes[_voter];
}
function createParamProposal(dt.ParamName _name, uint256 _value) external {
ParamProposal storage p = paramProposals[nextParamProposalId];
nextParamProposalId = nextParamProposalId + 1;
address msgSender = msg.sender;
uint256 deposit = staking.getParamValue(dt.ParamName.ProposalDeposit);
p.proposer = msgSender;
p.deposit = deposit;
p.voteDeadline = block.number + staking.getParamValue(dt.ParamName.VotingPeriod);
p.name = _name;
p.newValue = _value;
p.status = ProposalStatus.Voting;
celerToken.safeTransferFrom(msgSender, address(this), deposit);
emit CreateParamProposal(nextParamProposalId - 1, msgSender, deposit, p.voteDeadline, _name, _value);
}
function voteParam(uint256 _proposalId, VoteOption _vote) external {
address valAddr = msg.sender;
require(staking.getValidatorStatus(valAddr) == dt.ValidatorStatus.Bonded, "Voter is not a bonded validator");
ParamProposal storage p = paramProposals[_proposalId];
require(p.status == ProposalStatus.Voting, "Invalid proposal status");
require(block.number < p.voteDeadline, "Vote deadline passed");
require(p.votes[valAddr] == VoteOption.Null, "Voter has voted");
require(_vote != VoteOption.Null, "Invalid vote");
p.votes[valAddr] = _vote;
emit VoteParam(_proposalId, valAddr, _vote);
}
function confirmParamProposal(uint256 _proposalId) external {
uint256 yesVotes;
uint256 bondedTokens;
dt.ValidatorTokens[] memory validators = staking.getBondedValidatorsTokens();
for (uint32 i = 0; i < validators.length; i++) {
if (getParamProposalVote(_proposalId, validators[i].valAddr) == VoteOption.Yes) {
yesVotes += validators[i].tokens;
}
bondedTokens += validators[i].tokens;
}
bool passed = (yesVotes >= (bondedTokens * 2) / 3 + 1);
ParamProposal storage p = paramProposals[_proposalId];
require(p.status == ProposalStatus.Voting, "Invalid proposal status");
require(block.number >= p.voteDeadline, "Vote deadline not reached");
p.status = ProposalStatus.Closed;
if (passed) {
staking.setParamValue(p.name, p.newValue);
celerToken.safeTransfer(p.proposer, p.deposit);
} else {
forfeiture += p.deposit;
}
emit ConfirmParamProposal(_proposalId, passed, p.name, p.newValue);
}
function collectForfeiture() external {
require(forfeiture > 0, "Nothing to collect");
celerToken.safeTransfer(collector, forfeiture);
forfeiture = 0;
}
}
文件 23 的 102:Governor.sol
pragma solidity 0.8.9;
import "./Ownable.sol";
abstract contract Governor is Ownable {
mapping(address => bool) public governors;
event GovernorAdded(address account);
event GovernorRemoved(address account);
modifier onlyGovernor() {
require(isGovernor(msg.sender), "Caller is not governor");
_;
}
constructor() {
_addGovernor(msg.sender);
}
function isGovernor(address _account) public view returns (bool) {
return governors[_account];
}
function addGovernor(address _account) public onlyOwner {
_addGovernor(_account);
}
function removeGovernor(address _account) public onlyOwner {
_removeGovernor(_account);
}
function renounceGovernor() public {
_removeGovernor(msg.sender);
}
function _addGovernor(address _account) private {
require(!isGovernor(_account), "Account is already governor");
governors[_account] = true;
emit GovernorAdded(_account);
}
function _removeGovernor(address _account) private {
require(isGovernor(_account), "Account is not governor");
governors[_account] = false;
emit GovernorRemoved(_account);
}
}
文件 24 的 102: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 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;
}
文件 25 的 102:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 26 的 102:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
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);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
文件 27 的 102: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);
}
文件 28 的 102:IERC721.sol
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
interface IERC721 is IERC165 {
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
function balanceOf(address owner) external view returns (uint256 balance);
function ownerOf(uint256 tokenId) external view returns (address owner);
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external;
function transferFrom(
address from,
address to,
uint256 tokenId
) external;
function approve(address to, uint256 tokenId) external;
function getApproved(uint256 tokenId) external view returns (address operator);
function setApprovalForAll(address operator, bool _approved) external;
function isApprovedForAll(address owner, address operator) external view returns (bool);
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes calldata data
) external;
}
文件 29 的 102:IERC721Metadata.sol
pragma solidity ^0.8.0;
import "../IERC721.sol";
interface IERC721Metadata is IERC721 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function tokenURI(uint256 tokenId) external view returns (string memory);
}
文件 30 的 102:IERC721Receiver.sol
pragma solidity ^0.8.0;
interface IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
文件 31 的 102:IMessageBus.sol
pragma solidity >=0.8.0;
import "../libraries/MsgDataTypes.sol";
interface IMessageBus {
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);
function calcFee(bytes calldata _message) external view returns (uint256);
function sendMessage(
address _receiver,
uint256 _dstChainId,
bytes calldata _message
) external payable;
function sendMessageWithTransfer(
address _receiver,
uint256 _dstChainId,
address _srcBridge,
bytes32 _srcTransferId,
bytes calldata _message
) external payable;
function withdrawFee(
address _account,
uint256 _cumulativeFee,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers
) external;
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 executeMessage(
bytes calldata _message,
MsgDataTypes.RouteInfo calldata _route,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers
) external payable;
}
文件 32 的 102:IMessageReceiverApp.sol
pragma solidity >=0.8.0;
interface IMessageReceiverApp {
enum ExecutionStatus {
Fail,
Success,
Retry
}
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);
function executeMessage(
address _sender,
uint64 _srcChainId,
bytes calldata _message,
address _executor
) external payable returns (ExecutionStatus);
}
文件 33 的 102:IOriginalTokenVault.sol
pragma solidity >=0.8.0;
interface IOriginalTokenVault {
function deposit(
address _token,
uint256 _amount,
uint64 _mintChainId,
address _mintAccount,
uint64 _nonce
) external;
function withdraw(
bytes calldata _request,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers
) external;
function records(bytes32 recordId) external view returns (bool);
}
文件 34 的 102: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 withdraw(
bytes calldata _request,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers
) external returns (bytes32);
function records(bytes32 recordId) external view returns (bool);
}
文件 35 的 102:IPeggedToken.sol
pragma solidity >=0.8.0;
interface IPeggedToken {
function mint(address _to, uint256 _amount) external;
function burn(address _from, uint256 _amount) external;
}
文件 36 的 102: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);
}
文件 37 的 102: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);
}
文件 38 的 102:IPeggedTokenBurnFrom.sol
pragma solidity >=0.8.0;
interface IPeggedTokenBurnFrom {
function mint(address _to, uint256 _amount) external;
function burnFrom(address _from, uint256 _amount) external;
}
文件 39 的 102:IPool.sol
pragma solidity >=0.8.0;
interface IPool {
function addLiquidity(address _token, uint256 _amount) external;
function withdraws(bytes32 withdrawId) external view returns (bool);
function withdraw(
bytes calldata _wdmsg,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers
) external;
}
文件 40 的 102: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;
}
文件 41 的 102:IUniswapV2.sol
pragma solidity >=0.8.0;
interface IUniswapV2 {
function swapTokensForExactTokens(
uint256 amountOut,
uint256 amountInMax,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
function swapExactTokensForTokens(
uint256 amountIn,
uint256 amountOutMin,
address[] calldata path,
address to,
uint256 deadline
) external returns (uint256[] memory amounts);
}
文件 42 的 102:IWETH.sol
pragma solidity >=0.8.0;
interface IWETH {
function deposit() external payable;
function withdraw(uint256) external;
}
文件 43 的 102:IWithdrawInbox.sol
pragma solidity >=0.8.0;
interface IWithdrawInbox {
function withdraw(
uint64 _wdSeq,
address _receiver,
uint64 _toChain,
uint64[] calldata _fromChains,
address[] calldata _tokens,
uint32[] calldata _ratios,
uint32[] calldata _slippages
) external;
}
文件 44 的 102:MCNNFT.sol
pragma solidity 0.8.9;
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "../../safeguard/Pauser.sol";
interface INFTBridge {
function sendMsg(
uint64 _dstChid,
address _sender,
address _receiver,
uint256 _id,
string calldata _uri
) external payable;
function sendMsg(
uint64 _dstChid,
address _sender,
bytes calldata _receiver,
uint256 _id,
string calldata _uri
) external payable;
function totalFee(
uint64 _dstChid,
address _nft,
uint256 _id
) external view returns (uint256);
}
contract MCNNFT is ERC721URIStorage, Pauser {
event NFTBridgeUpdated(address);
address public nftBridge;
constructor(
string memory name_,
string memory symbol_,
address _nftBridge
) ERC721(name_, symbol_) {
nftBridge = _nftBridge;
}
modifier onlyNftBridge() {
require(msg.sender == nftBridge, "caller is not bridge");
_;
}
function bridgeMint(
address to,
uint256 id,
string memory uri
) external onlyNftBridge {
_mint(to, id);
_setTokenURI(id, uri);
}
function totalFee(uint64 _dstChid, uint256 _id) external view returns (uint256) {
return INFTBridge(nftBridge).totalFee(_dstChid, address(this), _id);
}
function crossChain(
uint64 _dstChid,
uint256 _id,
address _receiver
) external payable whenNotPaused {
require(msg.sender == ownerOf(_id), "not token owner");
string memory _uri = tokenURI(_id);
_burn(_id);
INFTBridge(nftBridge).sendMsg{value: msg.value}(_dstChid, msg.sender, _receiver, _id, _uri);
}
function crossChain(
uint64 _dstChid,
uint256 _id,
bytes calldata _receiver
) external payable whenNotPaused {
require(msg.sender == ownerOf(_id), "not token owner");
string memory _uri = tokenURI(_id);
_burn(_id);
INFTBridge(nftBridge).sendMsg{value: msg.value}(_dstChid, msg.sender, _receiver, _id, _uri);
}
function mint(
address to,
uint256 id,
string memory uri
) external onlyOwner {
_mint(to, id);
_setTokenURI(id, uri);
}
function setNFTBridge(address _newBridge) public onlyOwner {
nftBridge = _newBridge;
emit NFTBridgeUpdated(_newBridge);
}
}
文件 45 的 102:MaiBridgeToken.sol
pragma solidity >=0.8.9;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
interface IMaiBridgeHub {
function swapIn(address, uint256) external;
function swapOut(address, uint256) external;
function asset() external view returns (address);
}
contract MaiBridgeToken is ERC20, Ownable {
using SafeERC20 for IERC20;
address public bridge;
address public immutable maihub;
address public immutable asset;
event BridgeUpdated(address bridge);
modifier onlyBridge() {
require(msg.sender == bridge, "caller is not bridge");
_;
}
constructor(
string memory name_,
string memory symbol_,
address bridge_,
address maihub_
) ERC20(name_, symbol_) {
bridge = bridge_;
maihub = maihub_;
asset = IMaiBridgeHub(maihub_).asset();
}
function mint(address _to, uint256 _amount) external onlyBridge returns (bool) {
_mint(address(this), _amount);
_approve(address(this), maihub, _amount);
IMaiBridgeHub(maihub).swapIn(address(this), _amount);
IERC20(asset).safeTransfer(_to, _amount);
return true;
}
function burn(address _from, uint256 _amount) external onlyBridge returns (bool) {
IERC20(asset).safeTransferFrom(_from, address(this), _amount);
IERC20(asset).safeIncreaseAllowance(address(maihub), _amount);
IMaiBridgeHub(maihub).swapOut(address(this), _amount);
_burn(address(this), _amount);
return true;
}
function updateBridge(address _bridge) external onlyOwner {
bridge = _bridge;
emit BridgeUpdated(bridge);
}
function decimals() public view virtual override returns (uint8) {
return ERC20(asset).decimals();
}
function getOwner() external view returns (address) {
return owner();
}
}
文件 46 的 102:MessageBus.sol
pragma solidity 0.8.9;
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);
}
}
文件 47 的 102:MessageBusAddress.sol
pragma solidity >=0.8.0;
import "../../safeguard/Ownable.sol";
abstract contract MessageBusAddress is Ownable {
event MessageBusUpdated(address messageBus);
address public messageBus;
function setMessageBus(address _messageBus) public onlyOwner {
messageBus = _messageBus;
emit MessageBusUpdated(messageBus);
}
}
文件 48 的 102:MessageBusReceiver.sol
pragma solidity 0.8.9;
import "../libraries/MsgDataTypes.sol";
import "../interfaces/IMessageReceiverApp.sol";
import "../interfaces/IMessageBus.sol";
import "../../interfaces/IBridge.sol";
import "../../interfaces/IOriginalTokenVault.sol";
import "../../interfaces/IOriginalTokenVaultV2.sol";
import "../../interfaces/IPeggedTokenBridge.sol";
import "../../interfaces/IPeggedTokenBridgeV2.sol";
import "../../safeguard/Ownable.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 {
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), "Message"));
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.RouteInfo calldata _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;
if (_transfer.t == MsgDataTypes.TransferType.LqRelay) {
transferId = keccak256(
abi.encodePacked(
_transfer.sender,
_transfer.receiver,
_transfer.token,
_transfer.amount,
_transfer.srcChainId,
uint64(block.chainid),
_transfer.refId
)
);
bridgeAddr = liquidityBridge;
require(IBridge(bridgeAddr).transfers(transferId) == true, "bridge relay not exist");
} else if (_transfer.t == MsgDataTypes.TransferType.LqWithdraw) {
transferId = keccak256(
abi.encodePacked(
uint64(block.chainid),
_transfer.wdseq,
_transfer.receiver,
_transfer.token,
_transfer.amount
)
);
bridgeAddr = liquidityBridge;
require(IBridge(bridgeAddr).withdraws(transferId) == true, "bridge withdraw not exist");
} else if (
_transfer.t == MsgDataTypes.TransferType.PegMint || _transfer.t == MsgDataTypes.TransferType.PegWithdraw
) {
transferId = keccak256(
abi.encodePacked(
_transfer.receiver,
_transfer.token,
_transfer.amount,
_transfer.sender,
_transfer.srcChainId,
_transfer.refId
)
);
if (_transfer.t == MsgDataTypes.TransferType.PegMint) {
bridgeAddr = pegBridge;
require(IPeggedTokenBridge(bridgeAddr).records(transferId) == true, "mint record not exist");
} else {
bridgeAddr = pegVault;
require(IOriginalTokenVault(bridgeAddr).records(transferId) == true, "withdraw record not exist");
}
} else if (
_transfer.t == MsgDataTypes.TransferType.PegV2Mint || _transfer.t == MsgDataTypes.TransferType.PegV2Withdraw
) {
if (_transfer.t == MsgDataTypes.TransferType.PegV2Mint) {
bridgeAddr = pegBridgeV2;
} else {
bridgeAddr = pegVaultV2;
}
transferId = keccak256(
abi.encodePacked(
_transfer.receiver,
_transfer.token,
_transfer.amount,
_transfer.sender,
_transfer.srcChainId,
_transfer.refId,
bridgeAddr
)
);
if (_transfer.t == MsgDataTypes.TransferType.PegV2Mint) {
require(IPeggedTokenBridgeV2(bridgeAddr).records(transferId) == true, "mint record not exist");
} else {
require(IOriginalTokenVaultV2(bridgeAddr).records(transferId) == true, "withdraw record not exist");
}
}
return keccak256(abi.encodePacked(MsgDataTypes.MsgType.MessageWithTransfer, bridgeAddr, transferId));
}
function computeMessageOnlyId(MsgDataTypes.RouteInfo calldata _route, bytes calldata _message)
private
view
returns (bytes32)
{
return
keccak256(
abi.encodePacked(
MsgDataTypes.MsgType.MessageOnly,
_route.sender,
_route.receiver,
_route.srcChainId,
_route.srcTxHash,
uint64(block.chainid),
_message
)
);
}
function executeMessage(MsgDataTypes.RouteInfo calldata _route, bytes calldata _message)
private
returns (IMessageReceiverApp.ExecutionStatus)
{
uint256 gasLeftBeforeExecution = gasleft();
(bool ok, bytes memory res) = address(_route.receiver).call{value: msg.value}(
abi.encodeWithSelector(
IMessageReceiverApp.executeMessage.selector,
_route.sender,
_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()
}
}
emit CallReverted(getRevertMsg(_returnData));
}
function getRevertMsg(bytes memory _returnData) private pure returns (string memory) {
if (_returnData.length < 68) return "Transaction reverted silently";
assembly {
_returnData := add(_returnData, 0x04)
}
return abi.decode(_returnData, (string));
}
function transferAndExecuteMsg(
MsgDataTypes.BridgeTransferParams calldata _transferParams,
MsgDataTypes.MsgWithTransferExecutionParams calldata _msgParams
) external {
_bridgeTransfer(_msgParams.transfer.t, _transferParams);
executeMessageWithTransfer(
_msgParams.message,
_msgParams.transfer,
_msgParams.sigs,
_msgParams.signers,
_msgParams.powers
);
}
function refundAndExecuteMsg(
MsgDataTypes.BridgeTransferParams calldata _transferParams,
MsgDataTypes.MsgWithTransferExecutionParams calldata _msgParams
) external {
_bridgeTransfer(_msgParams.transfer.t, _transferParams);
executeMessageWithTransferRefund(
_msgParams.message,
_msgParams.transfer,
_msgParams.sigs,
_msgParams.signers,
_msgParams.powers
);
}
function _bridgeTransfer(MsgDataTypes.TransferType t, MsgDataTypes.BridgeTransferParams calldata _transferParams)
private
{
if (t == MsgDataTypes.TransferType.LqRelay) {
IBridge(liquidityBridge).relay(
_transferParams.request,
_transferParams.sigs,
_transferParams.signers,
_transferParams.powers
);
} else if (t == MsgDataTypes.TransferType.LqWithdraw) {
IBridge(liquidityBridge).withdraw(
_transferParams.request,
_transferParams.sigs,
_transferParams.signers,
_transferParams.powers
);
} else if (t == MsgDataTypes.TransferType.PegMint) {
IPeggedTokenBridge(pegBridge).mint(
_transferParams.request,
_transferParams.sigs,
_transferParams.signers,
_transferParams.powers
);
} else if (t == MsgDataTypes.TransferType.PegV2Mint) {
IPeggedTokenBridgeV2(pegBridgeV2).mint(
_transferParams.request,
_transferParams.sigs,
_transferParams.signers,
_transferParams.powers
);
} else if (t == MsgDataTypes.TransferType.PegWithdraw) {
IOriginalTokenVault(pegVault).withdraw(
_transferParams.request,
_transferParams.sigs,
_transferParams.signers,
_transferParams.powers
);
} else if (t == MsgDataTypes.TransferType.PegV2Withdraw) {
IOriginalTokenVaultV2(pegVaultV2).withdraw(
_transferParams.request,
_transferParams.sigs,
_transferParams.signers,
_transferParams.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;
}
}
文件 49 的 102:MessageBusSender.sol
pragma solidity 0.8.9;
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 MessageWithTransfer(
address indexed sender,
address receiver,
uint256 dstChainId,
address bridge,
bytes32 srcTransferId,
bytes message,
uint256 fee
);
event FeeBaseUpdated(uint256 feeBase);
event FeePerByteUpdated(uint256 feePerByte);
constructor(ISigsVerifier _sigsVerifier) {
sigsVerifier = _sigsVerifier;
}
function sendMessage(
address _receiver,
uint256 _dstChainId,
bytes calldata _message
) external payable {
require(_dstChainId != block.chainid, "Invalid chainId");
uint256 minFee = calcFee(_message);
require(msg.value >= minFee, "Insufficient fee");
emit Message(msg.sender, _receiver, _dstChainId, _message, msg.value);
}
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");
}
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);
}
}
文件 50 的 102:MessageReceiverApp.sol
pragma solidity 0.8.9;
import "../interfaces/IMessageReceiverApp.sol";
import "./MessageBusAddress.sol";
abstract contract MessageReceiverApp is IMessageReceiverApp, MessageBusAddress {
modifier onlyMessageBus() {
require(msg.sender == messageBus, "caller is not message bus");
_;
}
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) {}
function executeMessage(
address _sender,
uint64 _srcChainId,
bytes calldata _message,
address _executor
) external payable virtual override onlyMessageBus returns (ExecutionStatus) {}
}
文件 51 的 102:MessageSenderApp.sol
pragma solidity 0.8.9;
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 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
);
}
}
文件 52 的 102: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 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) {
if (_bridgeSendType == MsgDataTypes.BridgeSendType.Liquidity) {
return
sendMessageWithLiquidityBridgeTransfer(
_receiver,
_token,
_amount,
_dstChainId,
_nonce,
_maxSlippage,
_message,
_messageBus,
_fee
);
} else if (
_bridgeSendType == MsgDataTypes.BridgeSendType.PegDeposit ||
_bridgeSendType == MsgDataTypes.BridgeSendType.PegV2Deposit
) {
return
sendMessageWithPegVaultDeposit(
_bridgeSendType,
_receiver,
_token,
_amount,
_dstChainId,
_nonce,
_message,
_messageBus,
_fee
);
} else if (
_bridgeSendType == MsgDataTypes.BridgeSendType.PegBurn ||
_bridgeSendType == MsgDataTypes.BridgeSendType.PegV2Burn ||
_bridgeSendType == MsgDataTypes.BridgeSendType.PegV2BurnFrom
) {
return
sendMessageWithPegBridgeBurn(
_bridgeSendType,
_receiver,
_token,
_amount,
_dstChainId,
_nonce,
_message,
_messageBus,
_fee
);
} else {
revert("bridge type not supported");
}
}
function sendMessageWithLiquidityBridgeTransfer(
address _receiver,
address _token,
uint256 _amount,
uint64 _dstChainId,
uint64 _nonce,
uint32 _maxSlippage,
bytes memory _message,
address _messageBus,
uint256 _fee
) internal returns (bytes32) {
address bridge = IMessageBus(_messageBus).liquidityBridge();
IERC20(_token).safeIncreaseAllowance(bridge, _amount);
IBridge(bridge).send(_receiver, _token, _amount, _dstChainId, _nonce, _maxSlippage);
bytes32 transferId = keccak256(
abi.encodePacked(address(this), _receiver, _token, _amount, _dstChainId, _nonce, uint64(block.chainid))
);
if (_message.length > 0) {
IMessageBus(_messageBus).sendMessageWithTransfer{value: _fee}(
_receiver,
_dstChainId,
bridge,
transferId,
_message
);
}
return transferId;
}
function sendMessageWithPegVaultDeposit(
MsgDataTypes.BridgeSendType _bridgeSendType,
address _receiver,
address _token,
uint256 _amount,
uint64 _dstChainId,
uint64 _nonce,
bytes memory _message,
address _messageBus,
uint256 _fee
) internal returns (bytes32) {
address pegVault;
if (_bridgeSendType == MsgDataTypes.BridgeSendType.PegDeposit) {
pegVault = IMessageBus(_messageBus).pegVault();
} else {
pegVault = IMessageBus(_messageBus).pegVaultV2();
}
IERC20(_token).safeIncreaseAllowance(pegVault, _amount);
bytes32 transferId;
if (_bridgeSendType == MsgDataTypes.BridgeSendType.PegDeposit) {
IOriginalTokenVault(pegVault).deposit(_token, _amount, _dstChainId, _receiver, _nonce);
transferId = keccak256(
abi.encodePacked(address(this), _token, _amount, _dstChainId, _receiver, _nonce, uint64(block.chainid))
);
} else {
transferId = IOriginalTokenVaultV2(pegVault).deposit(_token, _amount, _dstChainId, _receiver, _nonce);
}
if (_message.length > 0) {
IMessageBus(_messageBus).sendMessageWithTransfer{value: _fee}(
_receiver,
_dstChainId,
pegVault,
transferId,
_message
);
}
return transferId;
}
function sendMessageWithPegBridgeBurn(
MsgDataTypes.BridgeSendType _bridgeSendType,
address _receiver,
address _token,
uint256 _amount,
uint64 _dstChainId,
uint64 _nonce,
bytes memory _message,
address _messageBus,
uint256 _fee
) internal returns (bytes32) {
address pegBridge;
if (_bridgeSendType == MsgDataTypes.BridgeSendType.PegBurn) {
pegBridge = IMessageBus(_messageBus).pegBridge();
} else {
pegBridge = IMessageBus(_messageBus).pegBridgeV2();
}
IERC20(_token).safeIncreaseAllowance(pegBridge, _amount);
bytes32 transferId;
if (_bridgeSendType == MsgDataTypes.BridgeSendType.PegBurn) {
IPeggedTokenBridge(pegBridge).burn(_token, _amount, _receiver, _nonce);
transferId = keccak256(
abi.encodePacked(address(this), _token, _amount, _receiver, _nonce, uint64(block.chainid))
);
} else if (_bridgeSendType == MsgDataTypes.BridgeSendType.PegV2Burn) {
transferId = IPeggedTokenBridgeV2(pegBridge).burn(_token, _amount, _dstChainId, _receiver, _nonce);
} else {
transferId = IPeggedTokenBridgeV2(pegBridge).burnFrom(_token, _amount, _dstChainId, _receiver, _nonce);
}
IERC20(_token).safeApprove(pegBridge, 0);
if (_message.length > 0) {
IMessageBus(_messageBus).sendMessageWithTransfer{value: _fee}(
_receiver,
_dstChainId,
pegBridge,
transferId,
_message
);
}
return transferId;
}
}
文件 53 的 102:MintSwapCanonicalToken.sol
pragma solidity >=0.8.9;
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "./MultiBridgeToken.sol";
contract MintSwapCanonicalToken is MultiBridgeToken {
using SafeERC20 for IERC20;
mapping(address => Supply) public swapSupplies;
event TokenSwapCapUpdated(address token, uint256 cap);
constructor(
string memory name_,
string memory symbol_,
uint8 decimals_
) MultiBridgeToken(name_, symbol_, decimals_) {}
function swapBridgeForCanonical(address _bridgeToken, uint256 _amount) external returns (uint256) {
Supply storage supply = swapSupplies[_bridgeToken];
require(supply.cap > 0, "invalid bridge token");
require(supply.total + _amount < supply.cap, "exceed swap cap");
supply.total += _amount;
_mint(msg.sender, _amount);
IERC20(_bridgeToken).safeTransferFrom(msg.sender, address(this), _amount);
return _amount;
}
function swapCanonicalForBridge(address _bridgeToken, uint256 _amount) external returns (uint256) {
Supply storage supply = swapSupplies[_bridgeToken];
require(supply.cap > 0, "invalid bridge token");
supply.total -= _amount;
_burn(msg.sender, _amount);
IERC20(_bridgeToken).safeTransfer(msg.sender, _amount);
return _amount;
}
function setBridgeTokenSwapCap(address _bridgeToken, uint256 _swapCap) external onlyOwner {
swapSupplies[_bridgeToken].cap = _swapCap;
emit TokenSwapCapUpdated(_bridgeToken, _swapCap);
}
}
文件 54 的 102:MintSwapCanonicalTokenPermit.sol
pragma solidity 0.8.9;
import "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol";
import "../MintSwapCanonicalToken.sol";
contract MintSwapCanonicalTokenPermit is ERC20Permit, MintSwapCanonicalToken {
uint8 private immutable _decimals;
constructor(
string memory name_,
string memory symbol_,
uint8 decimals_
) MintSwapCanonicalToken(name_, symbol_, decimals_) ERC20Permit(name_) {
_decimals = decimals_;
}
function decimals() public view override(ERC20, MultiBridgeToken) returns (uint8) {
return _decimals;
}
}
文件 55 的 102:MintSwapCanonicalTokenUpgradable.sol
pragma solidity >=0.8.9;
import "./MintSwapCanonicalToken.sol";
contract MintSwapCanonicalTokenUpgradable is MintSwapCanonicalToken {
string private _name;
string private _symbol;
constructor(
string memory name_,
string memory symbol_,
uint8 decimals_
) MintSwapCanonicalToken(name_, symbol_, decimals_) {}
function init(string memory name_, string memory symbol_) external {
initOwner();
_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;
}
}
文件 56 的 102:MintSwapCanonicalTokenUpgradableFreezable.sol
pragma solidity 0.8.9;
import "./Freezable.sol";
import "../MintSwapCanonicalTokenUpgradable.sol";
contract MintSwapCanonicalTokenUpgradableFreezable is MintSwapCanonicalTokenUpgradable, Freezable {
string private _name;
string private _symbol;
constructor(
string memory name_,
string memory symbol_,
uint8 decimals_
) MintSwapCanonicalTokenUpgradable(name_, symbol_, decimals_) {}
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual override {
super._beforeTokenTransfer(from, to, amount);
require(!isFrozen(from), "ERC20Freezable: from account is frozen");
require(!isFrozen(to), "ERC20Freezable: to account is frozen");
}
function freeze(address _account) public onlyOwner {
freezes[_account] = true;
emit Frozen(_account);
}
function unfreeze(address _account) public onlyOwner {
freezes[_account] = false;
emit Unfrozen(_account);
}
}
文件 57 的 102:MintableERC20.sol
pragma solidity 0.8.9;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
contract MintableERC20 is ERC20Burnable, Ownable {
uint8 private _decimals;
constructor(
string memory name_,
string memory symbol_,
uint8 decimals_,
uint256 initialSupply_
) ERC20(name_, symbol_) {
_decimals = decimals_;
_mint(msg.sender, initialSupply_);
}
function mint(address to, uint256 amount) public onlyOwner {
_mint(to, amount);
}
function decimals() public view override returns (uint8) {
return _decimals;
}
}
文件 58 的 102:MsgDataTypes.sol
pragma solidity >=0.8.0;
library MsgDataTypes {
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 MsgWithTransferExecutionParams {
bytes message;
TransferInfo transfer;
bytes[] sigs;
address[] signers;
uint256[] powers;
}
struct BridgeTransferParams {
bytes request;
bytes[] sigs;
address[] signers;
uint256[] powers;
}
}
文件 59 的 102:MsgTest.sol
pragma solidity >=0.8.9;
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../framework/MessageSenderApp.sol";
import "../framework/MessageReceiverApp.sol";
contract MsgTest is MessageSenderApp, MessageReceiverApp {
using SafeERC20 for IERC20;
uint64 nonce;
event MessageReceivedWithTransfer(
address token,
uint256 amount,
address sender,
uint64 srcChainId,
address receiver,
bytes message
);
event Refunded(address receiver, address token, uint256 amount, bytes message);
event MessageReceived(address sender, uint64 srcChainId, uint64 nonce, bytes message);
constructor(address _messageBus) {
messageBus = _messageBus;
}
function sendMessageWithTransfer(
address _receiver,
address _token,
uint256 _amount,
uint64 _dstChainId,
uint32 _maxSlippage,
bytes calldata _message,
MsgDataTypes.BridgeSendType _bridgeSendType
) external payable {
IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);
bytes memory message = abi.encode(msg.sender, _message);
sendMessageWithTransfer(
_receiver,
_token,
_amount,
_dstChainId,
nonce,
_maxSlippage,
message,
_bridgeSendType,
msg.value
);
nonce++;
}
function executeMessageWithTransfer(
address _sender,
address _token,
uint256 _amount,
uint64 _srcChainId,
bytes memory _message,
address
) external payable override onlyMessageBus returns (ExecutionStatus) {
(address receiver, bytes memory message) = abi.decode((_message), (address, bytes));
IERC20(_token).safeTransfer(receiver, _amount);
emit MessageReceivedWithTransfer(_token, _amount, _sender, _srcChainId, receiver, message);
return ExecutionStatus.Success;
}
function executeMessageWithTransferRefund(
address _token,
uint256 _amount,
bytes calldata _message,
address
) external payable override onlyMessageBus returns (ExecutionStatus) {
(address receiver, bytes memory message) = abi.decode((_message), (address, bytes));
IERC20(_token).safeTransfer(receiver, _amount);
emit Refunded(receiver, _token, _amount, message);
return ExecutionStatus.Success;
}
function sendMessage(
address _receiver,
uint64 _dstChainId,
bytes calldata _message
) external payable {
bytes memory message = abi.encode(nonce, _message);
nonce++;
sendMessage(_receiver, _dstChainId, message, msg.value);
}
function sendMessageWithNonce(
address _receiver,
uint64 _dstChainId,
bytes calldata _message,
uint64 _nonce
) external payable {
bytes memory message = abi.encode(_nonce, _message);
sendMessage(_receiver, _dstChainId, message, msg.value);
}
function executeMessage(
address _sender,
uint64 _srcChainId,
bytes calldata _message,
address
) external payable override onlyMessageBus returns (ExecutionStatus) {
(uint64 n, bytes memory message) = abi.decode((_message), (uint64, bytes));
require(n != 100000000000001, "invalid nonce");
if (n == 100000000000002) {
revert();
} else if (n == 100000000000003) {
return ExecutionStatus.Retry;
}
emit MessageReceived(_sender, _srcChainId, n, message);
return ExecutionStatus.Success;
}
function drainToken(address _token, uint256 _amount) external onlyOwner {
IERC20(_token).safeTransfer(msg.sender, _amount);
}
}
文件 60 的 102:MultiBridgeToken.sol
pragma solidity 0.8.9;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "../../safeguard/Ownable.sol";
contract MultiBridgeToken is ERC20, Ownable {
struct Supply {
uint256 cap;
uint256 total;
}
mapping(address => Supply) public bridges;
uint8 private immutable _decimals;
event BridgeSupplyCapUpdated(address bridge, uint256 supplyCap);
constructor(
string memory name_,
string memory symbol_,
uint8 decimals_
) ERC20(name_, symbol_) {
_decimals = decimals_;
}
function mint(address _to, uint256 _amount) external returns (bool) {
Supply storage b = bridges[msg.sender];
require(b.cap > 0, "invalid caller");
b.total += _amount;
require(b.total <= b.cap, "exceeds bridge supply cap");
_mint(_to, _amount);
return true;
}
function burn(uint256 _amount) external returns (bool) {
_burn(msg.sender, _amount);
return true;
}
function burn(address _from, uint256 _amount) external returns (bool) {
return _burnFrom(_from, _amount);
}
function burnFrom(address _from, uint256 _amount) external returns (bool) {
return _burnFrom(_from, _amount);
}
function _burnFrom(address _from, uint256 _amount) internal returns (bool) {
Supply storage b = bridges[msg.sender];
if (b.cap > 0 || b.total > 0) {
require(b.total >= _amount, "exceeds bridge minted amount");
unchecked {
b.total -= _amount;
}
}
_spendAllowance(_from, msg.sender, _amount);
_burn(_from, _amount);
return true;
}
function decimals() public view virtual override returns (uint8) {
return _decimals;
}
function updateBridgeSupplyCap(address _bridge, uint256 _cap) external onlyOwner {
bridges[_bridge].cap = _cap;
emit BridgeSupplyCapUpdated(_bridge, _cap);
}
function getOwner() external view returns (address) {
return owner();
}
}
文件 61 的 102:MultiBridgeTokenPermit.sol
pragma solidity 0.8.9;
import "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol";
import "../MultiBridgeToken.sol";
contract MultiBridgeTokenPermit is ERC20Permit, MultiBridgeToken {
uint8 private immutable _decimals;
constructor(
string memory name_,
string memory symbol_,
uint8 decimals_
) MultiBridgeToken(name_, symbol_, decimals_) ERC20Permit(name_) {
_decimals = decimals_;
}
function decimals() public view override(ERC20, MultiBridgeToken) returns (uint8) {
return _decimals;
}
}
文件 62 的 102:NFTBridge.sol
pragma solidity 0.8.9;
import "../framework/MessageReceiverApp.sol";
import "../interfaces/IMessageBus.sol";
import "../../safeguard/Pauser.sol";
interface INFT {
function tokenURI(uint256 tokenId) external view returns (string memory);
function ownerOf(uint256 tokenId) external view returns (address owner);
function transferFrom(
address from,
address to,
uint256 tokenId
) external;
function bridgeMint(
address to,
uint256 id,
string memory uri
) external;
function burn(uint256 id) external;
}
contract NFTBridge is MessageReceiverApp, Pauser {
mapping(uint64 => uint256) public destTxFee;
mapping(uint64 => address) public destBridge;
mapping(address => mapping(uint64 => address)) public destNFTAddr;
mapping(address => bool) public origNFT;
struct NFTMsg {
address user;
address nft;
uint256 id;
string uri;
}
event Sent(address sender, address srcNft, uint256 id, uint64 dstChid, address receiver, address dstNft);
event Received(address receiver, address nft, uint256 id, uint64 srcChid);
event SetDestNFT(address srcNft, uint64 dstChid, address dstNft);
event SetTxFee(uint64 chid, uint256 fee);
event SetDestBridge(uint64 dstChid, address dstNftBridge);
event FeeClaimed(uint256 amount);
event SetOrigNFT(address nft, bool isOrig);
event ExtCallErr(bytes returnData);
constructor(address _msgBus) {
messageBus = _msgBus;
}
function init(address _msgBus) external {
initOwner();
messageBus = _msgBus;
}
function totalFee(
uint64 _dstChid,
address _nft,
uint256 _id
) external view returns (uint256) {
string memory _uri = INFT(_nft).tokenURI(_id);
bytes memory message = abi.encode(NFTMsg(_nft, _nft, _id, _uri));
return IMessageBus(messageBus).calcFee(message) + destTxFee[_dstChid];
}
function sendTo(
address _nft,
uint256 _id,
uint64 _dstChid,
address _receiver
) external payable whenNotPaused {
require(msg.sender == INFT(_nft).ownerOf(_id), "not token owner");
string memory _uri = INFT(_nft).tokenURI(_id);
if (origNFT[_nft] == true) {
INFT(_nft).transferFrom(msg.sender, address(this), _id);
require(INFT(_nft).ownerOf(_id) == address(this), "transfer NFT failed");
} else {
INFT(_nft).burn(_id);
}
(address _dstBridge, address _dstNft) = checkAddr(_nft, _dstChid);
msgBus(_dstBridge, _dstChid, abi.encode(NFTMsg(_receiver, _dstNft, _id, _uri)));
emit Sent(msg.sender, _nft, _id, _dstChid, _receiver, _dstNft);
}
function sendMsg(
uint64 _dstChid,
address _sender,
address _receiver,
uint256 _id,
string calldata _uri
) external payable whenNotPaused {
address _nft = msg.sender;
(address _dstBridge, address _dstNft) = checkAddr(_nft, _dstChid);
msgBus(_dstBridge, _dstChid, abi.encode(NFTMsg(_receiver, _dstNft, _id, _uri)));
emit Sent(_sender, _nft, _id, _dstChid, _receiver, _dstNft);
}
function executeMessage(
address sender,
uint64 srcChid,
bytes memory _message,
address
) external payable override onlyMessageBus returns (ExecutionStatus) {
if (paused() || sender != destBridge[srcChid]) {
return ExecutionStatus.Retry;
}
NFTMsg memory nftMsg = abi.decode((_message), (NFTMsg));
if (origNFT[nftMsg.nft] == true) {
try INFT(nftMsg.nft).transferFrom(address(this), nftMsg.user, nftMsg.id) {
} catch (bytes memory returnData) {
emit ExtCallErr(returnData);
return ExecutionStatus.Retry;
}
} else {
try INFT(nftMsg.nft).bridgeMint(nftMsg.user, nftMsg.id, nftMsg.uri) {
} catch (bytes memory returnData) {
emit ExtCallErr(returnData);
return ExecutionStatus.Retry;
}
}
emit Received(nftMsg.user, nftMsg.nft, nftMsg.id, srcChid);
return ExecutionStatus.Success;
}
function checkAddr(address _nft, uint64 _dstChid) internal view returns (address dstBridge, address dstNft) {
dstBridge = destBridge[_dstChid];
require(dstBridge != address(0), "dest NFT Bridge not found");
dstNft = destNFTAddr[_nft][_dstChid];
require(dstNft != address(0), "dest NFT not found");
}
function msgBus(
address _dstBridge,
uint64 _dstChid,
bytes memory message
) internal {
uint256 fee = IMessageBus(messageBus).calcFee(message);
require(msg.value >= fee + destTxFee[_dstChid], "insufficient fee");
IMessageBus(messageBus).sendMessage{value: fee}(_dstBridge, _dstChid, message);
}
function setDestNFT(
address srcNft,
uint64 dstChid,
address dstNft
) external onlyOwner {
destNFTAddr[srcNft][dstChid] = dstNft;
emit SetDestNFT(srcNft, dstChid, dstNft);
}
function setDestNFTs(
address srcNft,
uint64[] calldata dstChid,
address[] calldata dstNft
) external onlyOwner {
require(dstChid.length == dstNft.length, "length mismatch");
for (uint256 i = 0; i < dstChid.length; i++) {
destNFTAddr[srcNft][dstChid[i]] = dstNft[i];
}
}
function setTxFee(uint64 chid, uint256 fee) external onlyOwner {
destTxFee[chid] = fee;
emit SetTxFee(chid, fee);
}
function setDestBridge(uint64 dstChid, address dstNftBridge) external onlyOwner {
destBridge[dstChid] = dstNftBridge;
emit SetDestBridge(dstChid, dstNftBridge);
}
function setDestBridges(uint64[] calldata dstChid, address[] calldata dstNftBridge) external onlyOwner {
for (uint256 i = 0; i < dstChid.length; i++) {
destBridge[dstChid[i]] = dstNftBridge[i];
}
}
function setOrigNFT(address _nft) external onlyOwner {
origNFT[_nft] = true;
emit SetOrigNFT(_nft, true);
}
function delOrigNFT(address _nft) external onlyOwner {
delete origNFT[_nft];
emit SetOrigNFT(_nft, false);
}
function claimFee() external onlyOwner {
uint256 amount = address(this).balance;
payable(msg.sender).transfer(amount);
emit FeeClaimed(amount);
}
}
文件 63 的 102:OrigNFT.sol
pragma solidity 0.8.9;
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "../../safeguard/Ownable.sol";
contract OrigNFT is ERC721URIStorage, Ownable {
constructor(string memory name_, string memory symbol_) ERC721(name_, symbol_) {}
function mint(
address to,
uint256 id,
string memory uri
) external onlyOwner {
_mint(to, id);
_setTokenURI(id, uri);
}
}
文件 64 的 102:OriginalTokenVault.sol
pragma solidity 0.8.9;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "../interfaces/ISigsVerifier.sol";
import "../interfaces/IWETH.sol";
import "../libraries/PbPegged.sol";
import "../safeguard/Pauser.sol";
import "../safeguard/VolumeControl.sol";
import "../safeguard/DelayedTransfer.sol";
contract OriginalTokenVault is ReentrancyGuard, Pauser, VolumeControl, DelayedTransfer {
using SafeERC20 for IERC20;
ISigsVerifier public immutable sigsVerifier;
mapping(bytes32 => bool) public records;
mapping(address => uint256) public minDeposit;
mapping(address => uint256) public maxDeposit;
address public nativeWrap;
event Deposited(
bytes32 depositId,
address depositor,
address token,
uint256 amount,
uint64 mintChainId,
address mintAccount
);
event Withdrawn(
bytes32 withdrawId,
address receiver,
address token,
uint256 amount,
uint64 refChainId,
bytes32 refId,
address burnAccount
);
event MinDepositUpdated(address token, uint256 amount);
event MaxDepositUpdated(address token, uint256 amount);
constructor(ISigsVerifier _sigsVerifier) {
sigsVerifier = _sigsVerifier;
}
function deposit(
address _token,
uint256 _amount,
uint64 _mintChainId,
address _mintAccount,
uint64 _nonce
) external nonReentrant whenNotPaused {
bytes32 depId = _deposit(_token, _amount, _mintChainId, _mintAccount, _nonce);
IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);
emit Deposited(depId, msg.sender, _token, _amount, _mintChainId, _mintAccount);
}
function depositNative(
uint256 _amount,
uint64 _mintChainId,
address _mintAccount,
uint64 _nonce
) external payable nonReentrant whenNotPaused {
require(msg.value == _amount, "Amount mismatch");
require(nativeWrap != address(0), "Native wrap not set");
bytes32 depId = _deposit(nativeWrap, _amount, _mintChainId, _mintAccount, _nonce);
IWETH(nativeWrap).deposit{value: _amount}();
emit Deposited(depId, msg.sender, nativeWrap, _amount, _mintChainId, _mintAccount);
}
function _deposit(
address _token,
uint256 _amount,
uint64 _mintChainId,
address _mintAccount,
uint64 _nonce
) private returns (bytes32) {
require(_amount > minDeposit[_token], "amount too small");
require(maxDeposit[_token] == 0 || _amount <= maxDeposit[_token], "amount too large");
bytes32 depId = keccak256(
abi.encodePacked(msg.sender, _token, _amount, _mintChainId, _mintAccount, _nonce, uint64(block.chainid))
);
require(records[depId] == false, "record exists");
records[depId] = true;
return depId;
}
function withdraw(
bytes calldata _request,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers
) external whenNotPaused {
bytes32 domain = keccak256(abi.encodePacked(block.chainid, address(this), "Withdraw"));
sigsVerifier.verifySigs(abi.encodePacked(domain, _request), _sigs, _signers, _powers);
PbPegged.Withdraw memory request = PbPegged.decWithdraw(_request);
bytes32 wdId = keccak256(
abi.encodePacked(
request.receiver,
request.token,
request.amount,
request.burnAccount,
request.refChainId,
request.refId
)
);
require(records[wdId] == false, "record exists");
records[wdId] = true;
_updateVolume(request.token, request.amount);
uint256 delayThreshold = delayThresholds[request.token];
if (delayThreshold > 0 && request.amount > delayThreshold) {
_addDelayedTransfer(wdId, request.receiver, request.token, request.amount);
} else {
_sendToken(request.receiver, request.token, request.amount);
}
emit Withdrawn(
wdId,
request.receiver,
request.token,
request.amount,
request.refChainId,
request.refId,
request.burnAccount
);
}
function executeDelayedTransfer(bytes32 id) external whenNotPaused {
delayedTransfer memory transfer = _executeDelayedTransfer(id);
_sendToken(transfer.receiver, transfer.token, transfer.amount);
}
function setMinDeposit(address[] calldata _tokens, uint256[] calldata _amounts) external onlyGovernor {
require(_tokens.length == _amounts.length, "length mismatch");
for (uint256 i = 0; i < _tokens.length; i++) {
minDeposit[_tokens[i]] = _amounts[i];
emit MinDepositUpdated(_tokens[i], _amounts[i]);
}
}
function setMaxDeposit(address[] calldata _tokens, uint256[] calldata _amounts) external onlyGovernor {
require(_tokens.length == _amounts.length, "length mismatch");
for (uint256 i = 0; i < _tokens.length; i++) {
maxDeposit[_tokens[i]] = _amounts[i];
emit MaxDepositUpdated(_tokens[i], _amounts[i]);
}
}
function setWrap(address _weth) external onlyOwner {
nativeWrap = _weth;
}
function _sendToken(
address _receiver,
address _token,
uint256 _amount
) private {
if (_token == nativeWrap) {
IWETH(nativeWrap).withdraw(_amount);
(bool sent, ) = _receiver.call{value: _amount, gas: 50000}("");
require(sent, "failed to send native token");
} else {
IERC20(_token).safeTransfer(_receiver, _amount);
}
}
receive() external payable {}
}
文件 65 的 102:OriginalTokenVaultV2.sol
pragma solidity 0.8.9;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "../interfaces/ISigsVerifier.sol";
import "../interfaces/IWETH.sol";
import "../libraries/PbPegged.sol";
import "../safeguard/Pauser.sol";
import "../safeguard/VolumeControl.sol";
import "../safeguard/DelayedTransfer.sol";
contract OriginalTokenVaultV2 is ReentrancyGuard, Pauser, VolumeControl, DelayedTransfer {
using SafeERC20 for IERC20;
ISigsVerifier public immutable sigsVerifier;
mapping(bytes32 => bool) public records;
mapping(address => uint256) public minDeposit;
mapping(address => uint256) public maxDeposit;
address public nativeWrap;
event Deposited(
bytes32 depositId,
address depositor,
address token,
uint256 amount,
uint64 mintChainId,
address mintAccount,
uint64 nonce
);
event Withdrawn(
bytes32 withdrawId,
address receiver,
address token,
uint256 amount,
uint64 refChainId,
bytes32 refId,
address burnAccount
);
event MinDepositUpdated(address token, uint256 amount);
event MaxDepositUpdated(address token, uint256 amount);
constructor(ISigsVerifier _sigsVerifier) {
sigsVerifier = _sigsVerifier;
}
function deposit(
address _token,
uint256 _amount,
uint64 _mintChainId,
address _mintAccount,
uint64 _nonce
) external nonReentrant whenNotPaused returns (bytes32) {
bytes32 depId = _deposit(_token, _amount, _mintChainId, _mintAccount, _nonce);
IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);
emit Deposited(depId, msg.sender, _token, _amount, _mintChainId, _mintAccount, _nonce);
return depId;
}
function depositNative(
uint256 _amount,
uint64 _mintChainId,
address _mintAccount,
uint64 _nonce
) external payable nonReentrant whenNotPaused returns (bytes32) {
require(msg.value == _amount, "Amount mismatch");
require(nativeWrap != address(0), "Native wrap not set");
bytes32 depId = _deposit(nativeWrap, _amount, _mintChainId, _mintAccount, _nonce);
IWETH(nativeWrap).deposit{value: _amount}();
emit Deposited(depId, msg.sender, nativeWrap, _amount, _mintChainId, _mintAccount, _nonce);
return depId;
}
function _deposit(
address _token,
uint256 _amount,
uint64 _mintChainId,
address _mintAccount,
uint64 _nonce
) private returns (bytes32) {
require(_amount > minDeposit[_token], "amount too small");
require(maxDeposit[_token] == 0 || _amount <= maxDeposit[_token], "amount too large");
bytes32 depId = keccak256(
abi.encodePacked(
msg.sender,
_token,
_amount,
_mintChainId,
_mintAccount,
_nonce,
uint64(block.chainid),
address(this)
)
);
require(records[depId] == false, "record exists");
records[depId] = true;
return depId;
}
function withdraw(
bytes calldata _request,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers
) external whenNotPaused returns (bytes32) {
bytes32 domain = keccak256(abi.encodePacked(block.chainid, address(this), "Withdraw"));
sigsVerifier.verifySigs(abi.encodePacked(domain, _request), _sigs, _signers, _powers);
PbPegged.Withdraw memory request = PbPegged.decWithdraw(_request);
bytes32 wdId = keccak256(
abi.encodePacked(
request.receiver,
request.token,
request.amount,
request.burnAccount,
request.refChainId,
request.refId,
address(this)
)
);
require(records[wdId] == false, "record exists");
records[wdId] = true;
_updateVolume(request.token, request.amount);
uint256 delayThreshold = delayThresholds[request.token];
if (delayThreshold > 0 && request.amount > delayThreshold) {
_addDelayedTransfer(wdId, request.receiver, request.token, request.amount);
} else {
_sendToken(request.receiver, request.token, request.amount);
}
emit Withdrawn(
wdId,
request.receiver,
request.token,
request.amount,
request.refChainId,
request.refId,
request.burnAccount
);
return wdId;
}
function executeDelayedTransfer(bytes32 id) external whenNotPaused {
delayedTransfer memory transfer = _executeDelayedTransfer(id);
_sendToken(transfer.receiver, transfer.token, transfer.amount);
}
function setMinDeposit(address[] calldata _tokens, uint256[] calldata _amounts) external onlyGovernor {
require(_tokens.length == _amounts.length, "length mismatch");
for (uint256 i = 0; i < _tokens.length; i++) {
minDeposit[_tokens[i]] = _amounts[i];
emit MinDepositUpdated(_tokens[i], _amounts[i]);
}
}
function setMaxDeposit(address[] calldata _tokens, uint256[] calldata _amounts) external onlyGovernor {
require(_tokens.length == _amounts.length, "length mismatch");
for (uint256 i = 0; i < _tokens.length; i++) {
maxDeposit[_tokens[i]] = _amounts[i];
emit MaxDepositUpdated(_tokens[i], _amounts[i]);
}
}
function setWrap(address _weth) external onlyOwner {
nativeWrap = _weth;
}
function _sendToken(
address _receiver,
address _token,
uint256 _amount
) private {
if (_token == nativeWrap) {
IWETH(nativeWrap).withdraw(_amount);
(bool sent, ) = _receiver.call{value: _amount, gas: 50000}("");
require(sent, "failed to send native token");
} else {
IERC20(_token).safeTransfer(_receiver, _amount);
}
}
receive() external payable {}
}
文件 66 的 102: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);
}
}
文件 67 的 102:Pausable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Pausable is Context {
event Paused(address account);
event Unpaused(address account);
bool private _paused;
constructor() {
_paused = false;
}
function paused() public view virtual returns (bool) {
return _paused;
}
modifier whenNotPaused() {
require(!paused(), "Pausable: paused");
_;
}
modifier whenPaused() {
require(paused(), "Pausable: not paused");
_;
}
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}
文件 68 的 102:Pauser.sol
pragma solidity 0.8.9;
import "@openzeppelin/contracts/security/Pausable.sol";
import "./Ownable.sol";
abstract contract Pauser is Ownable, Pausable {
mapping(address => bool) public pausers;
event PauserAdded(address account);
event PauserRemoved(address account);
constructor() {
_addPauser(msg.sender);
}
modifier onlyPauser() {
require(isPauser(msg.sender), "Caller is not pauser");
_;
}
function pause() public onlyPauser {
_pause();
}
function unpause() public onlyPauser {
_unpause();
}
function isPauser(address account) public view returns (bool) {
return pausers[account];
}
function addPauser(address account) public onlyOwner {
_addPauser(account);
}
function removePauser(address account) public onlyOwner {
_removePauser(account);
}
function renouncePauser() public {
_removePauser(msg.sender);
}
function _addPauser(address account) private {
require(!isPauser(account), "Account is already pauser");
pausers[account] = true;
emit PauserAdded(account);
}
function _removePauser(address account) private {
require(isPauser(account), "Account is not pauser");
pausers[account] = false;
emit PauserRemoved(account);
}
}
文件 69 的 102:Pb.sol
pragma solidity 0.8.9;
library Pb {
enum WireType {
Varint,
Fixed64,
LengthDelim,
StartGroup,
EndGroup,
Fixed32
}
struct Buffer {
uint256 idx;
bytes b;
}
function fromBytes(bytes memory raw) internal pure returns (Buffer memory buf) {
buf.b = raw;
buf.idx = 0;
}
function hasMore(Buffer memory buf) internal pure returns (bool) {
return buf.idx < buf.b.length;
}
function decKey(Buffer memory buf) internal pure returns (uint256 tag, WireType wiretype) {
uint256 v = decVarint(buf);
tag = v / 8;
wiretype = WireType(v & 7);
}
function cntTags(Buffer memory buf, uint256 maxtag) internal pure returns (uint256[] memory cnts) {
uint256 originalIdx = buf.idx;
cnts = new uint256[](maxtag + 1);
uint256 tag;
WireType wire;
while (hasMore(buf)) {
(tag, wire) = decKey(buf);
cnts[tag] += 1;
skipValue(buf, wire);
}
buf.idx = originalIdx;
}
function decVarint(Buffer memory buf) internal pure returns (uint256 v) {
bytes10 tmp;
bytes memory bb = buf.b;
v = buf.idx;
assembly {
tmp := mload(add(add(bb, 32), v))
}
uint256 b;
v = 0;
for (uint256 i = 0; i < 10; i++) {
assembly {
b := byte(i, tmp)
}
v |= (b & 0x7F) << (i * 7);
if (b & 0x80 == 0) {
buf.idx += i + 1;
return v;
}
}
revert();
}
function decBytes(Buffer memory buf) internal pure returns (bytes memory b) {
uint256 len = decVarint(buf);
uint256 end = buf.idx + len;
require(end <= buf.b.length);
b = new bytes(len);
bytes memory bufB = buf.b;
uint256 bStart;
uint256 bufBStart = buf.idx;
assembly {
bStart := add(b, 32)
bufBStart := add(add(bufB, 32), bufBStart)
}
for (uint256 i = 0; i < len; i += 32) {
assembly {
mstore(add(bStart, i), mload(add(bufBStart, i)))
}
}
buf.idx = end;
}
function decPacked(Buffer memory buf) internal pure returns (uint256[] memory t) {
uint256 len = decVarint(buf);
uint256 end = buf.idx + len;
require(end <= buf.b.length);
uint256[] memory tmp = new uint256[](len);
uint256 i = 0;
while (buf.idx < end) {
tmp[i] = decVarint(buf);
i++;
}
t = new uint256[](i);
for (uint256 j = 0; j < i; j++) {
t[j] = tmp[j];
}
return t;
}
function skipValue(Buffer memory buf, WireType wire) internal pure {
if (wire == WireType.Varint) {
decVarint(buf);
} else if (wire == WireType.LengthDelim) {
uint256 len = decVarint(buf);
buf.idx += len;
require(buf.idx <= buf.b.length);
} else {
revert();
}
}
function _bool(uint256 x) internal pure returns (bool v) {
return x != 0;
}
function _uint256(bytes memory b) internal pure returns (uint256 v) {
require(b.length <= 32);
assembly {
v := mload(add(b, 32))
}
v = v >> (8 * (32 - b.length));
}
function _address(bytes memory b) internal pure returns (address v) {
v = _addressPayable(b);
}
function _addressPayable(bytes memory b) internal pure returns (address payable v) {
require(b.length == 20);
assembly {
v := div(mload(add(b, 32)), 0x1000000000000000000000000)
}
}
function _bytes32(bytes memory b) internal pure returns (bytes32 v) {
require(b.length == 32);
assembly {
v := mload(add(b, 32))
}
}
function uint8s(uint256[] memory arr) internal pure returns (uint8[] memory t) {
t = new uint8[](arr.length);
for (uint256 i = 0; i < t.length; i++) {
t[i] = uint8(arr[i]);
}
}
function uint32s(uint256[] memory arr) internal pure returns (uint32[] memory t) {
t = new uint32[](arr.length);
for (uint256 i = 0; i < t.length; i++) {
t[i] = uint32(arr[i]);
}
}
function uint64s(uint256[] memory arr) internal pure returns (uint64[] memory t) {
t = new uint64[](arr.length);
for (uint256 i = 0; i < t.length; i++) {
t[i] = uint64(arr[i]);
}
}
function bools(uint256[] memory arr) internal pure returns (bool[] memory t) {
t = new bool[](arr.length);
for (uint256 i = 0; i < t.length; i++) {
t[i] = arr[i] != 0;
}
}
}
文件 70 的 102:PbBridge.sol
pragma solidity 0.8.9;
import "./Pb.sol";
library PbBridge {
using Pb for Pb.Buffer;
struct Relay {
address sender;
address receiver;
address token;
uint256 amount;
uint64 srcChainId;
uint64 dstChainId;
bytes32 srcTransferId;
}
function decRelay(bytes memory raw) internal pure returns (Relay memory m) {
Pb.Buffer memory buf = Pb.fromBytes(raw);
uint256 tag;
Pb.WireType wire;
while (buf.hasMore()) {
(tag, wire) = buf.decKey();
if (false) {}
else if (tag == 1) {
m.sender = Pb._address(buf.decBytes());
} else if (tag == 2) {
m.receiver = Pb._address(buf.decBytes());
} else if (tag == 3) {
m.token = Pb._address(buf.decBytes());
} else if (tag == 4) {
m.amount = Pb._uint256(buf.decBytes());
} else if (tag == 5) {
m.srcChainId = uint64(buf.decVarint());
} else if (tag == 6) {
m.dstChainId = uint64(buf.decVarint());
} else if (tag == 7) {
m.srcTransferId = Pb._bytes32(buf.decBytes());
} else {
buf.skipValue(wire);
}
}
}
}
文件 71 的 102:PbFarming.sol
pragma solidity 0.8.9;
import "./Pb.sol";
library PbFarming {
using Pb for Pb.Buffer;
struct FarmingRewards {
address recipient;
address[] tokenAddresses;
uint256[] cumulativeRewardAmounts;
}
function decFarmingRewards(bytes memory raw) internal pure returns (FarmingRewards memory m) {
Pb.Buffer memory buf = Pb.fromBytes(raw);
uint256[] memory cnts = buf.cntTags(3);
m.tokenAddresses = new address[](cnts[2]);
cnts[2] = 0;
m.cumulativeRewardAmounts = new uint256[](cnts[3]);
cnts[3] = 0;
uint256 tag;
Pb.WireType wire;
while (buf.hasMore()) {
(tag, wire) = buf.decKey();
if (false) {}
else if (tag == 1) {
m.recipient = Pb._address(buf.decBytes());
} else if (tag == 2) {
m.tokenAddresses[cnts[2]] = Pb._address(buf.decBytes());
cnts[2]++;
} else if (tag == 3) {
m.cumulativeRewardAmounts[cnts[3]] = Pb._uint256(buf.decBytes());
cnts[3]++;
} else {
buf.skipValue(wire);
}
}
}
}
文件 72 的 102:PbPegged.sol
pragma solidity 0.8.9;
import "./Pb.sol";
library PbPegged {
using Pb for Pb.Buffer;
struct Mint {
address token;
address account;
uint256 amount;
address depositor;
uint64 refChainId;
bytes32 refId;
}
function decMint(bytes memory raw) internal pure returns (Mint memory m) {
Pb.Buffer memory buf = Pb.fromBytes(raw);
uint256 tag;
Pb.WireType wire;
while (buf.hasMore()) {
(tag, wire) = buf.decKey();
if (false) {}
else if (tag == 1) {
m.token = Pb._address(buf.decBytes());
} else if (tag == 2) {
m.account = Pb._address(buf.decBytes());
} else if (tag == 3) {
m.amount = Pb._uint256(buf.decBytes());
} else if (tag == 4) {
m.depositor = Pb._address(buf.decBytes());
} else if (tag == 5) {
m.refChainId = uint64(buf.decVarint());
} else if (tag == 6) {
m.refId = Pb._bytes32(buf.decBytes());
} else {
buf.skipValue(wire);
}
}
}
struct Withdraw {
address token;
address receiver;
uint256 amount;
address burnAccount;
uint64 refChainId;
bytes32 refId;
}
function decWithdraw(bytes memory raw) internal pure returns (Withdraw memory m) {
Pb.Buffer memory buf = Pb.fromBytes(raw);
uint256 tag;
Pb.WireType wire;
while (buf.hasMore()) {
(tag, wire) = buf.decKey();
if (false) {}
else if (tag == 1) {
m.token = Pb._address(buf.decBytes());
} else if (tag == 2) {
m.receiver = Pb._address(buf.decBytes());
} else if (tag == 3) {
m.amount = Pb._uint256(buf.decBytes());
} else if (tag == 4) {
m.burnAccount = Pb._address(buf.decBytes());
} else if (tag == 5) {
m.refChainId = uint64(buf.decVarint());
} else if (tag == 6) {
m.refId = Pb._bytes32(buf.decBytes());
} else {
buf.skipValue(wire);
}
}
}
}
文件 73 的 102:PbPool.sol
pragma solidity 0.8.9;
import "./Pb.sol";
library PbPool {
using Pb for Pb.Buffer;
struct WithdrawMsg {
uint64 chainid;
uint64 seqnum;
address receiver;
address token;
uint256 amount;
bytes32 refid;
}
function decWithdrawMsg(bytes memory raw) internal pure returns (WithdrawMsg memory m) {
Pb.Buffer memory buf = Pb.fromBytes(raw);
uint256 tag;
Pb.WireType wire;
while (buf.hasMore()) {
(tag, wire) = buf.decKey();
if (false) {}
else if (tag == 1) {
m.chainid = uint64(buf.decVarint());
} else if (tag == 2) {
m.seqnum = uint64(buf.decVarint());
} else if (tag == 3) {
m.receiver = Pb._address(buf.decBytes());
} else if (tag == 4) {
m.token = Pb._address(buf.decBytes());
} else if (tag == 5) {
m.amount = Pb._uint256(buf.decBytes());
} else if (tag == 6) {
m.refid = Pb._bytes32(buf.decBytes());
} else {
buf.skipValue(wire);
}
}
}
}
文件 74 的 102:PbSgn.sol
pragma solidity 0.8.9;
import "./Pb.sol";
library PbSgn {
using Pb for Pb.Buffer;
struct Withdrawal {
address account;
address token;
uint256 cumulativeAmount;
}
function decWithdrawal(bytes memory raw) internal pure returns (Withdrawal memory m) {
Pb.Buffer memory buf = Pb.fromBytes(raw);
uint256 tag;
Pb.WireType wire;
while (buf.hasMore()) {
(tag, wire) = buf.decKey();
if (false) {}
else if (tag == 1) {
m.account = Pb._address(buf.decBytes());
} else if (tag == 2) {
m.token = Pb._address(buf.decBytes());
} else if (tag == 3) {
m.cumulativeAmount = Pb._uint256(buf.decBytes());
} else {
buf.skipValue(wire);
}
}
}
}
文件 75 的 102:PbStaking.sol
pragma solidity 0.8.9;
import "./Pb.sol";
library PbStaking {
using Pb for Pb.Buffer;
struct StakingReward {
address recipient;
uint256 cumulativeRewardAmount;
}
function decStakingReward(bytes memory raw) internal pure returns (StakingReward memory m) {
Pb.Buffer memory buf = Pb.fromBytes(raw);
uint256 tag;
Pb.WireType wire;
while (buf.hasMore()) {
(tag, wire) = buf.decKey();
if (false) {}
else if (tag == 1) {
m.recipient = Pb._address(buf.decBytes());
} else if (tag == 2) {
m.cumulativeRewardAmount = Pb._uint256(buf.decBytes());
} else {
buf.skipValue(wire);
}
}
}
struct Slash {
address validator;
uint64 nonce;
uint64 slashFactor;
uint64 expireTime;
uint64 jailPeriod;
AcctAmtPair[] collectors;
}
function decSlash(bytes memory raw) internal pure returns (Slash memory m) {
Pb.Buffer memory buf = Pb.fromBytes(raw);
uint256[] memory cnts = buf.cntTags(6);
m.collectors = new AcctAmtPair[](cnts[6]);
cnts[6] = 0;
uint256 tag;
Pb.WireType wire;
while (buf.hasMore()) {
(tag, wire) = buf.decKey();
if (false) {}
else if (tag == 1) {
m.validator = Pb._address(buf.decBytes());
} else if (tag == 2) {
m.nonce = uint64(buf.decVarint());
} else if (tag == 3) {
m.slashFactor = uint64(buf.decVarint());
} else if (tag == 4) {
m.expireTime = uint64(buf.decVarint());
} else if (tag == 5) {
m.jailPeriod = uint64(buf.decVarint());
} else if (tag == 6) {
m.collectors[cnts[6]] = decAcctAmtPair(buf.decBytes());
cnts[6]++;
} else {
buf.skipValue(wire);
}
}
}
struct AcctAmtPair {
address account;
uint256 amount;
}
function decAcctAmtPair(bytes memory raw) internal pure returns (AcctAmtPair memory m) {
Pb.Buffer memory buf = Pb.fromBytes(raw);
uint256 tag;
Pb.WireType wire;
while (buf.hasMore()) {
(tag, wire) = buf.decKey();
if (false) {}
else if (tag == 1) {
m.account = Pb._address(buf.decBytes());
} else if (tag == 2) {
m.amount = Pb._uint256(buf.decBytes());
} else {
buf.skipValue(wire);
}
}
}
}
文件 76 的 102:PegNFT.sol
pragma solidity 0.8.9;
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
contract PegNFT is ERC721URIStorage {
address public immutable nftBridge;
constructor(
string memory name_,
string memory symbol_,
address _nftBridge
) ERC721(name_, symbol_) {
nftBridge = _nftBridge;
}
modifier onlyNftBridge() {
require(msg.sender == nftBridge, "caller is not bridge");
_;
}
function bridgeMint(
address to,
uint256 id,
string memory uri
) external onlyNftBridge {
_mint(to, id);
_setTokenURI(id, uri);
}
function burn(uint256 id) external onlyNftBridge {
_burn(id);
}
}
文件 77 的 102:PeggedTokenBridge.sol
pragma solidity 0.8.9;
import "../interfaces/ISigsVerifier.sol";
import "../interfaces/IPeggedToken.sol";
import "../libraries/PbPegged.sol";
import "../safeguard/Pauser.sol";
import "../safeguard/VolumeControl.sol";
import "../safeguard/DelayedTransfer.sol";
contract PeggedTokenBridge is Pauser, VolumeControl, DelayedTransfer {
ISigsVerifier public immutable sigsVerifier;
mapping(bytes32 => bool) public records;
mapping(address => uint256) public minBurn;
mapping(address => uint256) public maxBurn;
event Mint(
bytes32 mintId,
address token,
address account,
uint256 amount,
uint64 refChainId,
bytes32 refId,
address depositor
);
event Burn(bytes32 burnId, address token, address account, uint256 amount, address withdrawAccount);
event MinBurnUpdated(address token, uint256 amount);
event MaxBurnUpdated(address token, uint256 amount);
constructor(ISigsVerifier _sigsVerifier) {
sigsVerifier = _sigsVerifier;
}
function mint(
bytes calldata _request,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers
) external whenNotPaused {
bytes32 domain = keccak256(abi.encodePacked(block.chainid, address(this), "Mint"));
sigsVerifier.verifySigs(abi.encodePacked(domain, _request), _sigs, _signers, _powers);
PbPegged.Mint memory request = PbPegged.decMint(_request);
bytes32 mintId = keccak256(
abi.encodePacked(
request.account,
request.token,
request.amount,
request.depositor,
request.refChainId,
request.refId
)
);
require(records[mintId] == false, "record exists");
records[mintId] = true;
_updateVolume(request.token, request.amount);
uint256 delayThreshold = delayThresholds[request.token];
if (delayThreshold > 0 && request.amount > delayThreshold) {
_addDelayedTransfer(mintId, request.account, request.token, request.amount);
} else {
IPeggedToken(request.token).mint(request.account, request.amount);
}
emit Mint(
mintId,
request.token,
request.account,
request.amount,
request.refChainId,
request.refId,
request.depositor
);
}
function burn(
address _token,
uint256 _amount,
address _withdrawAccount,
uint64 _nonce
) external whenNotPaused {
require(_amount > minBurn[_token], "amount too small");
require(maxBurn[_token] == 0 || _amount <= maxBurn[_token], "amount too large");
bytes32 burnId = keccak256(
abi.encodePacked(msg.sender, _token, _amount, _withdrawAccount, _nonce, uint64(block.chainid))
);
require(records[burnId] == false, "record exists");
records[burnId] = true;
IPeggedToken(_token).burn(msg.sender, _amount);
emit Burn(burnId, _token, msg.sender, _amount, _withdrawAccount);
}
function executeDelayedTransfer(bytes32 id) external whenNotPaused {
delayedTransfer memory transfer = _executeDelayedTransfer(id);
IPeggedToken(transfer.token).mint(transfer.receiver, transfer.amount);
}
function setMinBurn(address[] calldata _tokens, uint256[] calldata _amounts) external onlyGovernor {
require(_tokens.length == _amounts.length, "length mismatch");
for (uint256 i = 0; i < _tokens.length; i++) {
minBurn[_tokens[i]] = _amounts[i];
emit MinBurnUpdated(_tokens[i], _amounts[i]);
}
}
function setMaxBurn(address[] calldata _tokens, uint256[] calldata _amounts) external onlyGovernor {
require(_tokens.length == _amounts.length, "length mismatch");
for (uint256 i = 0; i < _tokens.length; i++) {
maxBurn[_tokens[i]] = _amounts[i];
emit MaxBurnUpdated(_tokens[i], _amounts[i]);
}
}
}
文件 78 的 102:PeggedTokenBridgeV2.sol
pragma solidity 0.8.9;
import "../interfaces/ISigsVerifier.sol";
import "../interfaces/IPeggedToken.sol";
import "../interfaces/IPeggedTokenBurnFrom.sol";
import "../libraries/PbPegged.sol";
import "../safeguard/Pauser.sol";
import "../safeguard/VolumeControl.sol";
import "../safeguard/DelayedTransfer.sol";
contract PeggedTokenBridgeV2 is Pauser, VolumeControl, DelayedTransfer {
ISigsVerifier public immutable sigsVerifier;
mapping(bytes32 => bool) public records;
mapping(address => uint256) public supplies;
mapping(address => uint256) public minBurn;
mapping(address => uint256) public maxBurn;
event Mint(
bytes32 mintId,
address token,
address account,
uint256 amount,
uint64 refChainId,
bytes32 refId,
address depositor
);
event Burn(
bytes32 burnId,
address token,
address account,
uint256 amount,
uint64 toChainId,
address toAccount,
uint64 nonce
);
event MinBurnUpdated(address token, uint256 amount);
event MaxBurnUpdated(address token, uint256 amount);
event SupplyUpdated(address token, uint256 supply);
constructor(ISigsVerifier _sigsVerifier) {
sigsVerifier = _sigsVerifier;
}
function mint(
bytes calldata _request,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers
) external whenNotPaused returns (bytes32) {
bytes32 domain = keccak256(abi.encodePacked(block.chainid, address(this), "Mint"));
sigsVerifier.verifySigs(abi.encodePacked(domain, _request), _sigs, _signers, _powers);
PbPegged.Mint memory request = PbPegged.decMint(_request);
bytes32 mintId = keccak256(
abi.encodePacked(
request.account,
request.token,
request.amount,
request.depositor,
request.refChainId,
request.refId,
address(this)
)
);
require(records[mintId] == false, "record exists");
records[mintId] = true;
_updateVolume(request.token, request.amount);
uint256 delayThreshold = delayThresholds[request.token];
if (delayThreshold > 0 && request.amount > delayThreshold) {
_addDelayedTransfer(mintId, request.account, request.token, request.amount);
} else {
IPeggedToken(request.token).mint(request.account, request.amount);
}
supplies[request.token] += request.amount;
emit Mint(
mintId,
request.token,
request.account,
request.amount,
request.refChainId,
request.refId,
request.depositor
);
return mintId;
}
function burn(
address _token,
uint256 _amount,
uint64 _toChainId,
address _toAccount,
uint64 _nonce
) external whenNotPaused returns (bytes32) {
bytes32 burnId = _burn(_token, _amount, _toChainId, _toAccount, _nonce);
IPeggedToken(_token).burn(msg.sender, _amount);
return burnId;
}
function burnFrom(
address _token,
uint256 _amount,
uint64 _toChainId,
address _toAccount,
uint64 _nonce
) external whenNotPaused returns (bytes32) {
bytes32 burnId = _burn(_token, _amount, _toChainId, _toAccount, _nonce);
IPeggedTokenBurnFrom(_token).burnFrom(msg.sender, _amount);
return burnId;
}
function _burn(
address _token,
uint256 _amount,
uint64 _toChainId,
address _toAccount,
uint64 _nonce
) private returns (bytes32) {
require(_amount > minBurn[_token], "amount too small");
require(maxBurn[_token] == 0 || _amount <= maxBurn[_token], "amount too large");
supplies[_token] -= _amount;
bytes32 burnId = keccak256(
abi.encodePacked(
msg.sender,
_token,
_amount,
_toChainId,
_toAccount,
_nonce,
uint64(block.chainid),
address(this)
)
);
require(records[burnId] == false, "record exists");
records[burnId] = true;
emit Burn(burnId, _token, msg.sender, _amount, _toChainId, _toAccount, _nonce);
return burnId;
}
function executeDelayedTransfer(bytes32 id) external whenNotPaused {
delayedTransfer memory transfer = _executeDelayedTransfer(id);
IPeggedToken(transfer.token).mint(transfer.receiver, transfer.amount);
}
function setMinBurn(address[] calldata _tokens, uint256[] calldata _amounts) external onlyGovernor {
require(_tokens.length == _amounts.length, "length mismatch");
for (uint256 i = 0; i < _tokens.length; i++) {
minBurn[_tokens[i]] = _amounts[i];
emit MinBurnUpdated(_tokens[i], _amounts[i]);
}
}
function setMaxBurn(address[] calldata _tokens, uint256[] calldata _amounts) external onlyGovernor {
require(_tokens.length == _amounts.length, "length mismatch");
for (uint256 i = 0; i < _tokens.length; i++) {
maxBurn[_tokens[i]] = _amounts[i];
emit MaxBurnUpdated(_tokens[i], _amounts[i]);
}
}
function setSupply(address _token, uint256 _supply) external onlyOwner {
supplies[_token] = _supply;
emit SupplyUpdated(_token, _supply);
}
function increaseSupply(address _token, uint256 _delta) external onlyOwner {
supplies[_token] += _delta;
emit SupplyUpdated(_token, supplies[_token]);
}
function decreaseSupply(address _token, uint256 _delta) external onlyOwner {
supplies[_token] -= _delta;
emit SupplyUpdated(_token, supplies[_token]);
}
}
文件 79 的 102:Pool.sol
pragma solidity 0.8.9;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "../interfaces/IWETH.sol";
import "../libraries/PbPool.sol";
import "../safeguard/Pauser.sol";
import "../safeguard/VolumeControl.sol";
import "../safeguard/DelayedTransfer.sol";
import "./Signers.sol";
contract Pool is Signers, ReentrancyGuard, Pauser, VolumeControl, DelayedTransfer {
using SafeERC20 for IERC20;
uint64 public addseq;
mapping(address => uint256) public minAdd;
mapping(bytes32 => bool) public withdraws;
address public nativeWrap;
event LiquidityAdded(
uint64 seqnum,
address provider,
address token,
uint256 amount
);
event WithdrawDone(
bytes32 withdrawId,
uint64 seqnum,
address receiver,
address token,
uint256 amount,
bytes32 refid
);
event MinAddUpdated(address token, uint256 amount);
function addLiquidity(address _token, uint256 _amount) external nonReentrant whenNotPaused {
require(_amount > minAdd[_token], "amount too small");
addseq += 1;
IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);
emit LiquidityAdded(addseq, msg.sender, _token, _amount);
}
function addNativeLiquidity(uint256 _amount) external payable nonReentrant whenNotPaused {
require(msg.value == _amount, "Amount mismatch");
require(nativeWrap != address(0), "Native wrap not set");
require(_amount > minAdd[nativeWrap], "amount too small");
addseq += 1;
IWETH(nativeWrap).deposit{value: _amount}();
emit LiquidityAdded(addseq, msg.sender, nativeWrap, _amount);
}
function withdraw(
bytes calldata _wdmsg,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers
) external whenNotPaused {
bytes32 domain = keccak256(abi.encodePacked(block.chainid, address(this), "WithdrawMsg"));
verifySigs(abi.encodePacked(domain, _wdmsg), _sigs, _signers, _powers);
PbPool.WithdrawMsg memory wdmsg = PbPool.decWithdrawMsg(_wdmsg);
bytes32 wdId = keccak256(
abi.encodePacked(wdmsg.chainid, wdmsg.seqnum, wdmsg.receiver, wdmsg.token, wdmsg.amount)
);
require(withdraws[wdId] == false, "withdraw already succeeded");
withdraws[wdId] = true;
_updateVolume(wdmsg.token, wdmsg.amount);
uint256 delayThreshold = delayThresholds[wdmsg.token];
if (delayThreshold > 0 && wdmsg.amount > delayThreshold) {
_addDelayedTransfer(wdId, wdmsg.receiver, wdmsg.token, wdmsg.amount);
} else {
_sendToken(wdmsg.receiver, wdmsg.token, wdmsg.amount);
}
emit WithdrawDone(wdId, wdmsg.seqnum, wdmsg.receiver, wdmsg.token, wdmsg.amount, wdmsg.refid);
}
function executeDelayedTransfer(bytes32 id) external whenNotPaused {
delayedTransfer memory transfer = _executeDelayedTransfer(id);
_sendToken(transfer.receiver, transfer.token, transfer.amount);
}
function setMinAdd(address[] calldata _tokens, uint256[] calldata _amounts) external onlyGovernor {
require(_tokens.length == _amounts.length, "length mismatch");
for (uint256 i = 0; i < _tokens.length; i++) {
minAdd[_tokens[i]] = _amounts[i];
emit MinAddUpdated(_tokens[i], _amounts[i]);
}
}
function _sendToken(
address _receiver,
address _token,
uint256 _amount
) internal {
if (_token == nativeWrap) {
IWETH(nativeWrap).withdraw(_amount);
(bool sent, ) = _receiver.call{value: _amount, gas: 50000}("");
require(sent, "failed to send native token");
} else {
IERC20(_token).safeTransfer(_receiver, _amount);
}
}
function setWrap(address _weth) external onlyOwner {
nativeWrap = _weth;
}
}
文件 80 的 102:ReentrancyGuard.sol
pragma solidity ^0.8.0;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
}
文件 81 的 102:RestrictedMultiBridgeTokenOwner.sol
pragma solidity 0.8.9;
import "../../../safeguard/Ownable.sol";
interface IMultiBridgeToken {
function updateBridgeSupplyCap(address _bridge, uint256 _cap) external;
}
contract RestrictedMultiBridgeTokenOwner is Ownable {
address public immutable token;
address public bridge;
constructor(address _token, address _bridge) {
token = _token;
bridge = _bridge;
}
function updateBridgeSupplyCap(uint256 _cap) external onlyOwner {
IMultiBridgeToken(token).updateBridgeSupplyCap(bridge, _cap);
}
function changeBridge(address _bridge, uint256 _cap) external onlyOwner {
IMultiBridgeToken(token).updateBridgeSupplyCap(bridge, 1);
IMultiBridgeToken(token).updateBridgeSupplyCap(_bridge, _cap);
bridge = _bridge;
}
function revokeBridge(address _bridge) external onlyOwner {
IMultiBridgeToken(token).updateBridgeSupplyCap(_bridge, 0);
}
}
文件 82 的 102:SGN.sol
pragma solidity 0.8.9;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {DataTypes as dt} from "./DataTypes.sol";
import "../libraries/PbSgn.sol";
import "../safeguard/Pauser.sol";
import "./Staking.sol";
contract SGN is Pauser {
using SafeERC20 for IERC20;
Staking public immutable staking;
bytes32[] public deposits;
mapping(address => mapping(address => uint256)) public withdrawnAmts;
mapping(address => bytes) public sgnAddrs;
event SgnAddrUpdate(address indexed valAddr, bytes oldAddr, bytes newAddr);
event Deposit(uint256 depositId, address account, address token, uint256 amount);
event Withdraw(address account, address token, uint256 amount);
constructor(Staking _staking) {
staking = _staking;
}
function updateSgnAddr(bytes calldata _sgnAddr) external {
address valAddr = msg.sender;
if (staking.signerVals(msg.sender) != address(0)) {
valAddr = staking.signerVals(msg.sender);
}
dt.ValidatorStatus status = staking.getValidatorStatus(valAddr);
require(status == dt.ValidatorStatus.Unbonded, "Not unbonded validator");
bytes memory oldAddr = sgnAddrs[valAddr];
sgnAddrs[valAddr] = _sgnAddr;
staking.validatorNotice(valAddr, "sgn-addr", _sgnAddr);
emit SgnAddrUpdate(valAddr, oldAddr, _sgnAddr);
}
function deposit(address _token, uint256 _amount) external whenNotPaused {
address msgSender = msg.sender;
deposits.push(keccak256(abi.encodePacked(msgSender, _token, _amount)));
IERC20(_token).safeTransferFrom(msgSender, address(this), _amount);
uint64 depositId = uint64(deposits.length - 1);
emit Deposit(depositId, msgSender, _token, _amount);
}
function withdraw(bytes calldata _withdrawalRequest, bytes[] calldata _sigs) external whenNotPaused {
bytes32 domain = keccak256(abi.encodePacked(block.chainid, address(this), "Withdrawal"));
staking.verifySignatures(abi.encodePacked(domain, _withdrawalRequest), _sigs);
PbSgn.Withdrawal memory withdrawal = PbSgn.decWithdrawal(_withdrawalRequest);
uint256 amount = withdrawal.cumulativeAmount - withdrawnAmts[withdrawal.account][withdrawal.token];
require(amount > 0, "No new amount to withdraw");
withdrawnAmts[withdrawal.account][withdrawal.token] = withdrawal.cumulativeAmount;
IERC20(withdrawal.token).safeTransfer(withdrawal.account, amount);
emit Withdraw(withdrawal.account, withdrawal.token, amount);
}
function drainToken(address _token, uint256 _amount) external whenPaused onlyOwner {
IERC20(_token).safeTransfer(msg.sender, _amount);
}
}
文件 83 的 102:SafeERC20.sol
pragma solidity ^0.8.0;
import "../IERC20.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 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
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");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
文件 84 的 102:Signers.sol
pragma solidity 0.8.9;
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "../safeguard/Ownable.sol";
import "../interfaces/ISigsVerifier.sol";
contract Signers is Ownable, ISigsVerifier {
using ECDSA for bytes32;
bytes32 public ssHash;
uint256 public triggerTime;
uint256 public resetTime;
uint256 public noticePeriod;
uint256 constant MAX_INT = 2**256 - 1;
event SignersUpdated(address[] _signers, uint256[] _powers);
event ResetNotification(uint256 resetTime);
function verifySigs(
bytes memory _msg,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers
) public view override {
bytes32 h = keccak256(abi.encodePacked(_signers, _powers));
require(ssHash == h, "Mismatch current signers");
_verifySignedPowers(keccak256(_msg).toEthSignedMessageHash(), _sigs, _signers, _powers);
}
function updateSigners(
uint256 _triggerTime,
address[] calldata _newSigners,
uint256[] calldata _newPowers,
bytes[] calldata _sigs,
address[] calldata _curSigners,
uint256[] calldata _curPowers
) external {
require(_triggerTime > triggerTime, "Trigger time is not increasing");
require(_triggerTime < block.timestamp + 3600, "Trigger time is too large");
bytes32 domain = keccak256(abi.encodePacked(block.chainid, address(this), "UpdateSigners"));
verifySigs(abi.encodePacked(domain, _triggerTime, _newSigners, _newPowers), _sigs, _curSigners, _curPowers);
_updateSigners(_newSigners, _newPowers);
triggerTime = _triggerTime;
}
function resetSigners(address[] calldata _signers, uint256[] calldata _powers) external onlyOwner {
require(block.timestamp > resetTime, "not reach reset time");
resetTime = MAX_INT;
_updateSigners(_signers, _powers);
}
function notifyResetSigners() external onlyOwner {
resetTime = block.timestamp + noticePeriod;
emit ResetNotification(resetTime);
}
function increaseNoticePeriod(uint256 period) external onlyOwner {
require(period > noticePeriod, "notice period can only be increased");
noticePeriod = period;
}
function _verifySignedPowers(
bytes32 _hash,
bytes[] calldata _sigs,
address[] calldata _signers,
uint256[] calldata _powers
) private pure {
require(_signers.length == _powers.length, "signers and powers length not match");
uint256 totalPower;
for (uint256 i = 0; i < _signers.length; i++) {
totalPower += _powers[i];
}
uint256 quorum = (totalPower * 2) / 3 + 1;
uint256 signedPower;
address prev = address(0);
uint256 index = 0;
for (uint256 i = 0; i < _sigs.length; i++) {
address signer = _hash.recover(_sigs[i]);
require(signer > prev, "signers not in ascending order");
prev = signer;
while (signer > _signers[index]) {
index += 1;
require(index < _signers.length, "signer not found");
}
if (signer == _signers[index]) {
signedPower += _powers[index];
}
if (signedPower >= quorum) {
return;
}
}
revert("quorum not reached");
}
function _updateSigners(address[] calldata _signers, uint256[] calldata _powers) private {
require(_signers.length == _powers.length, "signers and powers length not match");
address prev = address(0);
for (uint256 i = 0; i < _signers.length; i++) {
require(_signers[i] > prev, "New signers not in ascending order");
prev = _signers[i];
}
ssHash = keccak256(abi.encodePacked(_signers, _powers));
emit SignersUpdated(_signers, _powers);
}
}
文件 85 的 102:SingleBridgeToken.sol
pragma solidity 0.8.9;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract SingleBridgeToken is ERC20, Ownable {
address public bridge;
uint8 private immutable _decimals;
event BridgeUpdated(address bridge);
modifier onlyBridge() {
require(msg.sender == bridge, "caller is not bridge");
_;
}
constructor(
string memory name_,
string memory symbol_,
uint8 decimals_,
address bridge_
) ERC20(name_, symbol_) {
_decimals = decimals_;
bridge = bridge_;
}
function mint(address _to, uint256 _amount) external onlyBridge returns (bool) {
_mint(_to, _amount);
return true;
}
function burn(uint256 _amount) external returns (bool) {
_burn(msg.sender, _amount);
return true;
}
function burn(address _from, uint256 _amount) external returns (bool) {
return _burnFrom(_from, _amount);
}
function burnFrom(address _from, uint256 _amount) external returns (bool) {
return _burnFrom(_from, _amount);
}
function _burnFrom(address _from, uint256 _amount) internal returns (bool) {
_spendAllowance(_from, msg.sender, _amount);
_burn(_from, _amount);
return true;
}
function decimals() public view virtual override returns (uint8) {
return _decimals;
}
function updateBridge(address _bridge) external onlyOwner {
bridge = _bridge;
emit BridgeUpdated(bridge);
}
function getOwner() external view returns (address) {
return owner();
}
}
文件 86 的 102:SingleBridgeTokenPermit.sol
pragma solidity 0.8.9;
import "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol";
import "../SingleBridgeToken.sol";
contract SingleBridgeTokenPermit is ERC20Permit, SingleBridgeToken {
uint8 private immutable _decimals;
constructor(
string memory name_,
string memory symbol_,
uint8 decimals_,
address bridge_
) SingleBridgeToken(name_, symbol_, decimals_, bridge_) ERC20Permit(name_) {
_decimals = decimals_;
}
function decimals() public view override(ERC20, SingleBridgeToken) returns (uint8) {
return _decimals;
}
}
文件 87 的 102:Staking.sol
pragma solidity 0.8.9;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {DataTypes as dt} from "./DataTypes.sol";
import "../interfaces/ISigsVerifier.sol";
import "../libraries/PbStaking.sol";
import "../safeguard/Pauser.sol";
import "../safeguard/Whitelist.sol";
contract Staking is ISigsVerifier, Pauser, Whitelist {
using SafeERC20 for IERC20;
using ECDSA for bytes32;
IERC20 public immutable CELER_TOKEN;
uint256 public bondedTokens;
uint256 public nextBondBlock;
address[] public valAddrs;
address[] public bondedValAddrs;
mapping(address => dt.Validator) public validators;
mapping(address => address) public signerVals;
mapping(uint256 => bool) public slashNonces;
mapping(dt.ParamName => uint256) public params;
address public govContract;
address public rewardContract;
uint256 public forfeiture;
event ValidatorNotice(address indexed valAddr, string key, bytes data, address from);
event ValidatorStatusUpdate(address indexed valAddr, dt.ValidatorStatus indexed status);
event DelegationUpdate(
address indexed valAddr,
address indexed delAddr,
uint256 valTokens,
uint256 delShares,
int256 tokenDiff
);
event Undelegated(address indexed valAddr, address indexed delAddr, uint256 amount);
event Slash(address indexed valAddr, uint64 nonce, uint256 slashAmt);
event SlashAmtCollected(address indexed recipient, uint256 amount);
constructor(
address _celerTokenAddress,
uint256 _proposalDeposit,
uint256 _votingPeriod,
uint256 _unbondingPeriod,
uint256 _maxBondedValidators,
uint256 _minValidatorTokens,
uint256 _minSelfDelegation,
uint256 _advanceNoticePeriod,
uint256 _validatorBondInterval,
uint256 _maxSlashFactor
) {
CELER_TOKEN = IERC20(_celerTokenAddress);
params[dt.ParamName.ProposalDeposit] = _proposalDeposit;
params[dt.ParamName.VotingPeriod] = _votingPeriod;
params[dt.ParamName.UnbondingPeriod] = _unbondingPeriod;
params[dt.ParamName.MaxBondedValidators] = _maxBondedValidators;
params[dt.ParamName.MinValidatorTokens] = _minValidatorTokens;
params[dt.ParamName.MinSelfDelegation] = _minSelfDelegation;
params[dt.ParamName.AdvanceNoticePeriod] = _advanceNoticePeriod;
params[dt.ParamName.ValidatorBondInterval] = _validatorBondInterval;
params[dt.ParamName.MaxSlashFactor] = _maxSlashFactor;
}
receive() external payable {}
function initializeValidator(
address _signer,
uint256 _minSelfDelegation,
uint64 _commissionRate
) external whenNotPaused onlyWhitelisted {
address valAddr = msg.sender;
dt.Validator storage validator = validators[valAddr];
require(validator.status == dt.ValidatorStatus.Null, "Validator is initialized");
require(validators[_signer].status == dt.ValidatorStatus.Null, "Signer is other validator");
require(signerVals[valAddr] == address(0), "Validator is other signer");
require(signerVals[_signer] == address(0), "Signer already used");
require(_commissionRate <= dt.COMMISSION_RATE_BASE, "Invalid commission rate");
require(_minSelfDelegation >= params[dt.ParamName.MinSelfDelegation], "Insufficient min self delegation");
validator.signer = _signer;
validator.status = dt.ValidatorStatus.Unbonded;
validator.minSelfDelegation = _minSelfDelegation;
validator.commissionRate = _commissionRate;
valAddrs.push(valAddr);
signerVals[_signer] = valAddr;
delegate(valAddr, _minSelfDelegation);
emit ValidatorNotice(valAddr, "init", abi.encode(_signer, _minSelfDelegation, _commissionRate), address(0));
}
function updateValidatorSigner(address _signer) external {
address valAddr = msg.sender;
dt.Validator storage validator = validators[valAddr];
require(validator.status != dt.ValidatorStatus.Null, "Validator not initialized");
require(signerVals[_signer] == address(0), "Signer already used");
if (_signer != valAddr) {
require(validators[_signer].status == dt.ValidatorStatus.Null, "Signer is other validator");
}
delete signerVals[validator.signer];
validator.signer = _signer;
signerVals[_signer] = valAddr;
emit ValidatorNotice(valAddr, "signer", abi.encode(_signer), address(0));
}
function bondValidator() external {
address valAddr = msg.sender;
if (signerVals[msg.sender] != address(0)) {
valAddr = signerVals[msg.sender];
}
dt.Validator storage validator = validators[valAddr];
require(
validator.status == dt.ValidatorStatus.Unbonded || validator.status == dt.ValidatorStatus.Unbonding,
"Invalid validator status"
);
require(block.number >= validator.bondBlock, "Bond block not reached");
require(block.number >= nextBondBlock, "Too frequent validator bond");
nextBondBlock = block.number + params[dt.ParamName.ValidatorBondInterval];
require(hasMinRequiredTokens(valAddr, true), "Not have min tokens");
uint256 maxBondedValidators = params[dt.ParamName.MaxBondedValidators];
if (bondedValAddrs.length < maxBondedValidators) {
_bondValidator(valAddr);
_decentralizationCheck(validator.tokens);
return;
}
uint256 minTokens = dt.MAX_INT;
uint256 minTokensIndex;
for (uint256 i = 0; i < maxBondedValidators; i++) {
if (validators[bondedValAddrs[i]].tokens < minTokens) {
minTokensIndex = i;
minTokens = validators[bondedValAddrs[i]].tokens;
if (minTokens == 0) {
break;
}
}
}
require(validator.tokens > minTokens, "Insufficient tokens");
_replaceBondedValidator(valAddr, minTokensIndex);
_decentralizationCheck(validator.tokens);
}
function confirmUnbondedValidator(address _valAddr) external {
dt.Validator storage validator = validators[_valAddr];
require(validator.status == dt.ValidatorStatus.Unbonding, "Validator not unbonding");
require(block.number >= validator.unbondBlock, "Unbond block not reached");
validator.status = dt.ValidatorStatus.Unbonded;
delete validator.unbondBlock;
emit ValidatorStatusUpdate(_valAddr, dt.ValidatorStatus.Unbonded);
}
function delegate(address _valAddr, uint256 _tokens) public whenNotPaused {
address delAddr = msg.sender;
require(_tokens >= dt.CELR_DECIMAL, "Minimal amount is 1 CELR");
dt.Validator storage validator = validators[_valAddr];
require(validator.status != dt.ValidatorStatus.Null, "Validator is not initialized");
uint256 shares = _tokenToShare(_tokens, validator.tokens, validator.shares);
dt.Delegator storage delegator = validator.delegators[delAddr];
delegator.shares += shares;
validator.shares += shares;
validator.tokens += _tokens;
if (validator.status == dt.ValidatorStatus.Bonded) {
bondedTokens += _tokens;
_decentralizationCheck(validator.tokens);
}
CELER_TOKEN.safeTransferFrom(delAddr, address(this), _tokens);
emit DelegationUpdate(_valAddr, delAddr, validator.tokens, delegator.shares, int256(_tokens));
}
function undelegateShares(address _valAddr, uint256 _shares) external {
require(_shares >= dt.CELR_DECIMAL, "Minimal amount is 1 share");
dt.Validator storage validator = validators[_valAddr];
require(validator.status != dt.ValidatorStatus.Null, "Validator is not initialized");
uint256 tokens = _shareToToken(_shares, validator.tokens, validator.shares);
_undelegate(validator, _valAddr, tokens, _shares);
}
function undelegateTokens(address _valAddr, uint256 _tokens) external {
require(_tokens >= dt.CELR_DECIMAL, "Minimal amount is 1 CELR");
dt.Validator storage validator = validators[_valAddr];
require(validator.status != dt.ValidatorStatus.Null, "Validator is not initialized");
uint256 shares = _tokenToShare(_tokens, validator.tokens, validator.shares);
_undelegate(validator, _valAddr, _tokens, shares);
}
function completeUndelegate(address _valAddr) external {
address delAddr = msg.sender;
dt.Validator storage validator = validators[_valAddr];
require(validator.status != dt.ValidatorStatus.Null, "Validator is not initialized");
dt.Delegator storage delegator = validator.delegators[delAddr];
uint256 unbondingPeriod = params[dt.ParamName.UnbondingPeriod];
bool isUnbonded = validator.status == dt.ValidatorStatus.Unbonded;
uint32 i;
uint256 undelegationShares;
for (i = delegator.undelegations.head; i < delegator.undelegations.tail; i++) {
if (isUnbonded || delegator.undelegations.queue[i].creationBlock + unbondingPeriod <= block.number) {
undelegationShares += delegator.undelegations.queue[i].shares;
delete delegator.undelegations.queue[i];
continue;
}
break;
}
delegator.undelegations.head = i;
require(undelegationShares > 0, "No undelegation ready to be completed");
uint256 tokens = _shareToToken(undelegationShares, validator.undelegationTokens, validator.undelegationShares);
validator.undelegationShares -= undelegationShares;
validator.undelegationTokens -= tokens;
CELER_TOKEN.safeTransfer(delAddr, tokens);
emit Undelegated(_valAddr, delAddr, tokens);
}
function updateCommissionRate(uint64 _newRate) external {
address valAddr = msg.sender;
dt.Validator storage validator = validators[valAddr];
require(validator.status != dt.ValidatorStatus.Null, "Validator is not initialized");
require(_newRate <= dt.COMMISSION_RATE_BASE, "Invalid new rate");
validator.commissionRate = _newRate;
emit ValidatorNotice(valAddr, "commission", abi.encode(_newRate), address(0));
}
function updateMinSelfDelegation(uint256 _minSelfDelegation) external {
address valAddr = msg.sender;
dt.Validator storage validator = validators[valAddr];
require(validator.status != dt.ValidatorStatus.Null, "Validator is not initialized");
require(_minSelfDelegation >= params[dt.ParamName.MinSelfDelegation], "Insufficient min self delegation");
if (_minSelfDelegation < validator.minSelfDelegation) {
require(validator.status != dt.ValidatorStatus.Bonded, "Validator is bonded");
validator.bondBlock = uint64(block.number + params[dt.ParamName.AdvanceNoticePeriod]);
}
validator.minSelfDelegation = _minSelfDelegation;
emit ValidatorNotice(valAddr, "min-self-delegation", abi.encode(_minSelfDelegation), address(0));
}
function slash(bytes calldata _slashRequest, bytes[] calldata _sigs) external whenNotPaused {
bytes32 domain = keccak256(abi.encodePacked(block.chainid, address(this), "Slash"));
verifySignatures(abi.encodePacked(domain, _slashRequest), _sigs);
PbStaking.Slash memory request = PbStaking.decSlash(_slashRequest);
require(block.timestamp < request.expireTime, "Slash expired");
require(request.slashFactor <= dt.SLASH_FACTOR_DECIMAL, "Invalid slash factor");
require(request.slashFactor <= params[dt.ParamName.MaxSlashFactor], "Exceed max slash factor");
require(!slashNonces[request.nonce], "Used slash nonce");
slashNonces[request.nonce] = true;
address valAddr = request.validator;
dt.Validator storage validator = validators[valAddr];
require(
validator.status == dt.ValidatorStatus.Bonded || validator.status == dt.ValidatorStatus.Unbonding,
"Invalid validator status"
);
uint256 slashAmt = (validator.tokens * request.slashFactor) / dt.SLASH_FACTOR_DECIMAL;
validator.tokens -= slashAmt;
if (validator.status == dt.ValidatorStatus.Bonded) {
bondedTokens -= slashAmt;
if (request.jailPeriod > 0 || !hasMinRequiredTokens(valAddr, true)) {
_unbondValidator(valAddr);
}
}
if (validator.status == dt.ValidatorStatus.Unbonding && request.jailPeriod > 0) {
validator.bondBlock = uint64(block.number + request.jailPeriod);
}
emit DelegationUpdate(valAddr, address(0), validator.tokens, 0, -int256(slashAmt));
uint256 slashUndelegation = (validator.undelegationTokens * request.slashFactor) / dt.SLASH_FACTOR_DECIMAL;
validator.undelegationTokens -= slashUndelegation;
slashAmt += slashUndelegation;
uint256 collectAmt;
for (uint256 i = 0; i < request.collectors.length; i++) {
PbStaking.AcctAmtPair memory collector = request.collectors[i];
if (collectAmt + collector.amount > slashAmt) {
collector.amount = slashAmt - collectAmt;
}
if (collector.amount > 0) {
collectAmt += collector.amount;
if (collector.account == address(0)) {
CELER_TOKEN.safeTransfer(msg.sender, collector.amount);
emit SlashAmtCollected(msg.sender, collector.amount);
} else {
CELER_TOKEN.safeTransfer(collector.account, collector.amount);
emit SlashAmtCollected(collector.account, collector.amount);
}
}
}
forfeiture += slashAmt - collectAmt;
emit Slash(valAddr, request.nonce, slashAmt);
}
function collectForfeiture() external {
require(forfeiture > 0, "Nothing to collect");
CELER_TOKEN.safeTransfer(rewardContract, forfeiture);
forfeiture = 0;
}
function validatorNotice(
address _valAddr,
string calldata _key,
bytes calldata _data
) external {
dt.Validator storage validator = validators[_valAddr];
require(validator.status != dt.ValidatorStatus.Null, "Validator is not initialized");
emit ValidatorNotice(_valAddr, _key, _data, msg.sender);
}
function setParamValue(dt.ParamName _name, uint256 _value) external {
require(msg.sender == govContract, "Caller is not gov contract");
if (_name == dt.ParamName.MaxBondedValidators) {
require(bondedValAddrs.length <= _value, "invalid value");
}
params[_name] = _value;
}
function setGovContract(address _addr) external onlyOwner {
govContract = _addr;
}
function setRewardContract(address _addr) external onlyOwner {
rewardContract = _addr;
}
function setMaxSlashFactor(uint256 _maxSlashFactor) external onlyOwner {
params[dt.ParamName.MaxSlashFactor] = _maxSlashFactor;
}
function drainToken(uint256 _amount) external whenPaused onlyOwner {
CELER_TOKEN.safeTransfer(msg.sender, _amount);
}
function verifySignatures(bytes memory _msg, bytes[] memory _sigs) public view returns (bool) {
bytes32 hash = keccak256(_msg).toEthSignedMessageHash();
uint256 signedTokens;
address prev = address(0);
uint256 quorum = getQuorumTokens();
for (uint256 i = 0; i < _sigs.length; i++) {
address signer = hash.recover(_sigs[i]);
require(signer > prev, "Signers not in ascending order");
prev = signer;
dt.Validator storage validator = validators[signerVals[signer]];
if (validator.status != dt.ValidatorStatus.Bonded) {
continue;
}
signedTokens += validator.tokens;
if (signedTokens >= quorum) {
return true;
}
}
revert("Quorum not reached");
}
function verifySigs(
bytes memory _msg,
bytes[] calldata _sigs,
address[] calldata,
uint256[] calldata
) public view override {
require(verifySignatures(_msg, _sigs), "Failed to verify sigs");
}
function getQuorumTokens() public view returns (uint256) {
return (bondedTokens * 2) / 3 + 1;
}
function getValidatorTokens(address _valAddr) public view returns (uint256) {
return validators[_valAddr].tokens;
}
function getValidatorStatus(address _valAddr) public view returns (dt.ValidatorStatus) {
return validators[_valAddr].status;
}
function isBondedValidator(address _addr) public view returns (bool) {
return validators[_addr].status == dt.ValidatorStatus.Bonded;
}
function getValidatorNum() public view returns (uint256) {
return valAddrs.length;
}
function getBondedValidatorNum() public view returns (uint256) {
return bondedValAddrs.length;
}
function getBondedValidatorsTokens() public view returns (dt.ValidatorTokens[] memory) {
dt.ValidatorTokens[] memory infos = new dt.ValidatorTokens[](bondedValAddrs.length);
for (uint256 i = 0; i < bondedValAddrs.length; i++) {
address valAddr = bondedValAddrs[i];
infos[i] = dt.ValidatorTokens(valAddr, validators[valAddr].tokens);
}
return infos;
}
function hasMinRequiredTokens(address _valAddr, bool _checkSelfDelegation) public view returns (bool) {
dt.Validator storage v = validators[_valAddr];
uint256 valTokens = v.tokens;
if (valTokens < params[dt.ParamName.MinValidatorTokens]) {
return false;
}
if (_checkSelfDelegation) {
uint256 selfDelegation = _shareToToken(v.delegators[_valAddr].shares, valTokens, v.shares);
if (selfDelegation < v.minSelfDelegation) {
return false;
}
}
return true;
}
function getDelegatorInfo(address _valAddr, address _delAddr) public view returns (dt.DelegatorInfo memory) {
dt.Validator storage validator = validators[_valAddr];
dt.Delegator storage d = validator.delegators[_delAddr];
uint256 tokens = _shareToToken(d.shares, validator.tokens, validator.shares);
uint256 undelegationShares;
uint256 withdrawableUndelegationShares;
uint256 unbondingPeriod = params[dt.ParamName.UnbondingPeriod];
bool isUnbonded = validator.status == dt.ValidatorStatus.Unbonded;
uint256 len = d.undelegations.tail - d.undelegations.head;
dt.Undelegation[] memory undelegations = new dt.Undelegation[](len);
for (uint256 i = 0; i < len; i++) {
undelegations[i] = d.undelegations.queue[i + d.undelegations.head];
undelegationShares += undelegations[i].shares;
if (isUnbonded || undelegations[i].creationBlock + unbondingPeriod <= block.number) {
withdrawableUndelegationShares += undelegations[i].shares;
}
}
uint256 undelegationTokens = _shareToToken(
undelegationShares,
validator.undelegationTokens,
validator.undelegationShares
);
uint256 withdrawableUndelegationTokens = _shareToToken(
withdrawableUndelegationShares,
validator.undelegationTokens,
validator.undelegationShares
);
return
dt.DelegatorInfo(
_valAddr,
tokens,
d.shares,
undelegations,
undelegationTokens,
withdrawableUndelegationTokens
);
}
function getParamValue(dt.ParamName _name) public view returns (uint256) {
return params[_name];
}
function _undelegate(
dt.Validator storage validator,
address _valAddr,
uint256 _tokens,
uint256 _shares
) private {
address delAddr = msg.sender;
dt.Delegator storage delegator = validator.delegators[delAddr];
delegator.shares -= _shares;
validator.shares -= _shares;
validator.tokens -= _tokens;
if (validator.tokens != validator.shares && delegator.shares <= 2) {
validator.shares -= delegator.shares;
delegator.shares = 0;
}
require(delegator.shares == 0 || delegator.shares >= dt.CELR_DECIMAL, "not enough remaining shares");
if (validator.status == dt.ValidatorStatus.Unbonded) {
CELER_TOKEN.safeTransfer(delAddr, _tokens);
emit Undelegated(_valAddr, delAddr, _tokens);
return;
} else if (validator.status == dt.ValidatorStatus.Bonded) {
bondedTokens -= _tokens;
if (!hasMinRequiredTokens(_valAddr, delAddr == _valAddr)) {
_unbondValidator(_valAddr);
}
}
require(
delegator.undelegations.tail - delegator.undelegations.head < dt.MAX_UNDELEGATION_ENTRIES,
"Exceed max undelegation entries"
);
uint256 undelegationShares = _tokenToShare(_tokens, validator.undelegationTokens, validator.undelegationShares);
validator.undelegationShares += undelegationShares;
validator.undelegationTokens += _tokens;
dt.Undelegation storage undelegation = delegator.undelegations.queue[delegator.undelegations.tail];
undelegation.shares = undelegationShares;
undelegation.creationBlock = block.number;
delegator.undelegations.tail++;
emit DelegationUpdate(_valAddr, delAddr, validator.tokens, delegator.shares, -int256(_tokens));
}
function _setBondedValidator(address _valAddr) private {
dt.Validator storage validator = validators[_valAddr];
validator.status = dt.ValidatorStatus.Bonded;
delete validator.unbondBlock;
bondedTokens += validator.tokens;
emit ValidatorStatusUpdate(_valAddr, dt.ValidatorStatus.Bonded);
}
function _setUnbondingValidator(address _valAddr) private {
dt.Validator storage validator = validators[_valAddr];
validator.status = dt.ValidatorStatus.Unbonding;
validator.unbondBlock = uint64(block.number + params[dt.ParamName.UnbondingPeriod]);
bondedTokens -= validator.tokens;
emit ValidatorStatusUpdate(_valAddr, dt.ValidatorStatus.Unbonding);
}
function _bondValidator(address _valAddr) private {
bondedValAddrs.push(_valAddr);
_setBondedValidator(_valAddr);
}
function _replaceBondedValidator(address _valAddr, uint256 _index) private {
_setUnbondingValidator(bondedValAddrs[_index]);
bondedValAddrs[_index] = _valAddr;
_setBondedValidator(_valAddr);
}
function _unbondValidator(address _valAddr) private {
uint256 lastIndex = bondedValAddrs.length - 1;
for (uint256 i = 0; i < bondedValAddrs.length; i++) {
if (bondedValAddrs[i] == _valAddr) {
if (i < lastIndex) {
bondedValAddrs[i] = bondedValAddrs[lastIndex];
}
bondedValAddrs.pop();
_setUnbondingValidator(_valAddr);
return;
}
}
revert("Not bonded validator");
}
function _decentralizationCheck(uint256 _valTokens) private view {
uint256 bondedValNum = bondedValAddrs.length;
if (bondedValNum == 2 || bondedValNum == 3) {
require(_valTokens < getQuorumTokens(), "Single validator should not have quorum tokens");
} else if (bondedValNum > 3) {
require(_valTokens < bondedTokens / 3, "Single validator should not have 1/3 tokens");
}
}
function _tokenToShare(
uint256 tokens,
uint256 totalTokens,
uint256 totalShares
) private pure returns (uint256) {
if (totalTokens == 0) {
return tokens;
}
return (tokens * totalShares) / totalTokens;
}
function _shareToToken(
uint256 shares,
uint256 totalTokens,
uint256 totalShares
) private pure returns (uint256) {
if (totalShares == 0) {
return shares;
}
return (shares * totalTokens) / totalShares;
}
}
文件 88 的 102:StakingReward.sol
pragma solidity 0.8.9;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {DataTypes as dt} from "./DataTypes.sol";
import "../safeguard/Pauser.sol";
import "./Staking.sol";
contract StakingReward is Pauser {
using SafeERC20 for IERC20;
Staking public immutable staking;
mapping(address => uint256) public claimedRewardAmounts;
event StakingRewardClaimed(address indexed recipient, uint256 reward);
event StakingRewardContributed(address indexed contributor, uint256 contribution);
constructor(Staking _staking) {
staking = _staking;
}
function claimReward(bytes calldata _rewardRequest, bytes[] calldata _sigs) external whenNotPaused {
bytes32 domain = keccak256(abi.encodePacked(block.chainid, address(this), "StakingReward"));
staking.verifySignatures(abi.encodePacked(domain, _rewardRequest), _sigs);
PbStaking.StakingReward memory reward = PbStaking.decStakingReward(_rewardRequest);
uint256 cumulativeRewardAmount = reward.cumulativeRewardAmount;
uint256 newReward = cumulativeRewardAmount - claimedRewardAmounts[reward.recipient];
require(newReward > 0, "No new reward");
claimedRewardAmounts[reward.recipient] = cumulativeRewardAmount;
staking.CELER_TOKEN().safeTransfer(reward.recipient, newReward);
emit StakingRewardClaimed(reward.recipient, newReward);
}
function contributeToRewardPool(uint256 _amount) external whenNotPaused {
address contributor = msg.sender;
IERC20(staking.CELER_TOKEN()).safeTransferFrom(contributor, address(this), _amount);
emit StakingRewardContributed(contributor, _amount);
}
function drainToken(uint256 _amount) external whenPaused onlyOwner {
IERC20(staking.CELER_TOKEN()).safeTransfer(msg.sender, _amount);
}
}
文件 89 的 102:Strings.sol
pragma solidity ^0.8.0;
library Strings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
function toString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
}
文件 90 的 102:SwapBridgeToken.sol
pragma solidity >=0.8.9;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
interface ISwapCanoToken {
function swapBridgeForCanonical(address, uint256) external returns (uint256);
function swapCanonicalForBridge(address, uint256) external returns (uint256);
}
contract SwapBridgeToken is ERC20, Ownable {
using SafeERC20 for IERC20;
address public bridge;
address public immutable canonical;
event BridgeUpdated(address bridge);
modifier onlyBridge() {
require(msg.sender == bridge, "caller is not bridge");
_;
}
constructor(
string memory name_,
string memory symbol_,
address bridge_,
address canonical_
) ERC20(name_, symbol_) {
bridge = bridge_;
canonical = canonical_;
}
function mint(address _to, uint256 _amount) external onlyBridge returns (bool) {
_mint(address(this), _amount);
uint256 got = ISwapCanoToken(canonical).swapBridgeForCanonical(address(this), _amount);
IERC20(canonical).safeTransfer(_to, got);
return true;
}
function burn(address _from, uint256 _amount) external onlyBridge returns (bool) {
IERC20(canonical).safeTransferFrom(_from, address(this), _amount);
uint256 got = ISwapCanoToken(canonical).swapCanonicalForBridge(address(this), _amount);
_burn(address(this), got);
return true;
}
function updateBridge(address _bridge) external onlyOwner {
bridge = _bridge;
emit BridgeUpdated(bridge);
}
function approveCanonical() external onlyOwner {
_approve(address(this), canonical, type(uint256).max);
}
function revokeCanonical() external onlyOwner {
_approve(address(this), canonical, 0);
}
function getOwner() external view returns (address) {
return owner();
}
function decimals() public view virtual override returns (uint8) {
return ERC20(canonical).decimals();
}
}
文件 91 的 102:TestERC20.sol
pragma solidity 0.8.9;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract TestERC20 is ERC20 {
uint256 public constant INITIAL_SUPPLY = 1e28;
constructor() ERC20("TestERC20", "TERC20") {
_mint(msg.sender, INITIAL_SUPPLY);
}
}
文件 92 的 102:TransferSwap.sol
pragma solidity >=0.8.9;
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../framework/MessageBusAddress.sol";
import "../framework/MessageSenderApp.sol";
import "../framework/MessageReceiverApp.sol";
import "../../interfaces/IWETH.sol";
import "../../interfaces/IUniswapV2.sol";
contract TransferSwap is MessageSenderApp, MessageReceiverApp {
using SafeERC20 for IERC20;
modifier onlyEOA() {
require(msg.sender == tx.origin, "Not EOA");
_;
}
struct SwapInfo {
address[] path;
address dex;
uint256 deadline;
uint256 minRecvAmt;
}
struct SwapRequest {
SwapInfo swap;
address receiver;
uint64 nonce;
bool nativeOut;
}
enum SwapStatus {
Null,
Succeeded,
Failed,
Fallback
}
event DirectSwap(
bytes32 id,
uint64 srcChainId,
uint256 amountIn,
address tokenIn,
uint256 amountOut,
address tokenOut
);
event SwapRequestSent(bytes32 id, uint64 dstChainId, uint256 srcAmount, address srcToken, address dstToken);
event SwapRequestDone(bytes32 id, uint256 dstAmount, SwapStatus status);
mapping(address => uint256) public minSwapAmounts;
mapping(address => bool) supportedDex;
address public nativeWrap;
constructor(
address _messageBus,
address _supportedDex,
address _nativeWrap
) {
messageBus = _messageBus;
supportedDex[_supportedDex] = true;
nativeWrap = _nativeWrap;
}
function transferWithSwapNative(
address _receiver,
uint256 _amountIn,
uint64 _dstChainId,
SwapInfo calldata _srcSwap,
SwapInfo calldata _dstSwap,
uint32 _maxBridgeSlippage,
uint64 _nonce,
bool _nativeOut
) external payable onlyEOA {
require(msg.value >= _amountIn, "Amount insufficient");
require(_srcSwap.path[0] == nativeWrap, "token mismatch");
IWETH(nativeWrap).deposit{value: _amountIn}();
_transferWithSwap(
_receiver,
_amountIn,
_dstChainId,
_srcSwap,
_dstSwap,
_maxBridgeSlippage,
_nonce,
_nativeOut,
msg.value - _amountIn
);
}
function transferWithSwap(
address _receiver,
uint256 _amountIn,
uint64 _dstChainId,
SwapInfo calldata _srcSwap,
SwapInfo calldata _dstSwap,
uint32 _maxBridgeSlippage,
uint64 _nonce
) external payable onlyEOA {
IERC20(_srcSwap.path[0]).safeTransferFrom(msg.sender, address(this), _amountIn);
_transferWithSwap(
_receiver,
_amountIn,
_dstChainId,
_srcSwap,
_dstSwap,
_maxBridgeSlippage,
_nonce,
false,
msg.value
);
}
function _transferWithSwap(
address _receiver,
uint256 _amountIn,
uint64 _dstChainId,
SwapInfo memory _srcSwap,
SwapInfo memory _dstSwap,
uint32 _maxBridgeSlippage,
uint64 _nonce,
bool _nativeOut,
uint256 _fee
) private {
require(_srcSwap.path.length > 0, "empty src swap path");
address srcTokenOut = _srcSwap.path[_srcSwap.path.length - 1];
require(_amountIn > minSwapAmounts[_srcSwap.path[0]], "amount must be greater than min swap amount");
uint64 chainId = uint64(block.chainid);
require(_srcSwap.path.length > 1 || _dstChainId != chainId, "noop is not allowed");
uint256 srcAmtOut = _amountIn;
if (_srcSwap.path.length > 1) {
bool ok = true;
(ok, srcAmtOut) = _trySwap(_srcSwap, _amountIn);
if (!ok) revert("src swap failed");
}
if (_dstChainId == chainId) {
_directSend(_receiver, _amountIn, chainId, _srcSwap, _nonce, srcTokenOut, srcAmtOut);
} else {
_crossChainTransferWithSwap(
_receiver,
_amountIn,
chainId,
_dstChainId,
_srcSwap,
_dstSwap,
_maxBridgeSlippage,
_nonce,
_nativeOut,
_fee,
srcTokenOut,
srcAmtOut
);
}
}
function _directSend(
address _receiver,
uint256 _amountIn,
uint64 _chainId,
SwapInfo memory _srcSwap,
uint64 _nonce,
address srcTokenOut,
uint256 srcAmtOut
) private {
IERC20(srcTokenOut).safeTransfer(_receiver, srcAmtOut);
bytes32 id = keccak256(abi.encode(msg.sender, _chainId, _receiver, _nonce, _srcSwap));
emit DirectSwap(id, _chainId, _amountIn, _srcSwap.path[0], srcAmtOut, srcTokenOut);
}
function _crossChainTransferWithSwap(
address _receiver,
uint256 _amountIn,
uint64 _chainId,
uint64 _dstChainId,
SwapInfo memory _srcSwap,
SwapInfo memory _dstSwap,
uint32 _maxBridgeSlippage,
uint64 _nonce,
bool _nativeOut,
uint256 _fee,
address srcTokenOut,
uint256 srcAmtOut
) private {
require(_dstSwap.path.length > 0, "empty dst swap path");
bytes memory message = abi.encode(
SwapRequest({swap: _dstSwap, receiver: msg.sender, nonce: _nonce, nativeOut: _nativeOut})
);
bytes32 id = _computeSwapRequestId(msg.sender, _chainId, _dstChainId, message);
sendMessageWithTransfer(
_receiver,
srcTokenOut,
srcAmtOut,
_dstChainId,
_nonce,
_maxBridgeSlippage,
message,
MsgDataTypes.BridgeSendType.Liquidity,
_fee
);
emit SwapRequestSent(id, _dstChainId, _amountIn, _srcSwap.path[0], _dstSwap.path[_dstSwap.path.length - 1]);
}
function executeMessageWithTransfer(
address,
address _token,
uint256 _amount,
uint64 _srcChainId,
bytes memory _message,
address
) external payable override onlyMessageBus returns (ExecutionStatus) {
SwapRequest memory m = abi.decode((_message), (SwapRequest));
require(_token == m.swap.path[0], "bridged token must be the same as the first token in destination swap path");
bytes32 id = _computeSwapRequestId(m.receiver, _srcChainId, uint64(block.chainid), _message);
uint256 dstAmount;
SwapStatus status = SwapStatus.Succeeded;
if (m.swap.path.length > 1) {
bool ok = true;
(ok, dstAmount) = _trySwap(m.swap, _amount);
if (ok) {
_sendToken(m.swap.path[m.swap.path.length - 1], dstAmount, m.receiver, m.nativeOut);
status = SwapStatus.Succeeded;
} else {
_sendToken(_token, _amount, m.receiver, false);
dstAmount = _amount;
status = SwapStatus.Fallback;
}
} else {
_sendToken(m.swap.path[0], _amount, m.receiver, m.nativeOut);
dstAmount = _amount;
status = SwapStatus.Succeeded;
}
emit SwapRequestDone(id, dstAmount, status);
return ExecutionStatus.Success;
}
function executeMessageWithTransferFallback(
address,
address,
uint256,
uint64 _srcChainId,
bytes memory _message,
address
) external payable override onlyMessageBus returns (ExecutionStatus) {
SwapRequest memory m = abi.decode((_message), (SwapRequest));
bytes32 id = _computeSwapRequestId(m.receiver, _srcChainId, uint64(block.chainid), _message);
emit SwapRequestDone(id, 0, SwapStatus.Failed);
return ExecutionStatus.Fail;
}
function _trySwap(SwapInfo memory _swap, uint256 _amount) private returns (bool ok, uint256 amountOut) {
uint256 zero;
if (!supportedDex[_swap.dex]) {
return (false, zero);
}
IERC20(_swap.path[0]).safeIncreaseAllowance(_swap.dex, _amount);
try
IUniswapV2(_swap.dex).swapExactTokensForTokens(
_amount,
_swap.minRecvAmt,
_swap.path,
address(this),
_swap.deadline
)
returns (uint256[] memory amounts) {
return (true, amounts[amounts.length - 1]);
} catch {
return (false, zero);
}
}
function _sendToken(
address _token,
uint256 _amount,
address _receiver,
bool _nativeOut
) private {
if (_nativeOut) {
require(_token == nativeWrap, "token mismatch");
IWETH(nativeWrap).withdraw(_amount);
(bool sent, ) = _receiver.call{value: _amount, gas: 50000}("");
require(sent, "failed to send native");
} else {
IERC20(_token).safeTransfer(_receiver, _amount);
}
}
function _computeSwapRequestId(
address _sender,
uint64 _srcChainId,
uint64 _dstChainId,
bytes memory _message
) private pure returns (bytes32) {
return keccak256(abi.encodePacked(_sender, _srcChainId, _dstChainId, _message));
}
function setMinSwapAmount(address _token, uint256 _minSwapAmount) external onlyOwner {
minSwapAmounts[_token] = _minSwapAmount;
}
function setSupportedDex(address _dex, bool _enabled) external onlyOwner {
supportedDex[_dex] = _enabled;
}
function setNativeWrap(address _nativeWrap) external onlyOwner {
nativeWrap = _nativeWrap;
}
receive() external payable {}
}
文件 93 的 102:TransferSwapSendBack.sol
pragma solidity >=0.8.9;
import "../framework/MessageSenderApp.sol";
import "../framework/MessageReceiverApp.sol";
interface ISwapToken {
function swapExactTokensForTokens(
uint256,
uint256,
address[] calldata,
address,
uint256
) external returns (uint256[] memory);
}
contract CrossChainSwap is MessageSenderApp, MessageReceiverApp {
using SafeERC20 for IERC20;
address public dex;
struct SwapInfo {
address wantToken;
address user;
bool sendBack;
uint32 cbrMaxSlippage;
}
constructor(address dex_) {
dex = dex_;
}
uint64 nonce;
function startCrossChainSwap(
address _receiver,
address _token,
uint256 _amount,
uint64 _dstChainId,
SwapInfo calldata swapInfo
) external payable {
nonce += 1;
IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);
bytes memory message = abi.encode(swapInfo);
sendMessageWithTransfer(
_receiver,
_token,
_amount,
_dstChainId,
nonce,
swapInfo.cbrMaxSlippage,
message,
MsgDataTypes.BridgeSendType.Liquidity,
msg.value
);
}
function executeMessageWithTransfer(
address,
address _token,
uint256 _amount,
uint64 _srcChainId,
bytes memory _message,
address
) external payable override onlyMessageBus returns (ExecutionStatus) {
SwapInfo memory swapInfo = abi.decode((_message), (SwapInfo));
IERC20(_token).approve(dex, _amount);
address[] memory path = new address[](2);
path[0] = _token;
path[1] = swapInfo.wantToken;
if (swapInfo.sendBack) {
nonce += 1;
uint256[] memory swapReturn = ISwapToken(dex).swapExactTokensForTokens(
_amount,
0,
path,
address(this),
type(uint256).max
);
sendTokenTransfer(
swapInfo.user,
swapInfo.wantToken,
swapReturn[1],
_srcChainId,
nonce,
swapInfo.cbrMaxSlippage,
MsgDataTypes.BridgeSendType.Liquidity
);
} else {
ISwapToken(dex).swapExactTokensForTokens(_amount, 0, path, swapInfo.user, type(uint256).max);
}
return ExecutionStatus.Success;
}
}
文件 94 的 102:Viewer.sol
pragma solidity 0.8.9;
import {DataTypes as dt} from "./DataTypes.sol";
import "./Staking.sol";
contract Viewer {
Staking public immutable staking;
constructor(Staking _staking) {
staking = _staking;
}
function getValidatorInfos() public view returns (dt.ValidatorInfo[] memory) {
uint256 valNum = staking.getValidatorNum();
dt.ValidatorInfo[] memory infos = new dt.ValidatorInfo[](valNum);
for (uint32 i = 0; i < valNum; i++) {
infos[i] = getValidatorInfo(staking.valAddrs(i));
}
return infos;
}
function getBondedValidatorInfos() public view returns (dt.ValidatorInfo[] memory) {
uint256 bondedValNum = staking.getBondedValidatorNum();
dt.ValidatorInfo[] memory infos = new dt.ValidatorInfo[](bondedValNum);
for (uint32 i = 0; i < bondedValNum; i++) {
infos[i] = getValidatorInfo(staking.bondedValAddrs(i));
}
return infos;
}
function getValidatorInfo(address _valAddr) public view returns (dt.ValidatorInfo memory) {
(
dt.ValidatorStatus status,
address signer,
uint256 tokens,
uint256 shares,
,
,
uint256 minSelfDelegation,
,
,
uint64 commissionRate
) = staking.validators(_valAddr);
return
dt.ValidatorInfo({
valAddr: _valAddr,
status: status,
signer: signer,
tokens: tokens,
shares: shares,
minSelfDelegation: minSelfDelegation,
commissionRate: commissionRate
});
}
function getDelegatorInfos(address _delAddr) public view returns (dt.DelegatorInfo[] memory) {
uint256 valNum = staking.getValidatorNum();
dt.DelegatorInfo[] memory infos = new dt.DelegatorInfo[](valNum);
uint32 num = 0;
for (uint32 i = 0; i < valNum; i++) {
address valAddr = staking.valAddrs(i);
infos[i] = staking.getDelegatorInfo(valAddr, _delAddr);
if (infos[i].shares != 0 || infos[i].undelegationTokens != 0) {
num++;
}
}
dt.DelegatorInfo[] memory res = new dt.DelegatorInfo[](num);
uint32 j = 0;
for (uint32 i = 0; i < valNum; i++) {
if (infos[i].shares != 0 || infos[i].undelegationTokens != 0) {
res[j] = infos[i];
j++;
}
}
return res;
}
function getDelegatorTokens(address _delAddr) public view returns (uint256, uint256) {
dt.DelegatorInfo[] memory infos = getDelegatorInfos(_delAddr);
uint256 tokens;
uint256 undelegationTokens;
for (uint32 i = 0; i < infos.length; i++) {
tokens += infos[i].tokens;
undelegationTokens += infos[i].undelegationTokens;
}
return (tokens, undelegationTokens);
}
function getMinValidatorTokens() public view returns (uint256) {
uint256 bondedValNum = staking.getBondedValidatorNum();
if (bondedValNum < staking.params(dt.ParamName.MaxBondedValidators)) {
return 0;
}
uint256 minTokens = dt.MAX_INT;
for (uint256 i = 0; i < bondedValNum; i++) {
uint256 tokens = staking.getValidatorTokens(staking.bondedValAddrs(i));
if (tokens < minTokens) {
minTokens = tokens;
if (minTokens == 0) {
return 0;
}
}
}
return minTokens;
}
function shouldBondValidator(address _valAddr) public view returns (bool) {
(dt.ValidatorStatus status, , uint256 tokens, , , , , uint64 bondBlock, , ) = staking.validators(_valAddr);
if (status == dt.ValidatorStatus.Null || status == dt.ValidatorStatus.Bonded) {
return false;
}
if (block.number < bondBlock) {
return false;
}
if (!staking.hasMinRequiredTokens(_valAddr, true)) {
return false;
}
if (tokens <= getMinValidatorTokens()) {
return false;
}
uint256 nextBondBlock = staking.nextBondBlock();
if (block.number < nextBondBlock) {
return false;
}
return true;
}
}
文件 95 的 102:VolumeControl.sol
pragma solidity 0.8.9;
import "./Governor.sol";
abstract contract VolumeControl is Governor {
uint256 public epochLength;
mapping(address => uint256) public epochVolumes;
mapping(address => uint256) public epochVolumeCaps;
mapping(address => uint256) public lastOpTimestamps;
event EpochLengthUpdated(uint256 length);
event EpochVolumeUpdated(address token, uint256 cap);
function setEpochLength(uint256 _length) external onlyGovernor {
epochLength = _length;
emit EpochLengthUpdated(_length);
}
function setEpochVolumeCaps(address[] calldata _tokens, uint256[] calldata _caps) external onlyGovernor {
require(_tokens.length == _caps.length, "length mismatch");
for (uint256 i = 0; i < _tokens.length; i++) {
epochVolumeCaps[_tokens[i]] = _caps[i];
emit EpochVolumeUpdated(_tokens[i], _caps[i]);
}
}
function _updateVolume(address _token, uint256 _amount) internal {
if (epochLength == 0) {
return;
}
uint256 cap = epochVolumeCaps[_token];
if (cap == 0) {
return;
}
uint256 volume = epochVolumes[_token];
uint256 timestamp = block.timestamp;
uint256 epochStartTime = (timestamp / epochLength) * epochLength;
if (lastOpTimestamps[_token] < epochStartTime) {
volume = _amount;
} else {
volume += _amount;
}
require(volume <= cap, "volume exceeds cap");
epochVolumes[_token] = volume;
lastOpTimestamps[_token] = timestamp;
}
}
文件 96 的 102:WETH.sol
pragma solidity >=0.8.9;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract WETH is ERC20 {
constructor() ERC20("WETH", "WETH") {}
function deposit() external payable {
_mint(msg.sender, msg.value);
}
function withdraw(uint256 _amount) external {
_burn(msg.sender, _amount);
(bool sent, ) = msg.sender.call{value: _amount, gas: 50000}("");
require(sent, "failed to send");
}
receive() external payable {}
}
文件 97 的 102:Whitelist.sol
pragma solidity 0.8.9;
import "./Ownable.sol";
abstract contract Whitelist is Ownable {
mapping(address => bool) public whitelist;
bool public whitelistEnabled;
event WhitelistedAdded(address account);
event WhitelistedRemoved(address account);
modifier onlyWhitelisted() {
if (whitelistEnabled) {
require(isWhitelisted(msg.sender), "Caller is not whitelisted");
}
_;
}
function setWhitelistEnabled(bool _whitelistEnabled) external onlyOwner {
whitelistEnabled = _whitelistEnabled;
}
function addWhitelisted(address account) external onlyOwner {
require(!isWhitelisted(account), "Already whitelisted");
whitelist[account] = true;
emit WhitelistedAdded(account);
}
function removeWhitelisted(address account) external onlyOwner {
require(isWhitelisted(account), "Not whitelisted");
whitelist[account] = false;
emit WhitelistedRemoved(account);
}
function isWhitelisted(address account) public view returns (bool) {
return whitelist[account];
}
}
文件 98 的 102:WithdrawInbox.sol
pragma solidity 0.8.9;
import "../safeguard/Ownable.sol";
contract WithdrawInbox is Ownable {
uint32 public minimalMaxSlippage;
uint256 public validityPeriod;
event WithdrawalRequest(
uint64 seqNum,
address sender,
address receiver,
uint64 toChain,
uint64[] fromChains,
address[] tokens,
uint32[] ratios,
uint32[] slippages,
uint256 deadline
);
constructor() {
validityPeriod = 7200;
}
function withdraw(
uint64 _wdSeq,
address _receiver,
uint64 _toChain,
uint64[] calldata _fromChains,
address[] calldata _tokens,
uint32[] calldata _ratios,
uint32[] calldata _slippages
) external {
require(_fromChains.length > 0, "empty withdrawal request");
require(
_tokens.length == _fromChains.length &&
_ratios.length == _fromChains.length &&
_slippages.length == _fromChains.length,
"length mismatch"
);
for (uint256 i = 0; i < _ratios.length; i++) {
require(_ratios[i] > 0 && _ratios[i] <= 1e8, "invalid ratio");
require(_slippages[i] >= minimalMaxSlippage, "slippage too small");
}
uint256 _deadline = block.timestamp + validityPeriod;
emit WithdrawalRequest(
_wdSeq,
msg.sender,
_receiver,
_toChain,
_fromChains,
_tokens,
_ratios,
_slippages,
_deadline
);
}
function setMinimalMaxSlippage(uint32 _minimalMaxSlippage) external onlyOwner {
minimalMaxSlippage = _minimalMaxSlippage;
}
function setValidityPeriod(uint256 _validityPeriod) external onlyOwner {
validityPeriod = _validityPeriod;
}
}
文件 99 的 102:WrappedBridgeToken.sol
pragma solidity >=0.8.9;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract WrappedBridgeToken is ERC20, Ownable {
using SafeERC20 for IERC20;
address public bridge;
address public immutable canonical;
mapping(address => uint256) public liquidity;
event BridgeUpdated(address bridge);
event LiquidityAdded(address provider, uint256 amount);
event LiquidityRemoved(address provider, uint256 amount);
modifier onlyBridge() {
require(msg.sender == bridge, "caller is not bridge");
_;
}
constructor(
string memory name_,
string memory symbol_,
address bridge_,
address canonical_
) ERC20(name_, symbol_) {
bridge = bridge_;
canonical = canonical_;
}
function mint(address _to, uint256 _amount) external onlyBridge returns (bool) {
_mint(address(this), _amount);
IERC20(canonical).safeTransfer(_to, _amount);
return true;
}
function burn(address _from, uint256 _amount) external onlyBridge returns (bool) {
_burn(address(this), _amount);
IERC20(canonical).safeTransferFrom(_from, address(this), _amount);
return true;
}
function addLiquidity(uint256 _amount) external {
liquidity[msg.sender] += _amount;
IERC20(canonical).safeTransferFrom(msg.sender, address(this), _amount);
emit LiquidityAdded(msg.sender, _amount);
}
function removeLiquidity(uint256 _amount) external {
liquidity[msg.sender] -= _amount;
IERC20(canonical).safeTransfer(msg.sender, _amount);
emit LiquidityRemoved(msg.sender, _amount);
}
function updateBridge(address _bridge) external onlyOwner {
bridge = _bridge;
emit BridgeUpdated(bridge);
}
function decimals() public view virtual override returns (uint8) {
return ERC20(canonical).decimals();
}
function getOwner() external view returns (address) {
return owner();
}
}
文件 100 的 102:draft-EIP712.sol
pragma solidity ^0.8.0;
import "./ECDSA.sol";
abstract contract EIP712 {
bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;
uint256 private immutable _CACHED_CHAIN_ID;
address private immutable _CACHED_THIS;
bytes32 private immutable _HASHED_NAME;
bytes32 private immutable _HASHED_VERSION;
bytes32 private immutable _TYPE_HASH;
constructor(string memory name, string memory version) {
bytes32 hashedName = keccak256(bytes(name));
bytes32 hashedVersion = keccak256(bytes(version));
bytes32 typeHash = keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
);
_HASHED_NAME = hashedName;
_HASHED_VERSION = hashedVersion;
_CACHED_CHAIN_ID = block.chainid;
_CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);
_CACHED_THIS = address(this);
_TYPE_HASH = typeHash;
}
function _domainSeparatorV4() internal view returns (bytes32) {
if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) {
return _CACHED_DOMAIN_SEPARATOR;
} else {
return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);
}
}
function _buildDomainSeparator(
bytes32 typeHash,
bytes32 nameHash,
bytes32 versionHash
) private view returns (bytes32) {
return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));
}
function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
}
}
文件 101 的 102:draft-ERC20Permit.sol
pragma solidity ^0.8.0;
import "./draft-IERC20Permit.sol";
import "../ERC20.sol";
import "../../../utils/cryptography/draft-EIP712.sol";
import "../../../utils/cryptography/ECDSA.sol";
import "../../../utils/Counters.sol";
abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 {
using Counters for Counters.Counter;
mapping(address => Counters.Counter) private _nonces;
bytes32 private immutable _PERMIT_TYPEHASH =
keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
constructor(string memory name) EIP712(name, "1") {}
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual override {
require(block.timestamp <= deadline, "ERC20Permit: expired deadline");
bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));
bytes32 hash = _hashTypedDataV4(structHash);
address signer = ECDSA.recover(hash, v, r, s);
require(signer == owner, "ERC20Permit: invalid signature");
_approve(owner, spender, value);
}
function nonces(address owner) public view virtual override returns (uint256) {
return _nonces[owner].current();
}
function DOMAIN_SEPARATOR() external view override returns (bytes32) {
return _domainSeparatorV4();
}
function _useNonce(address owner) internal virtual returns (uint256 current) {
Counters.Counter storage nonce = _nonces[owner];
current = nonce.current();
nonce.increment();
}
}
文件 102 的 102:draft-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);
}
{
"compilationTarget": {
"contracts/pegged-bridge/tokens/WrappedBridgeToken.sol": "WrappedBridgeToken"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 800
},
"remappings": []
}
[{"inputs":[{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"address","name":"bridge_","type":"address"},{"internalType":"address","name":"canonical_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"bridge","type":"address"}],"name":"BridgeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"provider","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"LiquidityAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"provider","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"LiquidityRemoved","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":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"addLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bridge","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"burn","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"canonical","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"liquidity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"removeLiquidity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_bridge","type":"address"}],"name":"updateBridge","outputs":[],"stateMutability":"nonpayable","type":"function"}]