文件 1 的 17:AccessControl.sol
pragma solidity ^0.8.0;
import "./IAccessControl.sol";
import "../utils/Context.sol";
import "../utils/Strings.sol";
import "../utils/introspection/ERC165.sol";
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address => bool) members;
bytes32 adminRole;
}
mapping(bytes32 => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
modifier onlyRole(bytes32 role) {
_checkRole(role, _msgSender());
_;
}
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
function hasRole(bytes32 role, address account) public view override returns (bool) {
return _roles[role].members[account];
}
function _checkRole(bytes32 role, address account) internal view {
if (!hasRole(role, account)) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
Strings.toHexString(uint160(account), 20),
" is missing role ",
Strings.toHexString(uint256(role), 32)
)
)
);
}
}
function getRoleAdmin(bytes32 role) public view override returns (bytes32) {
return _roles[role].adminRole;
}
function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
function renounceRole(bytes32 role, address account) public virtual override {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
function _setupRole(bytes32 role, address account) internal virtual {
_grantRole(role, account);
}
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
function _grantRole(bytes32 role, address account) internal virtual {
if (!hasRole(role, account)) {
_roles[role].members[account] = true;
emit RoleGranted(role, account, _msgSender());
}
}
function _revokeRole(bytes32 role, address account) internal virtual {
if (hasRole(role, account)) {
_roles[role].members[account] = false;
emit RoleRevoked(role, account, _msgSender());
}
}
}
文件 2 的 17:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
文件 3 的 17: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;
uint8 v;
assembly {
s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)
v := add(shr(255, vs), 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));
}
}
文件 4 的 17: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;
}
}
文件 5 的 17:IAccessControl.sol
pragma solidity ^0.8.0;
interface IAccessControl {
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
function hasRole(bytes32 role, address account) external view returns (bool);
function getRoleAdmin(bytes32 role) external view returns (bytes32);
function grantRole(bytes32 role, address account) external;
function revokeRole(bytes32 role, address account) external;
function renounceRole(bytes32 role, address account) external;
}
文件 6 的 17:IBridge.sol
pragma solidity 0.8.9;
interface IBridge {
event MessageDelivered(
uint256 indexed messageIndex,
bytes32 indexed beforeInboxAcc,
address inbox,
uint8 kind,
address sender,
bytes32 messageDataHash
);
event BridgeCallTriggered(
address indexed outbox,
address indexed destAddr,
uint256 amount,
bytes data
);
event InboxToggle(address indexed inbox, bool enabled);
event OutboxToggle(address indexed outbox, bool enabled);
function deliverMessageToInbox(
uint8 kind,
address sender,
bytes32 messageDataHash
) external payable returns (uint256);
function executeCall(
address destAddr,
uint256 amount,
bytes calldata data
) external returns (bool success, bytes memory returnData);
function setInbox(address inbox, bool enabled) external;
function setOutbox(address inbox, bool enabled) external;
function activeOutbox() external view returns (address);
function allowedInboxes(address inbox) external view returns (bool);
function allowedOutboxes(address outbox) external view returns (bool);
function inboxAccs(uint256 index) external view returns (bytes32);
function messageCount() external view returns (uint256);
}
文件 7 的 17:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 8 的 17:IInbox.sol
pragma solidity 0.8.9;
import "./IMessageProvider.sol";
interface IInbox is IMessageProvider {
function sendL2Message(bytes calldata messageData)
external
returns (uint256);
function sendUnsignedTransaction(
uint256 maxGas,
uint256 gasPriceBid,
uint256 nonce,
address destAddr,
uint256 amount,
bytes calldata data
) external returns (uint256);
function sendContractTransaction(
uint256 maxGas,
uint256 gasPriceBid,
address destAddr,
uint256 amount,
bytes calldata data
) external returns (uint256);
function sendL1FundedUnsignedTransaction(
uint256 maxGas,
uint256 gasPriceBid,
uint256 nonce,
address destAddr,
bytes calldata data
) external payable returns (uint256);
function sendL1FundedContractTransaction(
uint256 maxGas,
uint256 gasPriceBid,
address destAddr,
bytes calldata data
) external payable returns (uint256);
function createRetryableTicket(
address destAddr,
uint256 arbTxCallValue,
uint256 maxSubmissionCost,
address submissionRefundAddress,
address valueRefundAddress,
uint256 maxGas,
uint256 gasPriceBid,
bytes calldata data
) external payable returns (uint256);
function createRetryableTicketNoRefundAliasRewrite(
address destAddr,
uint256 arbTxCallValue,
uint256 maxSubmissionCost,
address submissionRefundAddress,
address valueRefundAddress,
uint256 maxGas,
uint256 gasPriceBid,
bytes calldata data
) external payable returns (uint256);
function depositEth(uint256 maxSubmissionCost)
external
payable
returns (uint256);
function bridge() external view returns (address);
function pauseCreateRetryables() external;
function unpauseCreateRetryables() external;
function startRewriteAddress() external;
function stopRewriteAddress() external;
}
文件 9 的 17:IL1LPTGateway.sol
pragma solidity 0.8.9;
interface IL1LPTGateway {
event DepositInitiated(
address _l1Token,
address indexed _from,
address indexed _to,
uint256 indexed _sequenceNumber,
uint256 _amount
);
event WithdrawalFinalized(
address _l1Token,
address indexed _from,
address indexed _to,
uint256 indexed _exitNum,
uint256 _amount
);
function outboundTransfer(
address _l1Token,
address _to,
uint256 _amount,
uint256 _maxGas,
uint256 _gasPriceBid,
bytes calldata _data
) external payable returns (bytes memory);
function finalizeInboundTransfer(
address _token,
address _from,
address _to,
uint256 _amount,
bytes calldata _data
) external;
function calculateL2TokenAddress(address l1Token)
external
view
returns (address);
function counterpartGateway() external view returns (address);
}
文件 10 的 17:IMessageProvider.sol
pragma solidity 0.8.9;
interface IMessageProvider {
event InboxMessageDelivered(uint256 indexed messageNum, bytes data);
event InboxMessageDeliveredFromOrigin(uint256 indexed messageNum);
}
文件 11 的 17:IMigrator.sol
pragma solidity 0.8.9;
interface IMigrator {
struct MigrateDelegatorParams {
address l1Addr;
address l2Addr;
uint256 stake;
uint256 delegatedStake;
uint256 fees;
address delegate;
}
struct MigrateUnbondingLocksParams {
address l1Addr;
address l2Addr;
uint256 total;
uint256[] unbondingLockIds;
address delegate;
}
struct MigrateSenderParams {
address l1Addr;
address l2Addr;
uint256 deposit;
uint256 reserve;
}
}
文件 12 的 17:IOutbox.sol
pragma solidity 0.8.9;
interface IOutbox {
event OutboxEntryCreated(
uint256 indexed batchNum,
uint256 outboxEntryIndex,
bytes32 outputRoot,
uint256 numInBatch
);
event OutBoxTransactionExecuted(
address indexed destAddr,
address indexed l2Sender,
uint256 indexed outboxEntryIndex,
uint256 transactionIndex
);
function l2ToL1Sender() external view returns (address);
function l2ToL1Block() external view returns (uint256);
function l2ToL1EthBlock() external view returns (uint256);
function l2ToL1Timestamp() external view returns (uint256);
function l2ToL1BatchNum() external view returns (uint256);
function l2ToL1OutputId() external view returns (bytes32);
function processOutgoingMessages(
bytes calldata sendsData,
uint256[] calldata sendLengths
) external;
function outboxEntryExists(uint256 batchNum) external view returns (bool);
}
文件 13 的 17:L1ArbitrumMessenger.sol
pragma solidity 0.8.9;
import {IBridge} from "../../arbitrum/IBridge.sol";
import {IInbox} from "../../arbitrum/IInbox.sol";
import {IOutbox} from "../../arbitrum/IOutbox.sol";
abstract contract L1ArbitrumMessenger {
IInbox public immutable inbox;
event TxToL2(
address indexed from,
address indexed to,
uint256 indexed seqNum,
bytes data
);
constructor(address _inbox) {
inbox = IInbox(_inbox);
}
modifier onlyL2Counterpart(address l2Counterpart) {
address bridge = inbox.bridge();
require(msg.sender == bridge, "NOT_FROM_BRIDGE");
address l2ToL1Sender = IOutbox(IBridge(bridge).activeOutbox())
.l2ToL1Sender();
require(l2ToL1Sender == l2Counterpart, "ONLY_COUNTERPART_GATEWAY");
_;
}
function sendTxToL2(
address target,
address from,
uint256 maxSubmissionCost,
uint256 maxGas,
uint256 gasPriceBid,
bytes memory data
) internal returns (uint256) {
return
sendTxToL2(
target,
from,
msg.value,
0,
maxSubmissionCost,
maxGas,
gasPriceBid,
data
);
}
function sendTxToL2(
address target,
address from,
uint256 _l1CallValue,
uint256 _l2CallValue,
uint256 maxSubmissionCost,
uint256 maxGas,
uint256 gasPriceBid,
bytes memory data
) internal returns (uint256) {
uint256 seqNum = inbox.createRetryableTicket{value: _l1CallValue}(
target,
_l2CallValue,
maxSubmissionCost,
from,
from,
maxGas,
gasPriceBid,
data
);
emit TxToL2(from, target, seqNum, data);
return seqNum;
}
}
文件 14 的 17:L1Migrator.sol
pragma solidity 0.8.9;
import {L1ArbitrumMessenger} from "./L1ArbitrumMessenger.sol";
import {IL1LPTGateway} from "./IL1LPTGateway.sol";
import {IMigrator} from "../../interfaces/IMigrator.sol";
import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import {EIP712} from "@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol";
import {Pausable} from "@openzeppelin/contracts/security/Pausable.sol";
import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
interface IBondingManager {
function isRegisteredTranscoder(address _addr) external view returns (bool);
function pendingStake(address _addr, uint256 _endRound)
external
view
returns (uint256);
function pendingFees(address _addr, uint256 _endRound)
external
view
returns (uint256);
function getDelegator(address _addr)
external
view
returns (
uint256 bondedAmount,
uint256 fees,
address delegateAddress,
uint256 delegatedAmount,
uint256 startRound,
uint256 lastClaimRound,
uint256 nextUnbondingLockId
);
function getDelegatorUnbondingLock(address _addr, uint256 _unbondingLockId)
external
view
returns (uint256 amount, uint256 withdrawRound);
}
interface ITicketBroker {
struct Sender {
uint256 deposit;
uint256 withdrawRound;
}
struct ReserveInfo {
uint256 fundsRemaining;
uint256 claimedInCurrentRound;
}
function getSenderInfo(address _addr)
external
view
returns (Sender memory sender, ReserveInfo memory reserve);
}
interface IBridgeMinter {
function withdrawETHToL1Migrator() external returns (uint256);
function withdrawLPTToL1Migrator() external returns (uint256);
}
interface ApproveLike {
function approve(address _addr, uint256 _amount) external;
}
interface IL2Migrator is IMigrator {
function finalizeMigrateDelegator(MigrateDelegatorParams memory _params)
external;
function finalizeMigrateUnbondingLocks(
MigrateUnbondingLocksParams memory _params
) external;
function finalizeMigrateSender(MigrateSenderParams memory _params) external;
}
contract L1Migrator is
L1ArbitrumMessenger,
IMigrator,
EIP712,
AccessControl,
Pausable
{
address public immutable bondingManagerAddr;
address public immutable ticketBrokerAddr;
address public immutable tokenAddr;
address public immutable l1LPTGatewayAddr;
address public bridgeMinterAddr;
address public l2MigratorAddr;
event MigrateDelegatorInitiated(
uint256 indexed seqNo,
MigrateDelegatorParams params
);
event MigrateUnbondingLocksInitiated(
uint256 indexed seqNo,
MigrateUnbondingLocksParams params
);
event MigrateSenderInitiated(
uint256 indexed seqNo,
MigrateSenderParams params
);
event L2MigratorUpdate(address l2Migrator);
event BridgeMinterUpdate(address bridgeMinter);
bytes32 private immutable MIGRATE_DELEGATOR_TYPE_HASH =
keccak256("MigrateDelegator(address l1Addr,address l2Addr)");
bytes32 private immutable MIGRATE_UNBONDING_LOCKS_TYPE_HASH =
keccak256(
"MigrateUnbondingLocks(address l1Addr,address l2Addr,uint256[] unbondingLockIds)"
);
bytes32 private immutable MIGRATE_SENDER_TYPE_HASH =
keccak256("MigrateSender(address l1Addr,address l2Addr)");
constructor(
address _inbox,
address _bondingManagerAddr,
address _ticketBrokerAddr,
address _tokenAddr,
address _l1LPTGatewayAddr,
address _l2MigratorAddr
) L1ArbitrumMessenger(_inbox) EIP712("Livepeer L1Migrator", "1") {
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
bondingManagerAddr = _bondingManagerAddr;
ticketBrokerAddr = _ticketBrokerAddr;
tokenAddr = _tokenAddr;
l1LPTGatewayAddr = _l1LPTGatewayAddr;
l2MigratorAddr = _l2MigratorAddr;
_pause();
}
function setL2Migrator(address _l2MigratorAddr)
external
onlyRole(DEFAULT_ADMIN_ROLE)
{
l2MigratorAddr = _l2MigratorAddr;
emit L2MigratorUpdate(_l2MigratorAddr);
}
function setBridgeMinter(address _bridgeMinterAddr)
external
onlyRole(DEFAULT_ADMIN_ROLE)
{
bridgeMinterAddr = _bridgeMinterAddr;
emit BridgeMinterUpdate(_bridgeMinterAddr);
}
receive() external payable {}
function migrateDelegator(
address _l1Addr,
address _l2Addr,
bytes calldata _sig,
uint256 _maxGas,
uint256 _gasPriceBid,
uint256 _maxSubmissionCost
) external payable whenNotPaused {
requireValidMigration(
_l1Addr,
_l2Addr,
keccak256(
abi.encode(MIGRATE_DELEGATOR_TYPE_HASH, _l1Addr, _l2Addr)
),
_sig
);
(
bytes memory data,
MigrateDelegatorParams memory params
) = getMigrateDelegatorParams(_l1Addr, _l2Addr);
uint256 seqNo = sendTxToL2(
l2MigratorAddr,
_l2Addr,
_maxSubmissionCost,
_maxGas,
_gasPriceBid,
data
);
emit MigrateDelegatorInitiated(seqNo, params);
}
function migrateUnbondingLocks(
address _l1Addr,
address _l2Addr,
uint256[] calldata _unbondingLockIds,
bytes calldata _sig,
uint256 _maxGas,
uint256 _gasPriceBid,
uint256 _maxSubmissionCost
) external payable whenNotPaused {
requireValidMigration(
_l1Addr,
_l2Addr,
keccak256(
abi.encode(
MIGRATE_UNBONDING_LOCKS_TYPE_HASH,
_l1Addr,
_l2Addr,
keccak256(abi.encodePacked(_unbondingLockIds))
)
),
_sig
);
(
bytes memory data,
MigrateUnbondingLocksParams memory params
) = getMigrateUnbondingLocksParams(_l1Addr, _l2Addr, _unbondingLockIds);
uint256 seqNo = sendTxToL2(
l2MigratorAddr,
_l2Addr,
_maxSubmissionCost,
_maxGas,
_gasPriceBid,
data
);
emit MigrateUnbondingLocksInitiated(seqNo, params);
}
function migrateSender(
address _l1Addr,
address _l2Addr,
bytes calldata _sig,
uint256 _maxGas,
uint256 _gasPriceBid,
uint256 _maxSubmissionCost
) external payable whenNotPaused {
requireValidMigration(
_l1Addr,
_l2Addr,
keccak256(abi.encode(MIGRATE_SENDER_TYPE_HASH, _l1Addr, _l2Addr)),
_sig
);
(
bytes memory data,
MigrateSenderParams memory params
) = getMigrateSenderParams(_l1Addr, _l2Addr);
uint256 seqNo = sendTxToL2(
l2MigratorAddr,
_l2Addr,
_maxSubmissionCost,
_maxGas,
_gasPriceBid,
data
);
emit MigrateSenderInitiated(seqNo, params);
}
function migrateETH(
uint256 _maxGas,
uint256 _gasPriceBid,
uint256 _maxSubmissionCost
) external payable whenNotPaused {
uint256 amount = IBridgeMinter(bridgeMinterAddr)
.withdrawETHToL1Migrator();
sendTxToL2(
l2MigratorAddr,
address(this),
msg.value + amount,
amount,
_maxSubmissionCost,
_maxGas,
_gasPriceBid,
""
);
}
function migrateLPT(
uint256 _maxGas,
uint256 _gasPriceBid,
uint256 _maxSubmissionCost
) external payable whenNotPaused onlyRole(DEFAULT_ADMIN_ROLE) {
uint256 amount = IBridgeMinter(bridgeMinterAddr)
.withdrawLPTToL1Migrator();
ApproveLike(tokenAddr).approve(l1LPTGatewayAddr, amount);
IL1LPTGateway(l1LPTGatewayAddr).outboundTransfer{value: msg.value}(
tokenAddr,
l2MigratorAddr,
amount,
_maxGas,
_gasPriceBid,
abi.encode(_maxSubmissionCost, "")
);
}
function pause() external onlyRole(DEFAULT_ADMIN_ROLE) {
_pause();
}
function unpause() external onlyRole(DEFAULT_ADMIN_ROLE) {
_unpause();
}
function getMigrateDelegatorParams(address _l1Addr, address _l2Addr)
public
view
returns (bytes memory data, MigrateDelegatorParams memory params)
{
IBondingManager bondingManager = IBondingManager(bondingManagerAddr);
uint256 stake = bondingManager.pendingStake(_l1Addr, type(uint256).max);
uint256 fees = bondingManager.pendingFees(_l1Addr, type(uint256).max);
(
,
,
address delegateAddress,
uint256 delegatedAmount,
,
,
) = bondingManager.getDelegator(_l1Addr);
params = MigrateDelegatorParams({
l1Addr: _l1Addr,
l2Addr: _l2Addr,
stake: stake,
delegatedStake: delegatedAmount,
fees: fees,
delegate: delegateAddress
});
data = abi.encodeWithSelector(
IL2Migrator.finalizeMigrateDelegator.selector,
params
);
}
function getMigrateSenderParams(address _l1Addr, address _l2Addr)
public
view
returns (bytes memory data, MigrateSenderParams memory params)
{
ITicketBroker ticketBroker = ITicketBroker(ticketBrokerAddr);
(
ITicketBroker.Sender memory sender,
ITicketBroker.ReserveInfo memory reserveInfo
) = ticketBroker.getSenderInfo(_l1Addr);
params = MigrateSenderParams({
l1Addr: _l1Addr,
l2Addr: _l2Addr,
deposit: sender.deposit,
reserve: reserveInfo.fundsRemaining
});
data = abi.encodeWithSelector(
IL2Migrator.finalizeMigrateSender.selector,
params
);
}
function getMigrateUnbondingLocksParams(
address _l1Addr,
address _l2Addr,
uint256[] memory _unbondingLockIds
)
public
view
returns (bytes memory data, MigrateUnbondingLocksParams memory params)
{
IBondingManager bondingManager = IBondingManager(bondingManagerAddr);
uint256 total;
uint256 unbondingLockIdsLen = _unbondingLockIds.length;
for (uint256 i; i < unbondingLockIdsLen; i++) {
(uint256 amount, ) = bondingManager.getDelegatorUnbondingLock(
_l1Addr,
_unbondingLockIds[i]
);
total += amount;
}
(, , address delegateAddress, , , , ) = bondingManager.getDelegator(
_l1Addr
);
params = MigrateUnbondingLocksParams({
l1Addr: _l1Addr,
l2Addr: _l2Addr,
total: total,
unbondingLockIds: _unbondingLockIds,
delegate: delegateAddress
});
data = abi.encodeWithSelector(
IL2Migrator.finalizeMigrateUnbondingLocks.selector,
params
);
}
function requireValidMigration(
address _l1Addr,
address _l2Addr,
bytes32 _structHash,
bytes memory _sig
) private view {
require(_l2Addr != address(0), "INVALID_L2_ADDR");
require(
msg.sender == _l1Addr ||
recoverSigner(_structHash, _sig) == _l1Addr,
"FAIL_AUTH"
);
}
function recoverSigner(bytes32 _structHash, bytes memory _sig)
private
view
returns (address)
{
bytes32 hash = _hashTypedDataV4(_structHash);
return ECDSA.recover(hash, _sig);
}
}
文件 15 的 17: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());
}
}
文件 16 的 17: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);
}
}
文件 17 的 17: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);
}
}
{
"compilationTarget": {
"contracts/L1/gateway/L1Migrator.sol": "L1Migrator"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_inbox","type":"address"},{"internalType":"address","name":"_bondingManagerAddr","type":"address"},{"internalType":"address","name":"_ticketBrokerAddr","type":"address"},{"internalType":"address","name":"_tokenAddr","type":"address"},{"internalType":"address","name":"_l1LPTGatewayAddr","type":"address"},{"internalType":"address","name":"_l2MigratorAddr","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"bridgeMinter","type":"address"}],"name":"BridgeMinterUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"l2Migrator","type":"address"}],"name":"L2MigratorUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"seqNo","type":"uint256"},{"components":[{"internalType":"address","name":"l1Addr","type":"address"},{"internalType":"address","name":"l2Addr","type":"address"},{"internalType":"uint256","name":"stake","type":"uint256"},{"internalType":"uint256","name":"delegatedStake","type":"uint256"},{"internalType":"uint256","name":"fees","type":"uint256"},{"internalType":"address","name":"delegate","type":"address"}],"indexed":false,"internalType":"struct IMigrator.MigrateDelegatorParams","name":"params","type":"tuple"}],"name":"MigrateDelegatorInitiated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"seqNo","type":"uint256"},{"components":[{"internalType":"address","name":"l1Addr","type":"address"},{"internalType":"address","name":"l2Addr","type":"address"},{"internalType":"uint256","name":"deposit","type":"uint256"},{"internalType":"uint256","name":"reserve","type":"uint256"}],"indexed":false,"internalType":"struct IMigrator.MigrateSenderParams","name":"params","type":"tuple"}],"name":"MigrateSenderInitiated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"seqNo","type":"uint256"},{"components":[{"internalType":"address","name":"l1Addr","type":"address"},{"internalType":"address","name":"l2Addr","type":"address"},{"internalType":"uint256","name":"total","type":"uint256"},{"internalType":"uint256[]","name":"unbondingLockIds","type":"uint256[]"},{"internalType":"address","name":"delegate","type":"address"}],"indexed":false,"internalType":"struct IMigrator.MigrateUnbondingLocksParams","name":"params","type":"tuple"}],"name":"MigrateUnbondingLocksInitiated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"seqNum","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"TxToL2","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bondingManagerAddr","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bridgeMinterAddr","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_l1Addr","type":"address"},{"internalType":"address","name":"_l2Addr","type":"address"}],"name":"getMigrateDelegatorParams","outputs":[{"internalType":"bytes","name":"data","type":"bytes"},{"components":[{"internalType":"address","name":"l1Addr","type":"address"},{"internalType":"address","name":"l2Addr","type":"address"},{"internalType":"uint256","name":"stake","type":"uint256"},{"internalType":"uint256","name":"delegatedStake","type":"uint256"},{"internalType":"uint256","name":"fees","type":"uint256"},{"internalType":"address","name":"delegate","type":"address"}],"internalType":"struct IMigrator.MigrateDelegatorParams","name":"params","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_l1Addr","type":"address"},{"internalType":"address","name":"_l2Addr","type":"address"}],"name":"getMigrateSenderParams","outputs":[{"internalType":"bytes","name":"data","type":"bytes"},{"components":[{"internalType":"address","name":"l1Addr","type":"address"},{"internalType":"address","name":"l2Addr","type":"address"},{"internalType":"uint256","name":"deposit","type":"uint256"},{"internalType":"uint256","name":"reserve","type":"uint256"}],"internalType":"struct IMigrator.MigrateSenderParams","name":"params","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_l1Addr","type":"address"},{"internalType":"address","name":"_l2Addr","type":"address"},{"internalType":"uint256[]","name":"_unbondingLockIds","type":"uint256[]"}],"name":"getMigrateUnbondingLocksParams","outputs":[{"internalType":"bytes","name":"data","type":"bytes"},{"components":[{"internalType":"address","name":"l1Addr","type":"address"},{"internalType":"address","name":"l2Addr","type":"address"},{"internalType":"uint256","name":"total","type":"uint256"},{"internalType":"uint256[]","name":"unbondingLockIds","type":"uint256[]"},{"internalType":"address","name":"delegate","type":"address"}],"internalType":"struct IMigrator.MigrateUnbondingLocksParams","name":"params","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"inbox","outputs":[{"internalType":"contract IInbox","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"l1LPTGatewayAddr","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"l2MigratorAddr","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_l1Addr","type":"address"},{"internalType":"address","name":"_l2Addr","type":"address"},{"internalType":"bytes","name":"_sig","type":"bytes"},{"internalType":"uint256","name":"_maxGas","type":"uint256"},{"internalType":"uint256","name":"_gasPriceBid","type":"uint256"},{"internalType":"uint256","name":"_maxSubmissionCost","type":"uint256"}],"name":"migrateDelegator","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxGas","type":"uint256"},{"internalType":"uint256","name":"_gasPriceBid","type":"uint256"},{"internalType":"uint256","name":"_maxSubmissionCost","type":"uint256"}],"name":"migrateETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_maxGas","type":"uint256"},{"internalType":"uint256","name":"_gasPriceBid","type":"uint256"},{"internalType":"uint256","name":"_maxSubmissionCost","type":"uint256"}],"name":"migrateLPT","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_l1Addr","type":"address"},{"internalType":"address","name":"_l2Addr","type":"address"},{"internalType":"bytes","name":"_sig","type":"bytes"},{"internalType":"uint256","name":"_maxGas","type":"uint256"},{"internalType":"uint256","name":"_gasPriceBid","type":"uint256"},{"internalType":"uint256","name":"_maxSubmissionCost","type":"uint256"}],"name":"migrateSender","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_l1Addr","type":"address"},{"internalType":"address","name":"_l2Addr","type":"address"},{"internalType":"uint256[]","name":"_unbondingLockIds","type":"uint256[]"},{"internalType":"bytes","name":"_sig","type":"bytes"},{"internalType":"uint256","name":"_maxGas","type":"uint256"},{"internalType":"uint256","name":"_gasPriceBid","type":"uint256"},{"internalType":"uint256","name":"_maxSubmissionCost","type":"uint256"}],"name":"migrateUnbondingLocks","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_bridgeMinterAddr","type":"address"}],"name":"setBridgeMinter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_l2MigratorAddr","type":"address"}],"name":"setL2Migrator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ticketBrokerAddr","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenAddr","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]