// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)pragmasolidity ^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 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.
*/abstractcontractContext{
function_msgSender() internalviewvirtualreturns (address) {
returnmsg.sender;
}
function_msgData() internalviewvirtualreturns (bytescalldata) {
returnmsg.data;
}
}
Contract Source Code
File 2 of 11: CryptoDadsStake.sol
//SPDX-License-Identifier: MITpragmasolidity ^0.8.9;import"@openzeppelin/contracts/access/Ownable.sol";
import"@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol";
import"./tunnel/FxBaseRootTunnel.sol";
/**
* Cross-bridge staking contract via fx-portal
* Ethereum: source chain
* Polygon: destination chain
*
* @title CryptoDadsStake
* @author @ScottMitchell18
*/contractCryptoDadsStakeisFxBaseRootTunnel, Ownable{
addresspublic dadAddress;
addresspublic momAddress;
boolpublic stakingPaused;
/// @dev Users' staked tokens mapped from their addressmapping(address=>mapping(address=>mapping(uint256=>bool)))
public staked;
constructor(address _checkpointManager,
address _fxRoot,
address _dadAddress,
address _momAddress
) FxBaseRootTunnel(_checkpointManager, _fxRoot) {
dadAddress = _dadAddress;
momAddress = _momAddress;
}
/**
* Stakes the given token ids, provided the contract is approved to move them.
* @param dadIds - the dad token ids to stake
* @param momIds - the mom token ids to stake
*/functionstake(uint256[] calldata dadIds, uint256[] calldata momIds)
external{
require(!stakingPaused, "Staking paused");
require(
dadIds.length>0|| momIds.length>0,
"Staking requires at least 1 token"
);
// Dadsif (dadIds.length>0) {
IERC721Enumerable contractInstance = IERC721Enumerable(dadAddress);
for (uint256 i; i < dadIds.length; i++) {
contractInstance.transferFrom(
msg.sender,
address(this),
dadIds[i]
);
staked[dadAddress][msg.sender][dadIds[i]] =true;
}
}
// Momsif (momIds.length>0) {
IERC721Enumerable contractInstance = IERC721Enumerable(momAddress);
for (uint256 j; j < momIds.length; j++) {
contractInstance.transferFrom(
msg.sender,
address(this),
momIds[j]
);
staked[momAddress][msg.sender][momIds[j]] =true;
}
}
// Emit sync to child chain
_sendChildMessage(msg.sender, dadIds, momIds, true);
}
/**
* Unstakes the given token ids.
* @param dadIds - the dad token ids to unstake
* @param momIds - the mom token ids to unstake
*/functionunstake(uint256[] calldata dadIds, uint256[] calldata momIds)
external{
require(
dadIds.length>0|| momIds.length>0,
"Unstaking requires at least 1 token"
);
// Dadsif (dadIds.length>0) {
IERC721Enumerable contractInstance = IERC721Enumerable(dadAddress);
for (uint256 i; i < dadIds.length; i++) {
require(staked[dadAddress][msg.sender][dadIds[i]], "Not owned");
contractInstance.transferFrom(
address(this),
msg.sender,
dadIds[i]
);
staked[dadAddress][msg.sender][dadIds[i]] =false;
}
}
// Momsif (momIds.length>0) {
IERC721Enumerable contractInstance = IERC721Enumerable(momAddress);
for (uint256 i; i < momIds.length; i++) {
require(staked[momAddress][msg.sender][momIds[i]], "Not owned");
contractInstance.transferFrom(
address(this),
msg.sender,
momIds[i]
);
staked[momAddress][msg.sender][momIds[i]] =false;
}
}
// Emit sync to child chain
_sendChildMessage(msg.sender, dadIds, momIds, false);
}
/**
* @dev Set active state of staking protocol
* @param paused - the state's new value.
*/functionsetStakingPaused(bool paused) externalonlyOwner{
stakingPaused = paused;
}
/**
* Set FxChildTunnel
* @param _fxChildTunnel - the fxChildTunnel address
*/functionsetFxChildTunnel(address _fxChildTunnel)
publicoverrideonlyOwner{
fxChildTunnel = _fxChildTunnel;
}
/**
* Sends message the child contract
* @param from - the user that staked/unstaked
* @param dadIds - the dad tokenIds staked/unstaked
* @param momIds - the mom tokenIds staked/unstaked
* @param isInbound - true if staking, false if unstaking
*/function_sendChildMessage(addressfrom,
uint256[] calldata dadIds,
uint256[] calldata momIds,
bool isInbound
) internal{
_sendMessageToChild(abi.encode(from, dadIds, momIds, isInbound));
}
function_processMessageFromChild(bytesmemory) internaloverride{}
}
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;import {RLPReader} from"../lib/RLPReader.sol";
import {MerklePatriciaProof} from"../lib/MerklePatriciaProof.sol";
import {Merkle} from"../lib/Merkle.sol";
import"../lib/ExitPayloadReader.sol";
interfaceIFxStateSender{
functionsendMessageToChild(address _receiver, bytescalldata _data)
external;
}
contractICheckpointManager{
structHeaderBlock {
bytes32 root;
uint256 start;
uint256 end;
uint256 createdAt;
address proposer;
}
/**
* @notice mapping of checkpoint header numbers to block details
* @dev These checkpoints are submited by plasma contracts
*/mapping(uint256=> HeaderBlock) public headerBlocks;
}
abstractcontractFxBaseRootTunnel{
usingRLPReaderforRLPReader.RLPItem;
usingMerkleforbytes32;
usingExitPayloadReaderforbytes;
usingExitPayloadReaderforExitPayloadReader.ExitPayload;
usingExitPayloadReaderforExitPayloadReader.Log;
usingExitPayloadReaderforExitPayloadReader.LogTopics;
usingExitPayloadReaderforExitPayloadReader.Receipt;
// keccak256(MessageSent(bytes))bytes32publicconstant SEND_MESSAGE_EVENT_SIG =0x8c5261668696ce22758910d05bab8f186d6eb247ceac2af2e82c7dc17669b036;
// state sender contract
IFxStateSender public fxRoot;
// root chain manager
ICheckpointManager public checkpointManager;
// child tunnel contract which receives and sends messagesaddresspublic fxChildTunnel;
// storage to avoid duplicate exitsmapping(bytes32=>bool) public processedExits;
constructor(address _checkpointManager, address _fxRoot) {
checkpointManager = ICheckpointManager(_checkpointManager);
fxRoot = IFxStateSender(_fxRoot);
}
// set fxChildTunnel if not set alreadyfunctionsetFxChildTunnel(address _fxChildTunnel) publicvirtual{
require(
fxChildTunnel ==address(0x0),
"FxBaseRootTunnel: CHILD_TUNNEL_ALREADY_SET"
);
fxChildTunnel = _fxChildTunnel;
}
/**
* @notice Send bytes message to Child Tunnel
* @param message bytes message that will be sent to Child Tunnel
* some message examples -
* abi.encode(tokenId);
* abi.encode(tokenId, tokenMetadata);
* abi.encode(messageType, messageData);
*/function_sendMessageToChild(bytesmemory message) internal{
fxRoot.sendMessageToChild(fxChildTunnel, message);
}
function_validateAndExtractMessage(bytesmemory inputData)
internalreturns (bytesmemory)
{
ExitPayloadReader.ExitPayload memory payload = inputData
.toExitPayload();
bytesmemory branchMaskBytes = payload.getBranchMaskAsBytes();
uint256 blockNumber = payload.getBlockNumber();
// checking if exit has already been processed// unique exit is identified using hash of (blockNumber, branchMask, receiptLogIndex)bytes32 exitHash =keccak256(
abi.encodePacked(
blockNumber,
// first 2 nibbles are dropped while generating nibble array// this allows branch masks that are valid but bypass exitHash check (changing first 2 nibbles only)// so converting to nibble array and then hashing it
MerklePatriciaProof._getNibbleArray(branchMaskBytes),
payload.getReceiptLogIndex()
)
);
require(
processedExits[exitHash] ==false,
"FxRootTunnel: EXIT_ALREADY_PROCESSED"
);
processedExits[exitHash] =true;
ExitPayloadReader.Receipt memory receipt = payload.getReceipt();
ExitPayloadReader.Log memory log = receipt.getLog();
// check child tunnelrequire(
fxChildTunnel == log.getEmitter(),
"FxRootTunnel: INVALID_FX_CHILD_TUNNEL"
);
bytes32 receiptRoot = payload.getReceiptRoot();
// verify receipt inclusionrequire(
MerklePatriciaProof.verify(
receipt.toBytes(),
branchMaskBytes,
payload.getReceiptProof(),
receiptRoot
),
"FxRootTunnel: INVALID_RECEIPT_PROOF"
);
// verify checkpoint inclusion
_checkBlockMembershipInCheckpoint(
blockNumber,
payload.getBlockTime(),
payload.getTxRoot(),
receiptRoot,
payload.getHeaderNumber(),
payload.getBlockProof()
);
ExitPayloadReader.LogTopics memory topics = log.getTopics();
require(
bytes32(topics.getField(0).toUint()) == SEND_MESSAGE_EVENT_SIG, // topic0 is event sig"FxRootTunnel: INVALID_SIGNATURE"
);
// received message databytesmemory message =abi.decode(log.getData(), (bytes)); // event decodes params again, so decoding bytes to get messagereturn message;
}
function_checkBlockMembershipInCheckpoint(uint256 blockNumber,
uint256 blockTime,
bytes32 txRoot,
bytes32 receiptRoot,
uint256 headerNumber,
bytesmemory blockProof
) privateviewreturns (uint256) {
(
bytes32 headerRoot,
uint256 startBlock,
,
uint256 createdAt,
) = checkpointManager.headerBlocks(headerNumber);
require(
keccak256(
abi.encodePacked(blockNumber, blockTime, txRoot, receiptRoot)
).checkMembership(blockNumber - startBlock, headerRoot, blockProof),
"FxRootTunnel: INVALID_HEADER"
);
return createdAt;
}
/**
* @notice receive message from L2 to L1, validated by proof
* @dev This function verifies if the transaction actually happened on child chain
*
* @param inputData RLP encoded data of the reference tx containing following list of fields
* 0 - headerNumber - Checkpoint header block number containing the reference tx
* 1 - blockProof - Proof that the block header (in the child chain) is a leaf in the submitted merkle root
* 2 - blockNumber - Block number containing the reference tx on child chain
* 3 - blockTime - Reference tx block time
* 4 - txRoot - Transactions root of block
* 5 - receiptRoot - Receipts root of block
* 6 - receipt - Receipt of the reference transaction
* 7 - receiptProof - Merkle proof of the reference receipt
* 8 - branchMask - 32 bits denoting the path of receipt in merkle tree
* 9 - receiptLogIndex - Log Index to read from the receipt
*/functionreceiveMessage(bytesmemory inputData) publicvirtual{
bytesmemory message = _validateAndExtractMessage(inputData);
_processMessageFromChild(message);
}
/**
* @notice Process message received from Child Tunnel
* @dev function needs to be implemented to handle message as per requirement
* This is called by onStateReceive function.
* Since it is called via a system call, any event will not be emitted during its execution.
* @param message bytes message that was sent from Child Tunnel
*/function_processMessageFromChild(bytesmemory message) internalvirtual;
}
Contract Source Code
File 5 of 11: IERC165.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)pragmasolidity ^0.8.0;/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/interfaceIERC165{
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/functionsupportsInterface(bytes4 interfaceId) externalviewreturns (bool);
}
Contract Source Code
File 6 of 11: IERC721.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721.sol)pragmasolidity ^0.8.0;import"../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/interfaceIERC721isIERC165{
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/eventTransfer(addressindexedfrom, addressindexed to, uint256indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/eventApproval(addressindexed owner, addressindexed approved, uint256indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/eventApprovalForAll(addressindexed owner, addressindexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/functionbalanceOf(address owner) externalviewreturns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/functionownerOf(uint256 tokenId) externalviewreturns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId,
bytescalldata data
) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/functionsafeTransferFrom(addressfrom,
address to,
uint256 tokenId
) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/functiontransferFrom(addressfrom,
address to,
uint256 tokenId
) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/functionapprove(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/functionsetApprovalForAll(address operator, bool _approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/functiongetApproved(uint256 tokenId) externalviewreturns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/functionisApprovedForAll(address owner, address operator) externalviewreturns (bool);
}
Contract Source Code
File 7 of 11: IERC721Enumerable.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/extensions/IERC721Enumerable.sol)pragmasolidity ^0.8.0;import"../IERC721.sol";
/**
* @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/interfaceIERC721EnumerableisIERC721{
/**
* @dev Returns the total amount of tokens stored by the contract.
*/functiontotalSupply() externalviewreturns (uint256);
/**
* @dev Returns a token ID owned by `owner` at a given `index` of its token list.
* Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
*/functiontokenOfOwnerByIndex(address owner, uint256 index) externalviewreturns (uint256);
/**
* @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
* Use along with {totalSupply} to enumerate all tokens.
*/functiontokenByIndex(uint256 index) externalviewreturns (uint256);
}
Contract Source Code
File 8 of 11: Merkle.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;libraryMerkle{
functioncheckMembership(bytes32 leaf,
uint256 index,
bytes32 rootHash,
bytesmemory proof
) internalpurereturns (bool) {
require(proof.length%32==0, "Invalid proof length");
uint256 proofHeight = proof.length/32;
// Proof of size n means, height of the tree is n+1.// In a tree of height n+1, max #leafs possible is 2 ^ nrequire(index <2**proofHeight, "Leaf index is too big");
bytes32 proofElement;
bytes32 computedHash = leaf;
for (uint256 i =32; i <= proof.length; i +=32) {
assembly {
proofElement :=mload(add(proof, i))
}
if (index %2==0) {
computedHash =keccak256(abi.encodePacked(computedHash, proofElement));
} else {
computedHash =keccak256(abi.encodePacked(proofElement, computedHash));
}
index = index /2;
}
return computedHash == rootHash;
}
}
Contract Source Code
File 9 of 11: MerklePatriciaProof.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.0;import {RLPReader} from"./RLPReader.sol";
libraryMerklePatriciaProof{
/*
* @dev Verifies a merkle patricia proof.
* @param value The terminating value in the trie.
* @param encodedPath The path in the trie leading to value.
* @param rlpParentNodes The rlp encoded stack of nodes.
* @param root The root hash of the trie.
* @return The boolean validity of the proof.
*/functionverify(bytesmemory value,
bytesmemory encodedPath,
bytesmemory rlpParentNodes,
bytes32 root
) internalpurereturns (bool) {
RLPReader.RLPItem memory item = RLPReader.toRlpItem(rlpParentNodes);
RLPReader.RLPItem[] memory parentNodes = RLPReader.toList(item);
bytesmemory currentNode;
RLPReader.RLPItem[] memory currentNodeList;
bytes32 nodeKey = root;
uint256 pathPtr =0;
bytesmemory path = _getNibbleArray(encodedPath);
if (path.length==0) {
returnfalse;
}
for (uint256 i =0; i < parentNodes.length; i++) {
if (pathPtr > path.length) {
returnfalse;
}
currentNode = RLPReader.toRlpBytes(parentNodes[i]);
if (nodeKey !=keccak256(currentNode)) {
returnfalse;
}
currentNodeList = RLPReader.toList(parentNodes[i]);
if (currentNodeList.length==17) {
if (pathPtr == path.length) {
if (keccak256(RLPReader.toBytes(currentNodeList[16])) ==keccak256(value)) {
returntrue;
} else {
returnfalse;
}
}
uint8 nextPathNibble =uint8(path[pathPtr]);
if (nextPathNibble >16) {
returnfalse;
}
nodeKey =bytes32(RLPReader.toUintStrict(currentNodeList[nextPathNibble]));
pathPtr +=1;
} elseif (currentNodeList.length==2) {
uint256 traversed = _nibblesToTraverse(RLPReader.toBytes(currentNodeList[0]), path, pathPtr);
if (pathPtr + traversed == path.length) {
//leaf nodeif (keccak256(RLPReader.toBytes(currentNodeList[1])) ==keccak256(value)) {
returntrue;
} else {
returnfalse;
}
}
//extension nodeif (traversed ==0) {
returnfalse;
}
pathPtr += traversed;
nodeKey =bytes32(RLPReader.toUintStrict(currentNodeList[1]));
} else {
returnfalse;
}
}
}
function_nibblesToTraverse(bytesmemory encodedPartialPath,
bytesmemory path,
uint256 pathPtr
) privatepurereturns (uint256) {
uint256 len =0;
// encodedPartialPath has elements that are each two hex characters (1 byte), but partialPath// and slicedPath have elements that are each one hex character (1 nibble)bytesmemory partialPath = _getNibbleArray(encodedPartialPath);
bytesmemory slicedPath =newbytes(partialPath.length);
// pathPtr counts nibbles in path// partialPath.length is a number of nibblesfor (uint256 i = pathPtr; i < pathPtr + partialPath.length; i++) {
bytes1 pathNibble = path[i];
slicedPath[i - pathPtr] = pathNibble;
}
if (keccak256(partialPath) ==keccak256(slicedPath)) {
len = partialPath.length;
} else {
len =0;
}
return len;
}
// bytes b must be hp encodedfunction_getNibbleArray(bytesmemory b) internalpurereturns (bytesmemory) {
bytesmemory nibbles ="";
if (b.length>0) {
uint8 offset;
uint8 hpNibble =uint8(_getNthNibbleOfBytes(0, b));
if (hpNibble ==1|| hpNibble ==3) {
nibbles =newbytes(b.length*2-1);
bytes1 oddNibble = _getNthNibbleOfBytes(1, b);
nibbles[0] = oddNibble;
offset =1;
} else {
nibbles =newbytes(b.length*2-2);
offset =0;
}
for (uint256 i = offset; i < nibbles.length; i++) {
nibbles[i] = _getNthNibbleOfBytes(i - offset +2, b);
}
}
return nibbles;
}
function_getNthNibbleOfBytes(uint256 n, bytesmemory str) privatepurereturns (bytes1) {
returnbytes1(n %2==0 ? uint8(str[n /2]) /0x10 : uint8(str[n /2]) %0x10);
}
}
Contract Source Code
File 10 of 11: Ownable.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)pragmasolidity ^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.
*/abstractcontractOwnableisContext{
addressprivate _owner;
eventOwnershipTransferred(addressindexed previousOwner, addressindexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Returns the address of the current owner.
*/functionowner() publicviewvirtualreturns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/modifieronlyOwner() {
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.
*/functionrenounceOwnership() publicvirtualonlyOwner{
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/functiontransferOwnership(address newOwner) publicvirtualonlyOwner{
require(newOwner !=address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/function_transferOwnership(address newOwner) internalvirtual{
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
Contract Source Code
File 11 of 11: RLPReader.sol
/*
* @author Hamdi Allam hamdi.allam97@gmail.com
* Please reach out with any questions or concerns
*/pragmasolidity ^0.8.0;libraryRLPReader{
uint8constant STRING_SHORT_START =0x80;
uint8constant STRING_LONG_START =0xb8;
uint8constant LIST_SHORT_START =0xc0;
uint8constant LIST_LONG_START =0xf8;
uint8constant WORD_SIZE =32;
structRLPItem {
uint256 len;
uint256 memPtr;
}
structIterator {
RLPItem item; // Item that's being iterated over.uint256 nextPtr; // Position of the next item in the list.
}
/*
* @dev Returns the next element in the iteration. Reverts if it has not next element.
* @param self The iterator.
* @return The next element in the iteration.
*/functionnext(Iterator memoryself) internalpurereturns (RLPItem memory) {
require(hasNext(self));
uint256 ptr =self.nextPtr;
uint256 itemLength = _itemLength(ptr);
self.nextPtr = ptr + itemLength;
return RLPItem(itemLength, ptr);
}
/*
* @dev Returns true if the iteration has more elements.
* @param self The iterator.
* @return true if the iteration has more elements.
*/functionhasNext(Iterator memoryself) internalpurereturns (bool) {
RLPItem memory item =self.item;
returnself.nextPtr < item.memPtr + item.len;
}
/*
* @param item RLP encoded bytes
*/functiontoRlpItem(bytesmemory item) internalpurereturns (RLPItem memory) {
uint256 memPtr;
assembly {
memPtr :=add(item, 0x20)
}
return RLPItem(item.length, memPtr);
}
/*
* @dev Create an iterator. Reverts if item is not a list.
* @param self The RLP item.
* @return An 'Iterator' over the item.
*/functioniterator(RLPItem memoryself) internalpurereturns (Iterator memory) {
require(isList(self));
uint256 ptr =self.memPtr + _payloadOffset(self.memPtr);
return Iterator(self, ptr);
}
/*
* @param item RLP encoded bytes
*/functionrlpLen(RLPItem memory item) internalpurereturns (uint256) {
return item.len;
}
/*
* @param item RLP encoded bytes
*/functionpayloadLen(RLPItem memory item) internalpurereturns (uint256) {
return item.len - _payloadOffset(item.memPtr);
}
/*
* @param item RLP encoded list in bytes
*/functiontoList(RLPItem memory item) internalpurereturns (RLPItem[] memory) {
require(isList(item));
uint256 items = numItems(item);
RLPItem[] memory result =new RLPItem[](items);
uint256 memPtr = item.memPtr + _payloadOffset(item.memPtr);
uint256 dataLen;
for (uint256 i =0; i < items; i++) {
dataLen = _itemLength(memPtr);
result[i] = RLPItem(dataLen, memPtr);
memPtr = memPtr + dataLen;
}
return result;
}
// @return indicator whether encoded payload is a list. negate this function call for isData.functionisList(RLPItem memory item) internalpurereturns (bool) {
if (item.len ==0) returnfalse;
uint8 byte0;
uint256 memPtr = item.memPtr;
assembly {
byte0 :=byte(0, mload(memPtr))
}
if (byte0 < LIST_SHORT_START) returnfalse;
returntrue;
}
/*
* @dev A cheaper version of keccak256(toRlpBytes(item)) that avoids copying memory.
* @return keccak256 hash of RLP encoded bytes.
*/functionrlpBytesKeccak256(RLPItem memory item) internalpurereturns (bytes32) {
uint256 ptr = item.memPtr;
uint256 len = item.len;
bytes32 result;
assembly {
result :=keccak256(ptr, len)
}
return result;
}
functionpayloadLocation(RLPItem memory item) internalpurereturns (uint256, uint256) {
uint256 offset = _payloadOffset(item.memPtr);
uint256 memPtr = item.memPtr + offset;
uint256 len = item.len - offset; // data lengthreturn (memPtr, len);
}
/*
* @dev A cheaper version of keccak256(toBytes(item)) that avoids copying memory.
* @return keccak256 hash of the item payload.
*/functionpayloadKeccak256(RLPItem memory item) internalpurereturns (bytes32) {
(uint256 memPtr, uint256 len) = payloadLocation(item);
bytes32 result;
assembly {
result :=keccak256(memPtr, len)
}
return result;
}
/** RLPItem conversions into data types **/// @returns raw rlp encoding in bytesfunctiontoRlpBytes(RLPItem memory item) internalpurereturns (bytesmemory) {
bytesmemory result =newbytes(item.len);
if (result.length==0) return result;
uint256 ptr;
assembly {
ptr :=add(0x20, result)
}
copy(item.memPtr, ptr, item.len);
return result;
}
// any non-zero byte is considered truefunctiontoBoolean(RLPItem memory item) internalpurereturns (bool) {
require(item.len ==1);
uint256 result;
uint256 memPtr = item.memPtr;
assembly {
result :=byte(0, mload(memPtr))
}
return result ==0 ? false : true;
}
functiontoAddress(RLPItem memory item) internalpurereturns (address) {
// 1 byte for the length prefixrequire(item.len ==21);
returnaddress(uint160(toUint(item)));
}
functiontoUint(RLPItem memory item) internalpurereturns (uint256) {
require(item.len >0&& item.len <=33);
uint256 offset = _payloadOffset(item.memPtr);
uint256 len = item.len - offset;
uint256 result;
uint256 memPtr = item.memPtr + offset;
assembly {
result :=mload(memPtr)
// shfit to the correct location if neccesaryiflt(len, 32) {
result :=div(result, exp(256, sub(32, len)))
}
}
return result;
}
// enforces 32 byte lengthfunctiontoUintStrict(RLPItem memory item) internalpurereturns (uint256) {
// one byte prefixrequire(item.len ==33);
uint256 result;
uint256 memPtr = item.memPtr +1;
assembly {
result :=mload(memPtr)
}
return result;
}
functiontoBytes(RLPItem memory item) internalpurereturns (bytesmemory) {
require(item.len >0);
uint256 offset = _payloadOffset(item.memPtr);
uint256 len = item.len - offset; // data lengthbytesmemory result =newbytes(len);
uint256 destPtr;
assembly {
destPtr :=add(0x20, result)
}
copy(item.memPtr + offset, destPtr, len);
return result;
}
/*
* Private Helpers
*/// @return number of payload items inside an encoded list.functionnumItems(RLPItem memory item) privatepurereturns (uint256) {
if (item.len ==0) return0;
uint256 count =0;
uint256 currPtr = item.memPtr + _payloadOffset(item.memPtr);
uint256 endPtr = item.memPtr + item.len;
while (currPtr < endPtr) {
currPtr = currPtr + _itemLength(currPtr); // skip over an item
count++;
}
return count;
}
// @return entire rlp item byte lengthfunction_itemLength(uint256 memPtr) privatepurereturns (uint256) {
uint256 itemLen;
uint256 byte0;
assembly {
byte0 :=byte(0, mload(memPtr))
}
if (byte0 < STRING_SHORT_START) itemLen =1;
elseif (byte0 < STRING_LONG_START) itemLen = byte0 - STRING_SHORT_START +1;
elseif (byte0 < LIST_SHORT_START) {
assembly {
let byteLen :=sub(byte0, 0xb7) // # of bytes the actual length is
memPtr :=add(memPtr, 1) // skip over the first byte/* 32 byte word size */let dataLen :=div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to get the len
itemLen :=add(dataLen, add(byteLen, 1))
}
} elseif (byte0 < LIST_LONG_START) {
itemLen = byte0 - LIST_SHORT_START +1;
} else {
assembly {
let byteLen :=sub(byte0, 0xf7)
memPtr :=add(memPtr, 1)
let dataLen :=div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to the correct length
itemLen :=add(dataLen, add(byteLen, 1))
}
}
return itemLen;
}
// @return number of bytes until the datafunction_payloadOffset(uint256 memPtr) privatepurereturns (uint256) {
uint256 byte0;
assembly {
byte0 :=byte(0, mload(memPtr))
}
if (byte0 < STRING_SHORT_START) return0;
elseif (byte0 < STRING_LONG_START || (byte0 >= LIST_SHORT_START && byte0 < LIST_LONG_START)) return1;
elseif (byte0 < LIST_SHORT_START)
// being explicitreturn byte0 - (STRING_LONG_START -1) +1;
elsereturn byte0 - (LIST_LONG_START -1) +1;
}
/*
* @param src Pointer to source
* @param dest Pointer to destination
* @param len Amount of memory to copy from the source
*/functioncopy(uint256 src,
uint256 dest,
uint256 len
) privatepure{
if (len ==0) return;
// copy as many word sizes as possiblefor (; len >= WORD_SIZE; len -= WORD_SIZE) {
assembly {
mstore(dest, mload(src))
}
src += WORD_SIZE;
dest += WORD_SIZE;
}
if (len ==0) return;
// left over bytes. Mask is used to remove unwanted bytes from the worduint256 mask =256**(WORD_SIZE - len) -1;
assembly {
let srcpart :=and(mload(src), not(mask)) // zero out srclet destpart :=and(mload(dest), mask) // retrieve the bytesmstore(dest, or(destpart, srcpart))
}
}
}