Contract Source Code:
// SPDX-License-Identifier: Apache-2.0
/*
* Copyright 2019-2021, Offchain Labs, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity ^0.6.11;
import "./interfaces/IOutbox.sol";
import "./interfaces/IBridge.sol";
import "./Messages.sol";
import "../libraries/MerkleLib.sol";
import "../libraries/BytesLib.sol";
import "../libraries/Cloneable.sol";
import "@openzeppelin/contracts/proxy/BeaconProxy.sol";
import "@openzeppelin/contracts/proxy/UpgradeableBeacon.sol";
contract Outbox is IOutbox, Cloneable {
using BytesLib for bytes;
struct OutboxEntry {
// merkle root of outputs
bytes32 root;
// mapping from output id => is spent
mapping(bytes32 => bool) spentOutput;
}
bytes1 internal constant MSG_ROOT = 0;
uint8 internal constant SendType_sendTxToL1 = 3;
address public rollup;
IBridge public bridge;
mapping(uint256 => OutboxEntry) public outboxEntries;
struct L2ToL1Context {
uint128 l2Block;
uint128 l1Block;
uint128 timestamp;
uint128 batchNum;
bytes32 outputId;
address sender;
}
// Note, these variables are set and then wiped during a single transaction.
// Therefore their values don't need to be maintained, and their slots will
// be empty outside of transactions
L2ToL1Context internal context;
uint128 public constant OUTBOX_VERSION = 1;
function initialize(address _rollup, IBridge _bridge) external {
require(rollup == address(0), "ALREADY_INIT");
rollup = _rollup;
bridge = _bridge;
}
/// @notice When l2ToL1Sender returns a nonzero address, the message was originated by an L2 account
/// When the return value is zero, that means this is a system message
/// @dev the l2ToL1Sender behaves as the tx.origin, the msg.sender should be validated to protect against reentrancies
function l2ToL1Sender() external view override returns (address) {
return context.sender;
}
function l2ToL1Block() external view override returns (uint256) {
return uint256(context.l2Block);
}
function l2ToL1EthBlock() external view override returns (uint256) {
return uint256(context.l1Block);
}
function l2ToL1Timestamp() external view override returns (uint256) {
return uint256(context.timestamp);
}
function l2ToL1BatchNum() external view override returns (uint256) {
return uint256(context.batchNum);
}
function l2ToL1OutputId() external view override returns (bytes32) {
return context.outputId;
}
function processOutgoingMessages(bytes calldata sendsData, uint256[] calldata sendLengths)
external
override
{
require(msg.sender == rollup, "ONLY_ROLLUP");
// If we've reached here, we've already confirmed that sum(sendLengths) == sendsData.length
uint256 messageCount = sendLengths.length;
uint256 offset = 0;
for (uint256 i = 0; i < messageCount; i++) {
handleOutgoingMessage(bytes(sendsData[offset:offset + sendLengths[i]]));
offset += sendLengths[i];
}
}
function handleOutgoingMessage(bytes memory data) private {
// Otherwise we have an unsupported message type and we skip the message
if (data[0] == MSG_ROOT) {
require(data.length == 97, "BAD_LENGTH");
uint256 batchNum = data.toUint(1);
// Ensure no outbox entry already exists w/ batch number
require(!outboxEntryExists(batchNum), "ENTRY_ALREADY_EXISTS");
// This is the total number of msgs included in the root, it can be used to
// detect when all msgs were executed against a root.
// It currently isn't stored, but instead emitted in an event for utility
uint256 numInBatch = data.toUint(33);
bytes32 outputRoot = data.toBytes32(65);
OutboxEntry memory newOutboxEntry = OutboxEntry(outputRoot);
outboxEntries[batchNum] = newOutboxEntry;
// keeping redundant batchnum in event (batchnum and old outboxindex field) for outbox version interface compatibility
emit OutboxEntryCreated(batchNum, batchNum, outputRoot, numInBatch);
}
}
/**
* @notice Executes a messages in an Outbox entry.
* @dev Reverts if dispute period hasn't expired, since the outbox entry
* is only created once the rollup confirms the respective assertion.
* @param batchNum Index of OutboxEntry in outboxEntries array
* @param proof Merkle proof of message inclusion in outbox entry
* @param index Merkle path to message
* @param l2Sender sender if original message (i.e., caller of ArbSys.sendTxToL1)
* @param destAddr destination address for L1 contract call
* @param l2Block l2 block number at which sendTxToL1 call was made
* @param l1Block l1 block number at which sendTxToL1 call was made
* @param l2Timestamp l2 Timestamp at which sendTxToL1 call was made
* @param amount value in L1 message in wei
* @param calldataForL1 abi-encoded L1 message data
*/
function executeTransaction(
uint256 batchNum,
bytes32[] calldata proof,
uint256 index,
address l2Sender,
address destAddr,
uint256 l2Block,
uint256 l1Block,
uint256 l2Timestamp,
uint256 amount,
bytes calldata calldataForL1
) external virtual {
bytes32 outputId;
{
bytes32 userTx =
calculateItemHash(
l2Sender,
destAddr,
l2Block,
l1Block,
l2Timestamp,
amount,
calldataForL1
);
outputId = recordOutputAsSpent(batchNum, proof, index, userTx);
emit OutBoxTransactionExecuted(destAddr, l2Sender, batchNum, index);
}
// we temporarily store the previous values so the outbox can naturally
// unwind itself when there are nested calls to `executeTransaction`
L2ToL1Context memory prevContext = context;
context = L2ToL1Context({
sender: l2Sender,
l2Block: uint128(l2Block),
l1Block: uint128(l1Block),
timestamp: uint128(l2Timestamp),
batchNum: uint128(batchNum),
outputId: outputId
});
// set and reset vars around execution so they remain valid during call
executeBridgeCall(destAddr, amount, calldataForL1);
context = prevContext;
}
function recordOutputAsSpent(
uint256 batchNum,
bytes32[] memory proof,
uint256 path,
bytes32 item
) internal returns (bytes32) {
require(proof.length < 256, "PROOF_TOO_LONG");
require(path < 2**proof.length, "PATH_NOT_MINIMAL");
// Hash the leaf an extra time to prove it's a leaf
bytes32 calcRoot = calculateMerkleRoot(proof, path, item);
OutboxEntry storage outboxEntry = outboxEntries[batchNum];
require(outboxEntry.root != bytes32(0), "NO_OUTBOX_ENTRY");
// With a minimal path, the pair of path and proof length should always identify
// a unique leaf. The path itself is not enough since the path length to different
// leaves could potentially be different
bytes32 uniqueKey = keccak256(abi.encodePacked(path, proof.length));
require(!outboxEntry.spentOutput[uniqueKey], "ALREADY_SPENT");
require(calcRoot == outboxEntry.root, "BAD_ROOT");
outboxEntry.spentOutput[uniqueKey] = true;
return uniqueKey;
}
function executeBridgeCall(
address destAddr,
uint256 amount,
bytes memory data
) internal {
(bool success, bytes memory returndata) = bridge.executeCall(destAddr, amount, data);
if (!success) {
if (returndata.length > 0) {
// solhint-disable-next-line no-inline-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert("BRIDGE_CALL_FAILED");
}
}
}
function calculateItemHash(
address l2Sender,
address destAddr,
uint256 l2Block,
uint256 l1Block,
uint256 l2Timestamp,
uint256 amount,
bytes calldata calldataForL1
) public pure returns (bytes32) {
return
keccak256(
abi.encodePacked(
SendType_sendTxToL1,
uint256(uint160(bytes20(l2Sender))),
uint256(uint160(bytes20(destAddr))),
l2Block,
l1Block,
l2Timestamp,
amount,
calldataForL1
)
);
}
function calculateMerkleRoot(
bytes32[] memory proof,
uint256 path,
bytes32 item
) public pure returns (bytes32) {
return MerkleLib.calculateRoot(proof, path, keccak256(abi.encodePacked(item)));
}
function outboxEntryExists(uint256 batchNum) public view override returns (bool) {
return outboxEntries[batchNum].root != bytes32(0);
}
}
// SPDX-License-Identifier: Apache-2.0
/*
* Copyright 2021, Offchain Labs, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity ^0.6.11;
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);
}
// SPDX-License-Identifier: Apache-2.0
/*
* Copyright 2021, Offchain Labs, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity ^0.6.11;
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);
// These are only callable by the admin
function setInbox(address inbox, bool enabled) external;
function setOutbox(address inbox, bool enabled) external;
// View functions
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);
}
// SPDX-License-Identifier: Apache-2.0
/*
* Copyright 2019-2021, Offchain Labs, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity ^0.6.11;
library Messages {
function messageHash(
uint8 kind,
address sender,
uint256 blockNumber,
uint256 timestamp,
uint256 inboxSeqNum,
uint256 gasPriceL1,
bytes32 messageDataHash
) internal pure returns (bytes32) {
return
keccak256(
abi.encodePacked(
kind,
sender,
blockNumber,
timestamp,
inboxSeqNum,
gasPriceL1,
messageDataHash
)
);
}
function addMessageToInbox(bytes32 inbox, bytes32 message) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(inbox, message));
}
}
// SPDX-License-Identifier: Apache-2.0
/*
* Copyright 2019-2021, Offchain Labs, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity ^0.6.11;
library MerkleLib {
function generateRoot(bytes32[] memory _hashes) internal pure returns (bytes32) {
bytes32[] memory prevLayer = _hashes;
while (prevLayer.length > 1) {
bytes32[] memory nextLayer = new bytes32[]((prevLayer.length + 1) / 2);
for (uint256 i = 0; i < nextLayer.length; i++) {
if (2 * i + 1 < prevLayer.length) {
nextLayer[i] = keccak256(
abi.encodePacked(prevLayer[2 * i], prevLayer[2 * i + 1])
);
} else {
nextLayer[i] = prevLayer[2 * i];
}
}
prevLayer = nextLayer;
}
return prevLayer[0];
}
function calculateRoot(
bytes32[] memory nodes,
uint256 route,
bytes32 item
) internal pure returns (bytes32) {
uint256 proofItems = nodes.length;
require(proofItems <= 256);
bytes32 h = item;
for (uint256 i = 0; i < proofItems; i++) {
if (route % 2 == 0) {
h = keccak256(abi.encodePacked(nodes[i], h));
} else {
h = keccak256(abi.encodePacked(h, nodes[i]));
}
route /= 2;
}
return h;
}
}
// SPDX-License-Identifier: MIT
/*
* @title Solidity Bytes Arrays Utils
* @author Gonçalo Sá <[email protected]>
*
* @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.
* The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.
*/
pragma solidity ^0.6.11;
/* solhint-disable no-inline-assembly */
library BytesLib {
function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {
require(_bytes.length >= (_start + 20), "Read out of bounds");
address tempAddress;
assembly {
tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
}
return tempAddress;
}
function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) {
require(_bytes.length >= (_start + 1), "Read out of bounds");
uint8 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x1), _start))
}
return tempUint;
}
function toUint(bytes memory _bytes, uint256 _start) internal pure returns (uint256) {
require(_bytes.length >= (_start + 32), "Read out of bounds");
uint256 tempUint;
assembly {
tempUint := mload(add(add(_bytes, 0x20), _start))
}
return tempUint;
}
function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) {
require(_bytes.length >= (_start + 32), "Read out of bounds");
bytes32 tempBytes32;
assembly {
tempBytes32 := mload(add(add(_bytes, 0x20), _start))
}
return tempBytes32;
}
}
/* solhint-enable no-inline-assembly */
// SPDX-License-Identifier: Apache-2.0
/*
* Copyright 2019-2020, Offchain Labs, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity ^0.6.11;
import "./ICloneable.sol";
contract Cloneable is ICloneable {
string private constant NOT_CLONE = "NOT_CLONE";
bool private isMasterCopy;
constructor() public {
isMasterCopy = true;
}
function isMaster() external view override returns (bool) {
return isMasterCopy;
}
function safeSelfDestruct(address payable dest) internal {
require(!isMasterCopy, NOT_CLONE);
selfdestruct(dest);
}
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
import "./Proxy.sol";
import "../utils/Address.sol";
import "./IBeacon.sol";
/**
* @dev This contract implements a proxy that gets the implementation address for each call from a {UpgradeableBeacon}.
*
* The beacon address is stored in storage slot `uint256(keccak256('eip1967.proxy.beacon')) - 1`, so that it doesn't
* conflict with the storage layout of the implementation behind the proxy.
*
* _Available since v3.4._
*/
contract BeaconProxy is Proxy {
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
*/
bytes32 private constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Initializes the proxy with `beacon`.
*
* If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This
* will typically be an encoded function call, and allows initializating the storage of the proxy like a Solidity
* constructor.
*
* Requirements:
*
* - `beacon` must be a contract with the interface {IBeacon}.
*/
constructor(address beacon, bytes memory data) public payable {
assert(_BEACON_SLOT == bytes32(uint256(keccak256("eip1967.proxy.beacon")) - 1));
_setBeacon(beacon, data);
}
/**
* @dev Returns the current beacon address.
*/
function _beacon() internal view virtual returns (address beacon) {
bytes32 slot = _BEACON_SLOT;
// solhint-disable-next-line no-inline-assembly
assembly {
beacon := sload(slot)
}
}
/**
* @dev Returns the current implementation address of the associated beacon.
*/
function _implementation() internal view virtual override returns (address) {
return IBeacon(_beacon()).implementation();
}
/**
* @dev Changes the proxy to use a new beacon.
*
* If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon.
*
* Requirements:
*
* - `beacon` must be a contract.
* - The implementation returned by `beacon` must be a contract.
*/
function _setBeacon(address beacon, bytes memory data) internal virtual {
require(
Address.isContract(beacon),
"BeaconProxy: beacon is not a contract"
);
require(
Address.isContract(IBeacon(beacon).implementation()),
"BeaconProxy: beacon implementation is not a contract"
);
bytes32 slot = _BEACON_SLOT;
// solhint-disable-next-line no-inline-assembly
assembly {
sstore(slot, beacon)
}
if (data.length > 0) {
Address.functionDelegateCall(_implementation(), data, "BeaconProxy: function call failed");
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
import "./IBeacon.sol";
import "../access/Ownable.sol";
import "../utils/Address.sol";
/**
* @dev This contract is used in conjunction with one or more instances of {BeaconProxy} to determine their
* implementation contract, which is where they will delegate all function calls.
*
* An owner is able to change the implementation the beacon points to, thus upgrading the proxies that use this beacon.
*/
contract UpgradeableBeacon is IBeacon, Ownable {
address private _implementation;
/**
* @dev Emitted when the implementation returned by the beacon is changed.
*/
event Upgraded(address indexed implementation);
/**
* @dev Sets the address of the initial implementation, and the deployer account as the owner who can upgrade the
* beacon.
*/
constructor(address implementation_) public {
_setImplementation(implementation_);
}
/**
* @dev Returns the current implementation address.
*/
function implementation() public view virtual override returns (address) {
return _implementation;
}
/**
* @dev Upgrades the beacon to a new implementation.
*
* Emits an {Upgraded} event.
*
* Requirements:
*
* - msg.sender must be the owner of the contract.
* - `newImplementation` must be a contract.
*/
function upgradeTo(address newImplementation) public virtual onlyOwner {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
}
/**
* @dev Sets the implementation contract address for this beacon
*
* Requirements:
*
* - `newImplementation` must be a contract.
*/
function _setImplementation(address newImplementation) private {
require(Address.isContract(newImplementation), "UpgradeableBeacon: implementation is not a contract");
_implementation = newImplementation;
}
}
// SPDX-License-Identifier: Apache-2.0
/*
* Copyright 2019, Offchain Labs, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity ^0.6.11;
interface ICloneable {
function isMaster() external view returns (bool);
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
/**
* @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
* instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
* be specified by overriding the virtual {_implementation} function.
*
* Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
* different contract through the {_delegate} function.
*
* The success and return data of the delegated call will be returned back to the caller of the proxy.
*/
abstract contract Proxy {
/**
* @dev Delegates the current call to `implementation`.
*
* This function does not return to its internall call site, it will return directly to the external caller.
*/
function _delegate(address implementation) internal virtual {
// solhint-disable-next-line no-inline-assembly
assembly {
// Copy msg.data. We take full control of memory in this inline assembly
// block because it will not return to Solidity code. We overwrite the
// Solidity scratch pad at memory position 0.
calldatacopy(0, 0, calldatasize())
// Call the implementation.
// out and outsize are 0 because we don't know the size yet.
let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
// Copy the returned data.
returndatacopy(0, 0, returndatasize())
switch result
// delegatecall returns 0 on error.
case 0 { revert(0, returndatasize()) }
default { return(0, returndatasize()) }
}
}
/**
* @dev This is a virtual function that should be overriden so it returns the address to which the fallback function
* and {_fallback} should delegate.
*/
function _implementation() internal view virtual returns (address);
/**
* @dev Delegates the current call to the address returned by `_implementation()`.
*
* This function does not return to its internall call site, it will return directly to the external caller.
*/
function _fallback() internal virtual {
_beforeFallback();
_delegate(_implementation());
}
/**
* @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
* function in the contract matches the call data.
*/
fallback () external payable virtual {
_fallback();
}
/**
* @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
* is empty.
*/
receive () external payable virtual {
_fallback();
}
/**
* @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
* call, or as part of the Solidity `fallback` or `receive` functions.
*
* If overriden should call `super._beforeFallback()`.
*/
function _beforeFallback() internal virtual {
}
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2 <0.8.0;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize, which returns 0 for contracts in
// construction, since the code is only stored at the end of the
// constructor execution.
uint256 size;
// solhint-disable-next-line no-inline-assembly
assembly { size := extcodesize(account) }
return size > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
// solhint-disable-next-line avoid-low-level-calls, avoid-call-value
(bool success, ) = recipient.call{ value: amount }("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain`call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
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");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
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");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = target.call{ value: value }(data);
return _verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = target.staticcall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = target.delegatecall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
// solhint-disable-next-line no-inline-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeacon {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {BeaconProxy} will check that this address is a contract.
*/
function implementation() external view returns (address);
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor () internal {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
/*
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with GSN meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
return msg.data;
}
}