Source Code
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| 0x60a06040 | 18122866 | 858 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
CartesiDApp
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// (c) Cartesi and individual authors (see AUTHORS)
// SPDX-License-Identifier: Apache-2.0 (see LICENSE)
pragma solidity ^0.8.8;
import {ICartesiDApp, Proof} from "./ICartesiDApp.sol";
import {IConsensus} from "../consensus/IConsensus.sol";
import {LibOutputValidation, OutputValidityProof} from "../library/LibOutputValidation.sol";
import {Bitmask} from "@cartesi/util/contracts/Bitmask.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {ERC721Holder} from "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol";
import {ERC1155Holder} from "@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol";
/// @title Cartesi DApp
///
/// @notice This contract acts as the base layer incarnation of a DApp running on the execution layer.
/// The DApp is hereby able to interact with other smart contracts through the execution of vouchers
/// and the validation of notices. These outputs are generated by the DApp backend on the execution
/// layer and can be proven in the base layer thanks to claims submitted by a consensus contract.
///
/// A voucher is a one-time message call to another contract. It can encode asset transfers, approvals,
/// or any other message call that doesn't require Ether to be sent along. A voucher will only be consumed
/// if the underlying message call succeeds (that is, it doesn't revert). Furthermore, the return data of
/// the message call is discarded entirely. As a protective measure against reentrancy attacks, nested
/// voucher executions are prohibited.
///
/// A notice, on the other hand, constitutes an arbitrary piece of data that can be proven any number of times.
/// On their own, they do not trigger any type of contract-to-contract interaction.
/// Rather, they merely serve to attest off-chain results, e.g. which player won a particular chess match.
///
/// Every DApp is subscribed to a consensus contract, and governed by a single address, the owner.
/// The consensus has the power of submitting claims, which, in turn, are used to validate vouchers and notices.
/// Meanwhile, the owner has complete power over the DApp, as it can replace the consensus at any time.
/// Therefore, the users of a DApp must trust both the consensus and the DApp owner.
///
/// The DApp developer can choose whichever ownership and consensus models it wants.
///
/// Examples of DApp ownership models include:
///
/// * no owner (address zero)
/// * individual signer (externally-owned account)
/// * multiple signers (multi-sig)
/// * DAO (decentralized autonomous organization)
/// * self-owned DApp (off-chain governance logic)
///
/// See `IConsensus` for examples of consensus models.
///
/// This contract inherits the following OpenZeppelin contracts.
/// For more information, please consult OpenZeppelin's official documentation.
///
/// * `Ownable`
/// * `ERC721Holder`
/// * `ERC1155Holder`
/// * `ReentrancyGuard`
///
contract CartesiDApp is
ICartesiDApp,
Ownable,
ERC721Holder,
ERC1155Holder,
ReentrancyGuard
{
using Bitmask for mapping(uint256 => uint256);
using LibOutputValidation for OutputValidityProof;
/// @notice Raised when executing an already executed voucher.
error VoucherReexecutionNotAllowed();
/// @notice Raised when the transfer fails.
error EtherTransferFailed();
/// @notice Raised when a mehtod is not called by DApp itself.
error OnlyDApp();
/// @notice The initial machine state hash.
/// @dev See the `getTemplateHash` function.
bytes32 internal immutable templateHash;
/// @notice The executed voucher bitmask, which keeps track of which vouchers
/// were executed already in order to avoid re-execution.
/// @dev See the `wasVoucherExecuted` function.
mapping(uint256 => uint256) internal voucherBitmask;
/// @notice The current consensus contract.
/// @dev See the `getConsensus` and `migrateToConsensus` functions.
IConsensus internal consensus;
/// @notice Creates a `CartesiDApp` contract.
/// @param _consensus The initial consensus contract
/// @param _owner The initial DApp owner
/// @param _templateHash The initial machine state hash
/// @dev Calls the `join` function on `_consensus`.
constructor(IConsensus _consensus, address _owner, bytes32 _templateHash) {
transferOwnership(_owner);
templateHash = _templateHash;
consensus = _consensus;
_consensus.join();
}
function executeVoucher(
address _destination,
bytes calldata _payload,
Proof calldata _proof
) external override nonReentrant returns (bool) {
bytes32 epochHash;
uint256 firstInputIndex;
uint256 lastInputIndex;
uint256 inputIndex;
// query the current consensus for the desired claim
(epochHash, firstInputIndex, lastInputIndex) = getClaim(_proof.context);
// validate input index range and calculate the input index
// based on the input index range provided by the consensus
inputIndex = _proof.validity.validateInputIndexRange(
firstInputIndex,
lastInputIndex
);
// reverts if proof isn't valid
_proof.validity.validateVoucher(_destination, _payload, epochHash);
uint256 voucherPosition = LibOutputValidation.getBitMaskPosition(
_proof.validity.outputIndexWithinInput,
inputIndex
);
// check if voucher has been executed
if (_wasVoucherExecuted(voucherPosition)) {
revert VoucherReexecutionNotAllowed();
}
// execute voucher
(bool succ, ) = _destination.call(_payload);
// if properly executed, mark it as executed and emit event
if (succ) {
voucherBitmask.setBit(voucherPosition, true);
emit VoucherExecuted(voucherPosition);
}
return succ;
}
function wasVoucherExecuted(
uint256 _inputIndex,
uint256 _outputIndexWithinInput
) external view override returns (bool) {
uint256 voucherPosition = LibOutputValidation.getBitMaskPosition(
_outputIndexWithinInput,
_inputIndex
);
return _wasVoucherExecuted(voucherPosition);
}
function _wasVoucherExecuted(
uint256 _voucherPosition
) internal view returns (bool) {
return voucherBitmask.getBit(_voucherPosition);
}
function validateNotice(
bytes calldata _notice,
Proof calldata _proof
) external view override returns (bool) {
bytes32 epochHash;
uint256 firstInputIndex;
uint256 lastInputIndex;
// query the current consensus for the desired claim
(epochHash, firstInputIndex, lastInputIndex) = getClaim(_proof.context);
// validate the epoch input index based on the input index range
// provided by the consensus
_proof.validity.validateInputIndexRange(
firstInputIndex,
lastInputIndex
);
// reverts if proof isn't valid
_proof.validity.validateNotice(_notice, epochHash);
return true;
}
/// @notice Retrieve a claim about the DApp from the current consensus.
/// The encoding of `_proofContext` might vary depending on the implementation.
/// @param _proofContext Data for retrieving the desired claim
/// @return The claimed epoch hash
/// @return The index of the first input of the epoch in the input box
/// @return The index of the last input of the epoch in the input box
function getClaim(
bytes calldata _proofContext
) internal view returns (bytes32, uint256, uint256) {
return consensus.getClaim(address(this), _proofContext);
}
function migrateToConsensus(
IConsensus _newConsensus
) external override onlyOwner {
consensus = _newConsensus;
_newConsensus.join();
emit NewConsensus(_newConsensus);
}
function getTemplateHash() external view override returns (bytes32) {
return templateHash;
}
function getConsensus() external view override returns (IConsensus) {
return consensus;
}
/// @notice Accept Ether transfers.
/// @dev If you wish to transfer Ether to a DApp while informing
/// the DApp backend of it, then please do so through the Ether portal contract.
receive() external payable {}
/// @notice Transfer some amount of Ether to some recipient.
/// @param _receiver The address which will receive the amount of Ether
/// @param _value The amount of Ether to be transferred in Wei
/// @dev This function can only be called by the DApp itself through vouchers.
/// If this method is not called by DApp itself, `OnlyDApp` error is raised.
/// If the transfer fails, `EtherTransferFailed` error is raised.
function withdrawEther(address _receiver, uint256 _value) external {
if (msg.sender != address(this)) {
revert OnlyDApp();
}
(bool sent, ) = _receiver.call{value: _value}("");
if (!sent) {
revert EtherTransferFailed();
}
}
}// SPDX-License-Identifier: Apache-2.0
// 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.8.0;
/// @title Bit Mask Library
/// @author Stephen Chen
/// @notice Implements bit mask with dynamic array
library Bitmask {
/// @notice Set a bit in the bit mask
function setBit(mapping(uint256 => uint256) storage bitmask, uint256 _bit, bool _value) public {
// calculate the number of bits has been store in bitmask now
uint256 positionOfMask = uint256(_bit / 256);
uint256 positionOfBit = _bit % 256;
if (_value) {
bitmask[positionOfMask] = bitmask[positionOfMask] | (1 << positionOfBit);
} else {
bitmask[positionOfMask] = bitmask[positionOfMask] & ~(1 << positionOfBit);
}
}
/// @notice Get a bit in the bit mask
function getBit(mapping(uint256 => uint256) storage bitmask, uint256 _bit) public view returns (bool) {
// calculate the number of bits has been store in bitmask now
uint256 positionOfMask = uint256(_bit / 256);
uint256 positionOfBit = _bit % 256;
return ((bitmask[positionOfMask] & (1 << positionOfBit)) != 0);
}
}// SPDX-License-Identifier: Apache-2.0
// 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.
/// @title CartesiMath
/// @author Felipe Argento
pragma solidity ^0.8.0;
library CartesiMathV2 {
// mapping values are packed as bytes3 each
// see test/TestCartesiMath.ts for decimal values
bytes constant log2tableTimes1M =
hex"0000000F4240182F421E8480236E082771822AD63A2DC6C0305E8532B04834C96736B3C23876D73A187A3B9D4A3D09003E5EA63FA0C540D17741F28843057D440BA745062945F60246DC1047B917488DC7495ABA4A207C4ADF8A4B98544C4B404CF8AA4DA0E64E44434EE3054F7D6D5013B750A61A5134C851BFF05247BD52CC58534DE753CC8D54486954C19C55384255AC75561E50568DE956FB575766B057D00758376F589CFA5900BA5962BC59C3135A21CA5A7EF15ADA945B34BF5B8D805BE4DF5C3AEA5C8FA95CE3265D356C5D86835DD6735E25455E73005EBFAD5F0B525F55F75F9FA25FE85A60302460770860BD0A61023061467F6189FD61CCAE620E98624FBF62902762CFD5630ECD634D12638AA963C7966403DC643F7F647A8264B4E864EEB56527EC6560906598A365D029660724663D9766738566A8F066DDDA6712476746386779AF67ACAF67DF3A6811526842FA68743268A4FC68D55C6905536934E169640A6992CF69C13169EF326A1CD46A4A186A76FF6AA38C6ACFC0";
/// @notice Approximates log2 * 1M
/// @param _num number to take log2 * 1M of
/// @return approximate log2 times 1M
function log2ApproxTimes1M(uint256 _num) public pure returns (uint256) {
require(_num > 0, "Number cannot be zero");
uint256 leading = 0;
if (_num == 1) return 0;
while (_num > 128) {
_num = _num >> 1;
leading += 1;
}
return (leading * uint256(1000000)) + (getLog2TableTimes1M(_num));
}
/// @notice navigates log2tableTimes1M
/// @param _num number to take log2 of
/// @return result after table look-up
function getLog2TableTimes1M(uint256 _num) public pure returns (uint256) {
bytes3 result = 0;
for (uint8 i = 0; i < 3; i++) {
bytes3 tempResult = log2tableTimes1M[(_num - 1) * 3 + i];
result = result | (tempResult >> (i * 8));
}
return uint256(uint24(result));
}
/// @notice get floor of log2 of number
/// @param _num number to take floor(log2) of
/// @return floor(log2) of _num
function getLog2Floor(uint256 _num) public pure returns (uint8) {
require(_num != 0, "log of zero is undefined");
return uint8(255 - clz(_num));
}
/// @notice checks if a number is Power of 2
/// @param _num number to check
/// @return true if number is power of 2, false if not
function isPowerOf2(uint256 _num) public pure returns (bool) {
if (_num == 0) return false;
return _num & (_num - 1) == 0;
}
/// @notice count trailing zeros
/// @param _num number you want the ctz of
/// @dev this a binary search implementation
function ctz(uint256 _num) public pure returns (uint256) {
if (_num == 0) return 256;
uint256 n = 0;
if (_num & 0x00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0) {
n = n + 128;
_num = _num >> 128;
}
if (_num & 0x000000000000000000000000000000000000000000000000FFFFFFFFFFFFFFFF == 0) {
n = n + 64;
_num = _num >> 64;
}
if (_num & 0x00000000000000000000000000000000000000000000000000000000FFFFFFFF == 0) {
n = n + 32;
_num = _num >> 32;
}
if (_num & 0x000000000000000000000000000000000000000000000000000000000000FFFF == 0) {
n = n + 16;
_num = _num >> 16;
}
if (_num & 0x00000000000000000000000000000000000000000000000000000000000000FF == 0) {
n = n + 8;
_num = _num >> 8;
}
if (_num & 0x000000000000000000000000000000000000000000000000000000000000000F == 0) {
n = n + 4;
_num = _num >> 4;
}
if (_num & 0x0000000000000000000000000000000000000000000000000000000000000003 == 0) {
n = n + 2;
_num = _num >> 2;
}
if (_num & 0x0000000000000000000000000000000000000000000000000000000000000001 == 0) {
n = n + 1;
}
return n;
}
/// @notice count leading zeros
/// @param _num number you want the clz of
/// @dev this a binary search implementation
function clz(uint256 _num) public pure returns (uint256) {
if (_num == 0) return 256;
uint256 n = 0;
if (_num & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000 == 0) {
n = n + 128;
_num = _num << 128;
}
if (_num & 0xFFFFFFFFFFFFFFFF000000000000000000000000000000000000000000000000 == 0) {
n = n + 64;
_num = _num << 64;
}
if (_num & 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000 == 0) {
n = n + 32;
_num = _num << 32;
}
if (_num & 0xFFFF000000000000000000000000000000000000000000000000000000000000 == 0) {
n = n + 16;
_num = _num << 16;
}
if (_num & 0xFF00000000000000000000000000000000000000000000000000000000000000 == 0) {
n = n + 8;
_num = _num << 8;
}
if (_num & 0xF000000000000000000000000000000000000000000000000000000000000000 == 0) {
n = n + 4;
_num = _num << 4;
}
if (_num & 0xC000000000000000000000000000000000000000000000000000000000000000 == 0) {
n = n + 2;
_num = _num << 2;
}
if (_num & 0x8000000000000000000000000000000000000000000000000000000000000000 == 0) {
n = n + 1;
}
return n;
}
}// SPDX-License-Identifier: Apache-2.0
// 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.
/// @title Library for Merkle proofs
pragma solidity ^0.8.0;
import "./CartesiMathV2.sol";
library MerkleV2 {
using CartesiMathV2 for uint256;
uint128 constant L_WORD_SIZE = 3; // word = 8 bytes, log = 3
// number of hashes in EMPTY_TREE_HASHES
uint128 constant EMPTY_TREE_SIZE = 1952; // 61*32=1952. 32 bytes per 61 indexes (64 words)
// merkle root hashes of trees of zero concatenated
// 32 bytes for each root, first one is keccak(0), second one is
// keccak(keccack(0), keccak(0)) and so on
bytes constant EMPTY_TREE_HASHES =
hex"011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce4d9470a821fbe90117ec357e30bad9305732fb19ddf54a07dd3e29f440619254ae39ce8537aca75e2eff3e38c98011dfe934e700a0967732fc07b430dd656a233fc9a15f5b4869c872f81087bb6104b7d63e6f9ab47f2c43f3535eae7172aa7f17d2dd614cddaa4d879276b11e0672c9560033d3e8453a1d045339d34ba601b9c37b8b13ca95166fb7af16988a70fcc90f38bf9126fd833da710a47fb37a55e68e7a427fa943d9966b389f4f257173676090c6e95f43e2cb6d65f8758111e30930b0b9deb73e155c59740bacf14a6ff04b64bb8e201a506409c3fe381ca4ea90cd5deac729d0fdaccc441d09d7325f41586ba13c801b7eccae0f95d8f3933efed8b96e5b7f6f459e9cb6a2f41bf276c7b85c10cd4662c04cbbb365434726c0a0c9695393027fb106a8153109ac516288a88b28a93817899460d6310b71cf1e6163e8806fa0d4b197a259e8c3ac28864268159d0ac85f8581ca28fa7d2c0c03eb91e3eee5ca7a3da2b3053c9770db73599fb149f620e3facef95e947c0ee860b72122e31e4bbd2b7c783d79cc30f60c6238651da7f0726f767d22747264fdb046f7549f26cc70ed5e18baeb6c81bb0625cb95bb4019aeecd40774ee87ae29ec517a71f6ee264c5d761379b3d7d617ca83677374b49d10aec50505ac087408ca892b573c267a712a52e1d06421fe276a03efb1889f337201110fdc32a81f8e152499af665835aabfdc6740c7e2c3791a31c3cdc9f5ab962f681b12fc092816a62f27d86025599a41233848702f0cfc0437b445682df51147a632a0a083d2d38b5e13e466a8935afff58bb533b3ef5d27fba63ee6b0fd9e67ff20af9d50deee3f8bf065ec220c1fd4ba57e341261d55997f85d66d32152526736872693d2b437a233e2337b715f6ac9a6a272622fdc2d67fcfe1da3459f8dab4ed7e40a657a54c36766c5e8ac9a88b35b05c34747e6507f6b044ab66180dc76ac1a696de03189593fedc0d0dbbd855c8ead673544899b0960e4a5a7ca43b4ef90afe607de7698caefdc242788f654b57a4fb32a71b335ef6ff9a4cc118b282b53bdd6d6192b7a82c3c5126b9c7e33c8e5a5ac9738b8bd31247fb7402054f97b573e8abb9faad219f4fd085aceaa7f542d787ee4196d365f3cc566e7bbcfbfd451230c48d804c017d21e2d8fa914e2559bb72bf0ab78c8ab92f00ef0d0d576eccdd486b64138a4172674857e543d1d5b639058dd908186597e366ad5f3d9c7ceaff44d04d1550b8d33abc751df07437834ba5acb32328a396994aebb3c40f759c2d6d7a3cb5377e55d5d218ef5a296dda8ddc355f3f50c3d0b660a51dfa4d98a6a5a33564556cf83c1373a814641d6a1dcef97b883fee61bb84fe60a3409340217e629cc7e4dcc93b85d8820921ff5826148b60e6939acd7838e1d7f20562bff8ee4b5ec4a05ad997a57b9796fdcb2eda87883c2640b072b140b946bfdf6575cacc066fdae04f6951e63624cbd316a677cad529bbe4e97b9144e4bc06c4afd1de55dd3e1175f90423847a230d34dfb71ed56f2965a7f6c72e6aa33c24c303fd67745d632656c5ef90bec80f4f5d1daa251988826cef375c81c36bf457e09687056f924677cb0bccf98dff81e014ce25f2d132497923e267363963cdf4302c5049d63131dc03fd95f65d8b6aa5934f817252c028c90f56d413b9d5d10d89790707dae2fabb249f649929927c21dd71e3f656826de5451c5da375aadecbd59d5ebf3a31fae65ac1b316a1611f1b276b26530f58d7247df459ce1f86db1d734f6f811932f042cee45d0e455306d01081bc3384f82c5fb2aacaa19d89cdfa46cc916eac61121475ba2e6191b4feecbe1789717021a158ace5d06744b40f551076b67cd63af60007f8c99876e1424883a45ec49d497ddaf808a5521ca74a999ab0b3c7aa9c80f85e93977ec61ce68b20307a1a81f71ca645b568fcd319ccbb5f651e87b707d37c39e15f945ea69e2f7c7d2ccc85b7e654c07e96f0636ae4044fe0e38590b431795ad0f8647bdd613713ada493cc17efd313206380e6a685b8198475bbd021c6e9d94daab2214947127506073e44d5408ba166c512a0b86805d07f5a44d3c41706be2bc15e712e55805248b92e8677d90f6d284d1d6ffaff2c430657042a0e82624fa3717b06cc0a6fd12230ea586dae83019fb9e06034ed2803c98d554b93c9a52348cafff75c40174a91f9ae6b8647854a156029f0b88b83316663ce574a4978277bb6bb27a31085634b6ec78864b6d8201c7e93903d75815067e378289a3d072ae172dafa6a452470f8d645bebfad9779594fc0784bb764a22e3a8181d93db7bf97893c414217a618ccb14caa9e92e8c61673afc9583662e812adba1f87a9c68202d60e909efab43c42c0cb00695fc7f1ffe67c75ca894c3c51e1e5e731360199e600f6ced9a87b2a6a87e70bf251bb5075ab222138288164b2eda727515ea7de12e2496d4fe42ea8d1a120c03cf9c50622c2afe4acb0dad98fd62d07ab4e828a94495f6d1ab973982c7ccbe6c1fae02788e4422ae22282fa49cbdb04ba54a7a238c6fc41187451383460762c06d1c8a72b9cd718866ad4b689e10c9a8c38fe5ef045bd785b01e980fc82c7e3532ce81876b778dd9f1ceeba4478e86411fb6fdd790683916ca832592485093644e8760cd7b4c01dba1ccc82b661bf13f0e3f34acd6b88";
/// @notice Gets merkle root hash of drive with a replacement
/// @param _position position of _drive
/// @param _logSizeOfReplacement log2 of size the replacement
/// @param _logSizeOfFullDrive log2 of size the full drive, which can be the entire machine
/// @param _replacement hash of the replacement
/// @param siblings of replacement that merkle root can be calculated
function getRootAfterReplacementInDrive(
uint256 _position,
uint256 _logSizeOfReplacement,
uint256 _logSizeOfFullDrive,
bytes32 _replacement,
bytes32[] calldata siblings
) public pure returns (bytes32) {
require(
_logSizeOfFullDrive >= _logSizeOfReplacement && _logSizeOfReplacement >= 3 && _logSizeOfFullDrive <= 64,
"3 <= logSizeOfReplacement <= logSizeOfFullDrive <= 64"
);
uint256 size = 1 << _logSizeOfReplacement;
require(((size - 1) & _position) == 0, "Position is not aligned");
require(siblings.length == _logSizeOfFullDrive - _logSizeOfReplacement, "Proof length does not match");
for (uint256 i; i < siblings.length; i++) {
if ((_position & (size << i)) == 0) {
_replacement = keccak256(abi.encodePacked(_replacement, siblings[i]));
} else {
_replacement = keccak256(abi.encodePacked(siblings[i], _replacement));
}
}
return _replacement;
}
/// @notice Gets precomputed hash of zero in empty tree hashes
/// @param _index of hash wanted
/// @dev first index is keccak(0), second index is keccak(keccak(0), keccak(0))
function getEmptyTreeHashAtIndex(uint256 _index) public pure returns (bytes32) {
uint256 start = _index * 32;
require(EMPTY_TREE_SIZE >= start + 32, "index out of bounds");
bytes32 hashedZeros;
bytes memory zeroTree = EMPTY_TREE_HASHES;
// first word is length, then skip index words
assembly {
hashedZeros := mload(add(add(zeroTree, 0x20), start))
}
return hashedZeros;
}
/// @notice get merkle root of generic array of bytes
/// @param _data array of bytes to be merklelized
/// @param _log2Size log2 of total size of the drive
/// @dev _data is padded with zeroes until is multiple of 8
/// @dev root is completed with zero tree until log2size is complete
/// @dev hashes are taken word by word (8 bytes by 8 bytes)
function getMerkleRootFromBytes(bytes calldata _data, uint256 _log2Size) public pure returns (bytes32) {
require(_log2Size >= 3 && _log2Size <= 64, "range of log2Size: [3,64]");
// if _data is empty return pristine drive of size log2size
if (_data.length == 0) return getEmptyTreeHashAtIndex(_log2Size - 3);
// total size of the drive in words
uint256 size = 1 << (_log2Size - 3);
require(size << L_WORD_SIZE >= _data.length, "data is bigger than drive");
// the stack depth is log2(_data.length / 8) + 2
uint256 stack_depth = 2 + ((_data.length) >> L_WORD_SIZE).getLog2Floor();
bytes32[] memory stack = new bytes32[](stack_depth);
uint256 numOfHashes; // total number of hashes on stack (counting levels)
uint256 stackLength; // total length of stack
uint256 numOfJoins; // number of hashes of the same level on stack
uint256 topStackLevel; // hash level of the top of the stack
while (numOfHashes < size) {
if ((numOfHashes << L_WORD_SIZE) < _data.length) {
// we still have words to hash
stack[stackLength] = getHashOfWordAtIndex(_data, numOfHashes);
numOfHashes++;
numOfJoins = numOfHashes;
} else {
// since padding happens in hashOfWordAtIndex function
// we only need to complete the stack with pre-computed
// hash(0), hash(hash(0),hash(0)) and so on
topStackLevel = numOfHashes.ctz();
stack[stackLength] = getEmptyTreeHashAtIndex(topStackLevel);
//Empty Tree Hash summarizes many hashes
numOfHashes = numOfHashes + (1 << topStackLevel);
numOfJoins = numOfHashes >> topStackLevel;
}
stackLength++;
// while there are joins, hash top of stack together
while (numOfJoins & 1 == 0) {
bytes32 h2 = stack[stackLength - 1];
bytes32 h1 = stack[stackLength - 2];
stack[stackLength - 2] = keccak256(abi.encodePacked(h1, h2));
stackLength = stackLength - 1; // remove hashes from stack
numOfJoins = numOfJoins >> 1;
}
}
require(stackLength == 1, "stack error");
return stack[0];
}
/// @notice Get the hash of a word in an array of bytes
/// @param _data array of bytes
/// @param _wordIndex index of word inside the bytes to get the hash of
/// @dev if word is incomplete (< 8 bytes) it gets padded with zeroes
function getHashOfWordAtIndex(bytes calldata _data, uint256 _wordIndex) public pure returns (bytes32) {
uint256 start = _wordIndex << L_WORD_SIZE;
uint256 end = start + (1 << L_WORD_SIZE);
// TODO: in .lua this just returns zero, but this might be more consistent
require(start <= _data.length, "word out of bounds");
if (end <= _data.length) {
return keccak256(abi.encodePacked(_data[start:end]));
}
// word is incomplete
// fill paddedSlice with incomplete words - the rest is going to be bytes(0)
bytes memory paddedSlice = new bytes(8);
uint256 remaining = _data.length - start;
for (uint256 i; i < remaining; i++) {
paddedSlice[i] = _data[start + i];
}
return keccak256(paddedSlice);
}
/// @notice Calculate the root of Merkle tree from an array of power of 2 elements
/// @param hashes The array containing power of 2 elements
/// @return byte32 the root hash being calculated
function calculateRootFromPowerOfTwo(bytes32[] memory hashes) public pure returns (bytes32) {
// revert when the input is not of power of 2
require((hashes.length).isPowerOf2(), "array len not power of 2");
if (hashes.length == 1) {
return hashes[0];
} else {
bytes32[] memory newHashes = new bytes32[](hashes.length >> 1);
for (uint256 i; i < hashes.length; i += 2) {
newHashes[i >> 1] = keccak256(abi.encodePacked(hashes[i], hashes[i + 1]));
}
return calculateRootFromPowerOfTwo(newHashes);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^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() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(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");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev _Available since v3.1._
*/
interface IERC1155Receiver is IERC165 {
/**
* @dev Handles the receipt of a single ERC1155 token type. This function is
* called at the end of a `safeTransferFrom` after the balance has been updated.
*
* NOTE: To accept the transfer, this must return
* `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
* (i.e. 0xf23a6e61, or its own function selector).
*
* @param operator The address which initiated the transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param id The ID of the token being transferred
* @param value The amount of tokens being transferred
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
*/
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
) external returns (bytes4);
/**
* @dev Handles the receipt of a multiple ERC1155 token types. This function
* is called at the end of a `safeBatchTransferFrom` after the balances have
* been updated.
*
* NOTE: To accept the transfer(s), this must return
* `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
* (i.e. 0xbc197c81, or its own function selector).
*
* @param operator The address which initiated the batch transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param ids An array containing ids of each token being transferred (order and length must match values array)
* @param values An array containing amounts of each token being transferred (order and length must match ids array)
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
*/
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external returns (bytes4);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/utils/ERC1155Holder.sol)
pragma solidity ^0.8.0;
import "./ERC1155Receiver.sol";
/**
* Simple implementation of `ERC1155Receiver` that will allow a contract to hold ERC1155 tokens.
*
* IMPORTANT: When inheriting this contract, you must include a way to use the received tokens, otherwise they will be
* stuck.
*
* @dev _Available since v3.1._
*/
contract ERC1155Holder is ERC1155Receiver {
function onERC1155Received(
address,
address,
uint256,
uint256,
bytes memory
) public virtual override returns (bytes4) {
return this.onERC1155Received.selector;
}
function onERC1155BatchReceived(
address,
address,
uint256[] memory,
uint256[] memory,
bytes memory
) public virtual override returns (bytes4) {
return this.onERC1155BatchReceived.selector;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC1155/utils/ERC1155Receiver.sol)
pragma solidity ^0.8.0;
import "../IERC1155Receiver.sol";
import "../../../utils/introspection/ERC165.sol";
/**
* @dev _Available since v3.1._
*/
abstract contract ERC1155Receiver is ERC165, IERC1155Receiver {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)
pragma solidity ^0.8.0;
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/
interface IERC721Receiver {
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
*
* The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/utils/ERC721Holder.sol)
pragma solidity ^0.8.0;
import "../IERC721Receiver.sol";
/**
* @dev Implementation of the {IERC721Receiver} interface.
*
* Accepts all token transfers.
* Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or {IERC721-setApprovalForAll}.
*/
contract ERC721Holder is IERC721Receiver {
/**
* @dev See {IERC721Receiver-onERC721Received}.
*
* Always returns `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(address, address, uint256, bytes memory) public virtual override returns (bytes4) {
return this.onERC721Received.selector;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^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.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^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}.
*/
interface IERC165 {
/**
* @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.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// (c) Cartesi and individual authors (see AUTHORS)
// SPDX-License-Identifier: Apache-2.0 (see LICENSE)
pragma solidity ^0.8.8;
/// @title Canonical Machine Constants Library
///
/// @notice Defines several constants related to the reference implementation
/// of the RISC-V machine that runs Linux, also known as the "Cartesi Machine".
library CanonicalMachine {
/// @notice Base-2 logarithm of number of bytes.
type Log2Size is uint64;
/// @notice Machine word size (8 bytes).
Log2Size constant WORD_LOG2_SIZE = Log2Size.wrap(3);
/// @notice Machine address space size (2^64 bytes).
Log2Size constant MACHINE_LOG2_SIZE = Log2Size.wrap(64);
/// @notice Keccak-256 output size (32 bytes).
Log2Size constant KECCAK_LOG2_SIZE = Log2Size.wrap(5);
/// @notice Maximum input size (~2 megabytes).
/// @dev The offset and size fields use up the extra 64 bytes.
uint256 constant INPUT_MAX_SIZE = (1 << 21) - 64;
/// @notice Maximum voucher metadata memory range (2 megabytes).
Log2Size constant VOUCHER_METADATA_LOG2_SIZE = Log2Size.wrap(21);
/// @notice Maximum notice metadata memory range (2 megabytes).
Log2Size constant NOTICE_METADATA_LOG2_SIZE = Log2Size.wrap(21);
/// @notice Maximum epoch voucher memory range (128 megabytes).
Log2Size constant EPOCH_VOUCHER_LOG2_SIZE = Log2Size.wrap(37);
/// @notice Maximum epoch notice memory range (128 megabytes).
Log2Size constant EPOCH_NOTICE_LOG2_SIZE = Log2Size.wrap(37);
/// @notice Unwrap `s` into its underlying uint64 value.
/// @param s Base-2 logarithm of some number of bytes
function uint64OfSize(Log2Size s) internal pure returns (uint64) {
return Log2Size.unwrap(s);
}
/// @notice Return the position of an intra memory range on a memory range
/// with contents with the same size.
/// @param index Index of intra memory range
/// @param log2Size Base-2 logarithm of intra memory range size
function getIntraMemoryRangePosition(
uint64 index,
Log2Size log2Size
) internal pure returns (uint64) {
return index << Log2Size.unwrap(log2Size);
}
}// (c) Cartesi and individual authors (see AUTHORS)
// SPDX-License-Identifier: Apache-2.0 (see LICENSE)
pragma solidity ^0.8.8;
/// @title Output Encoding Library
///
/// @notice Defines the encoding of outputs generated by the off-chain machine.
library OutputEncoding {
/// @notice Encode a notice.
/// @param notice The notice
/// @return The encoded output
function encodeNotice(
bytes calldata notice
) internal pure returns (bytes memory) {
return abi.encode(notice);
}
/// @notice Encode a voucher.
/// @param destination The address that will receive the payload through a message call
/// @param payload The payload, which—in the case of Solidity contracts—encodes a function call
/// @return The encoded output
function encodeVoucher(
address destination,
bytes calldata payload
) internal pure returns (bytes memory) {
return abi.encode(destination, payload);
}
}// (c) Cartesi and individual authors (see AUTHORS)
// SPDX-License-Identifier: Apache-2.0 (see LICENSE)
pragma solidity ^0.8.8;
/// @title Consensus interface
///
/// @notice This contract defines a generic interface for consensuses.
/// We use the word "consensus" to designate a contract that provides claims
/// in the base layer regarding the state of off-chain machines running in
/// the execution layer. How this contract is able to reach consensus, who is
/// able to submit claims, and how are claims stored in the base layer are
/// some of the implementation details left unspecified by this interface.
///
/// From the point of view of a DApp, these claims are necessary to validate
/// on-chain action allowed by the off-chain machine in the form of vouchers
/// and notices. Each claim is composed of three parts: an epoch hash, a first
/// index, and a last index. We'll explain each of these parts below.
///
/// First, let us define the word "epoch". For finality reasons, we need to
/// divide the stream of inputs being fed into the off-chain machine into
/// batches of inputs, which we call "epoches". At the end of every epoch,
/// we summarize the state of the off-chain machine in a single hash, called
/// "epoch hash". Please note that this interface does not define how this
/// stream of inputs is being chopped up into epoches.
///
/// The other two parts are simply the indices of the first and last inputs
/// accepted during the epoch. Logically, the first index MUST BE less than
/// or equal to the last index. As a result, every epoch MUST accept at least
/// one input. This assumption stems from the fact that the state of a machine
/// can only change after an input is fed into it.
///
/// Examples of possible implementations of this interface include:
///
/// * An authority consensus, controlled by a single address who has full
/// control over epoch boundaries, claim submission, asset management, etc.
///
/// * A quorum consensus, controlled by a limited set of validators, that
/// vote on the state of the machine at the end of every epoch. Also, epoch
/// boundaries are determined by the timestamp in the base layer, and assets
/// are split equally amongst the validators.
///
/// * An NxN consensus, which allows anyone to submit and dispute claims
/// in the base layer. Epoch boundaries are determined in the same fashion
/// as in the quorum example.
///
interface IConsensus {
/// @notice An application has joined the consensus' validation set.
/// @param application The application
/// @dev MUST be triggered on a successful call to `join`.
event ApplicationJoined(address application);
/// @notice Get a specific claim regarding a specific DApp.
/// The encoding of `_proofContext` might vary
/// depending on the implementation.
/// @param _dapp The DApp address
/// @param _proofContext Data for retrieving the desired claim
/// @return epochHash_ The claimed epoch hash
/// @return firstInputIndex_ The index of the first input of the epoch in the input box
/// @return lastInputIndex_ The index of the last input of the epoch in the input box
function getClaim(
address _dapp,
bytes calldata _proofContext
)
external
view
returns (
bytes32 epochHash_,
uint256 firstInputIndex_,
uint256 lastInputIndex_
);
/// @notice Signal the consensus that the message sender wants to join its validation set.
/// @dev MUST fire an `ApplicationJoined` event with the message sender as argument.
function join() external;
}// (c) Cartesi and individual authors (see AUTHORS)
// SPDX-License-Identifier: Apache-2.0 (see LICENSE)
pragma solidity ^0.8.8;
import {IConsensus} from "../consensus/IConsensus.sol";
import {OutputValidityProof} from "../library/LibOutputValidation.sol";
/// @notice Data for validating outputs.
/// @param validity A validity proof for the output
/// @param context Data for querying the right claim from the current consensus contract
/// @dev The encoding of `context` might vary depending on the implementation of the consensus contract.
struct Proof {
OutputValidityProof validity;
bytes context;
}
/// @title Cartesi DApp interface
interface ICartesiDApp {
// Events
/// @notice The DApp has migrated to another consensus contract.
/// @param newConsensus The new consensus contract
/// @dev MUST be triggered on a successful call to `migrateToConsensus`.
event NewConsensus(IConsensus newConsensus);
/// @notice A voucher was executed from the DApp.
/// @param voucherId A number that uniquely identifies the voucher
/// amongst all vouchers emitted by this DApp
event VoucherExecuted(uint256 voucherId);
// Permissioned functions
/// @notice Migrate the DApp to a new consensus.
/// @param _newConsensus The new consensus
/// @dev Can only be called by the DApp owner.
function migrateToConsensus(IConsensus _newConsensus) external;
// Permissionless functions
/// @notice Try to execute a voucher.
///
/// Reverts if voucher was already successfully executed.
///
/// @param _destination The address that will receive the payload through a message call
/// @param _payload The payload, which—in the case of Solidity contracts—encodes a function call
/// @param _proof The proof used to validate the voucher against
/// a claim submitted by the current consensus contract
/// @return Whether the execution was successful or not
/// @dev On a successful execution, emits a `VoucherExecuted` event.
/// Execution of already executed voucher will raise a `VoucherReexecutionNotAllowed` error.
function executeVoucher(
address _destination,
bytes calldata _payload,
Proof calldata _proof
) external returns (bool);
/// @notice Check whether a voucher has been executed.
/// @param _inputIndex The index of the input in the input box
/// @param _outputIndexWithinInput The index of output emitted by the input
/// @return Whether the voucher has been executed before
function wasVoucherExecuted(
uint256 _inputIndex,
uint256 _outputIndexWithinInput
) external view returns (bool);
/// @notice Validate a notice.
/// @param _notice The notice
/// @param _proof Data for validating outputs
/// @return Whether the notice is valid or not
function validateNotice(
bytes calldata _notice,
Proof calldata _proof
) external view returns (bool);
/// @notice Get the DApp's template hash.
/// @return The DApp's template hash
function getTemplateHash() external view returns (bytes32);
/// @notice Get the current consensus.
/// @return The current consensus
function getConsensus() external view returns (IConsensus);
}// (c) Cartesi and individual authors (see AUTHORS)
// SPDX-License-Identifier: Apache-2.0 (see LICENSE)
pragma solidity ^0.8.8;
import {CanonicalMachine} from "../common/CanonicalMachine.sol";
import {MerkleV2} from "@cartesi/util/contracts/MerkleV2.sol";
import {OutputEncoding} from "../common/OutputEncoding.sol";
/// @param inputIndexWithinEpoch Which input, inside the epoch, the output belongs to
/// @param outputIndexWithinInput Index of output emitted by the input
/// @param outputHashesRootHash Merkle root of hashes of outputs emitted by the input
/// @param vouchersEpochRootHash Merkle root of all epoch's voucher metadata hashes
/// @param noticesEpochRootHash Merkle root of all epoch's notice metadata hashes
/// @param machineStateHash Hash of the machine state claimed this epoch
/// @param outputHashInOutputHashesSiblings Proof that this output metadata is in metadata memory range
/// @param outputHashesInEpochSiblings Proof that this output metadata is in epoch's output memory range
struct OutputValidityProof {
uint64 inputIndexWithinEpoch;
uint64 outputIndexWithinInput;
bytes32 outputHashesRootHash;
bytes32 vouchersEpochRootHash;
bytes32 noticesEpochRootHash;
bytes32 machineStateHash;
bytes32[] outputHashInOutputHashesSiblings;
bytes32[] outputHashesInEpochSiblings;
}
/// @title Output Validation Library
library LibOutputValidation {
using CanonicalMachine for CanonicalMachine.Log2Size;
/// @notice Raised when some `OutputValidityProof` variables does not match
/// the presented finalized epoch.
error IncorrectEpochHash();
/// @notice Raised when `OutputValidityProof` metadata memory range is NOT
/// contained in epoch's output memory range.
error IncorrectOutputsEpochRootHash();
/// @notice Raised when Merkle root of output hash is NOT contained
/// in the output metadata array memory range.
error IncorrectOutputHashesRootHash();
/// @notice Raised when epoch input index is NOT compatible with the
/// provided input index range.
error InputIndexOutOfClaimBounds();
/// @notice Make sure the output proof is valid, otherwise revert.
/// @param v The output validity proof
/// @param encodedOutput The encoded output
/// @param epochHash The hash of the epoch in which the output was generated
/// @param outputsEpochRootHash Either `v.vouchersEpochRootHash` (for vouchers)
/// or `v.noticesEpochRootHash` (for notices)
/// @param outputEpochLog2Size Either `EPOCH_VOUCHER_LOG2_SIZE` (for vouchers)
/// or `EPOCH_NOTICE_LOG2_SIZE` (for notices)
/// @param outputHashesLog2Size Either `VOUCHER_METADATA_LOG2_SIZE` (for vouchers)
/// or `NOTICE_METADATA_LOG2_SIZE` (for notices)
function validateEncodedOutput(
OutputValidityProof calldata v,
bytes memory encodedOutput,
bytes32 epochHash,
bytes32 outputsEpochRootHash,
uint256 outputEpochLog2Size,
uint256 outputHashesLog2Size
) internal pure {
// prove that outputs hash is represented in a finalized epoch
if (
keccak256(
abi.encodePacked(
v.vouchersEpochRootHash,
v.noticesEpochRootHash,
v.machineStateHash
)
) != epochHash
) {
revert IncorrectEpochHash();
}
// prove that output metadata memory range is contained in epoch's output memory range
if (
MerkleV2.getRootAfterReplacementInDrive(
CanonicalMachine.getIntraMemoryRangePosition(
v.inputIndexWithinEpoch,
CanonicalMachine.KECCAK_LOG2_SIZE
),
CanonicalMachine.KECCAK_LOG2_SIZE.uint64OfSize(),
outputEpochLog2Size,
v.outputHashesRootHash,
v.outputHashesInEpochSiblings
) != outputsEpochRootHash
) {
revert IncorrectOutputsEpochRootHash();
}
// The hash of the output is converted to bytes (abi.encode) and
// treated as data. The metadata output memory range stores that data while
// being indifferent to its contents. To prove that the received
// output is contained in the metadata output memory range we need to
// prove that x, where:
// x = keccak(
// keccak(
// keccak(hashOfOutput[0:7]),
// keccak(hashOfOutput[8:15])
// ),
// keccak(
// keccak(hashOfOutput[16:23]),
// keccak(hashOfOutput[24:31])
// )
// )
// is contained in it. We can't simply use hashOfOutput because the
// log2size of the leaf is three (8 bytes) not five (32 bytes)
bytes32 merkleRootOfHashOfOutput = MerkleV2.getMerkleRootFromBytes(
abi.encodePacked(keccak256(encodedOutput)),
CanonicalMachine.KECCAK_LOG2_SIZE.uint64OfSize()
);
// prove that Merkle root of bytes(hashOfOutput) is contained
// in the output metadata array memory range
if (
MerkleV2.getRootAfterReplacementInDrive(
CanonicalMachine.getIntraMemoryRangePosition(
v.outputIndexWithinInput,
CanonicalMachine.KECCAK_LOG2_SIZE
),
CanonicalMachine.KECCAK_LOG2_SIZE.uint64OfSize(),
outputHashesLog2Size,
merkleRootOfHashOfOutput,
v.outputHashInOutputHashesSiblings
) != v.outputHashesRootHash
) {
revert IncorrectOutputHashesRootHash();
}
}
/// @notice Make sure the output proof is valid, otherwise revert.
/// @param v The output validity proof
/// @param destination The address that will receive the payload through a message call
/// @param payload The payload, which—in the case of Solidity contracts—encodes a function call
/// @param epochHash The hash of the epoch in which the output was generated
function validateVoucher(
OutputValidityProof calldata v,
address destination,
bytes calldata payload,
bytes32 epochHash
) internal pure {
bytes memory encodedVoucher = OutputEncoding.encodeVoucher(
destination,
payload
);
validateEncodedOutput(
v,
encodedVoucher,
epochHash,
v.vouchersEpochRootHash,
CanonicalMachine.EPOCH_VOUCHER_LOG2_SIZE.uint64OfSize(),
CanonicalMachine.VOUCHER_METADATA_LOG2_SIZE.uint64OfSize()
);
}
/// @notice Make sure the output proof is valid, otherwise revert.
/// @param v The output validity proof
/// @param notice The notice
/// @param epochHash The hash of the epoch in which the output was generated
function validateNotice(
OutputValidityProof calldata v,
bytes calldata notice,
bytes32 epochHash
) internal pure {
bytes memory encodedNotice = OutputEncoding.encodeNotice(notice);
validateEncodedOutput(
v,
encodedNotice,
epochHash,
v.noticesEpochRootHash,
CanonicalMachine.EPOCH_NOTICE_LOG2_SIZE.uint64OfSize(),
CanonicalMachine.NOTICE_METADATA_LOG2_SIZE.uint64OfSize()
);
}
/// @notice Get the position of a voucher on the bit mask.
/// @param voucher The index of voucher from those generated by such input
/// @param input The index of the input in the DApp's input box
/// @return Position of the voucher on the bit mask
function getBitMaskPosition(
uint256 voucher,
uint256 input
) internal pure returns (uint256) {
// voucher * 2 ** 128 + input
// this shouldn't overflow because it is impossible to have > 2**128 vouchers
// and because we are assuming there will be < 2 ** 128 inputs on the input box
return (((voucher << 128) | input));
}
/// @notice Validate input index range and get the input index.
/// @param v The output validity proof
/// @param firstInputIndex The index of the first input of the epoch in the input box
/// @param lastInputIndex The index of the last input of the epoch in the input box
/// @return The index of the input in the DApp's input box
/// @dev Reverts if epoch input index is not compatible with the provided input index range.
function validateInputIndexRange(
OutputValidityProof calldata v,
uint256 firstInputIndex,
uint256 lastInputIndex
) internal pure returns (uint256) {
uint256 inputIndex = firstInputIndex + v.inputIndexWithinEpoch;
if (inputIndex > lastInputIndex) {
revert InputIndexOutOfClaimBounds();
}
return inputIndex;
}
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"metadata": {
"useLiteralContent": true
},
"libraries": {
"@cartesi/util/contracts/Bitmask.sol": {
"Bitmask": "0xf5b2d8c81cde4d6238bbf20d3d77db37df13f735"
},
"@cartesi/util/contracts/MerkleV2.sol": {
"MerkleV2": "0x33436035441927df1a73fe3aac5906854632e53d"
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract IConsensus","name":"_consensus","type":"address"},{"internalType":"address","name":"_owner","type":"address"},{"internalType":"bytes32","name":"_templateHash","type":"bytes32"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"EtherTransferFailed","type":"error"},{"inputs":[],"name":"IncorrectEpochHash","type":"error"},{"inputs":[],"name":"IncorrectOutputHashesRootHash","type":"error"},{"inputs":[],"name":"IncorrectOutputsEpochRootHash","type":"error"},{"inputs":[],"name":"InputIndexOutOfClaimBounds","type":"error"},{"inputs":[],"name":"OnlyDApp","type":"error"},{"inputs":[],"name":"VoucherReexecutionNotAllowed","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IConsensus","name":"newConsensus","type":"address"}],"name":"NewConsensus","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"voucherId","type":"uint256"}],"name":"VoucherExecuted","type":"event"},{"inputs":[{"internalType":"address","name":"_destination","type":"address"},{"internalType":"bytes","name":"_payload","type":"bytes"},{"components":[{"components":[{"internalType":"uint64","name":"inputIndexWithinEpoch","type":"uint64"},{"internalType":"uint64","name":"outputIndexWithinInput","type":"uint64"},{"internalType":"bytes32","name":"outputHashesRootHash","type":"bytes32"},{"internalType":"bytes32","name":"vouchersEpochRootHash","type":"bytes32"},{"internalType":"bytes32","name":"noticesEpochRootHash","type":"bytes32"},{"internalType":"bytes32","name":"machineStateHash","type":"bytes32"},{"internalType":"bytes32[]","name":"outputHashInOutputHashesSiblings","type":"bytes32[]"},{"internalType":"bytes32[]","name":"outputHashesInEpochSiblings","type":"bytes32[]"}],"internalType":"struct OutputValidityProof","name":"validity","type":"tuple"},{"internalType":"bytes","name":"context","type":"bytes"}],"internalType":"struct Proof","name":"_proof","type":"tuple"}],"name":"executeVoucher","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getConsensus","outputs":[{"internalType":"contract IConsensus","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTemplateHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IConsensus","name":"_newConsensus","type":"address"}],"name":"migrateToConsensus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","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":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_notice","type":"bytes"},{"components":[{"components":[{"internalType":"uint64","name":"inputIndexWithinEpoch","type":"uint64"},{"internalType":"uint64","name":"outputIndexWithinInput","type":"uint64"},{"internalType":"bytes32","name":"outputHashesRootHash","type":"bytes32"},{"internalType":"bytes32","name":"vouchersEpochRootHash","type":"bytes32"},{"internalType":"bytes32","name":"noticesEpochRootHash","type":"bytes32"},{"internalType":"bytes32","name":"machineStateHash","type":"bytes32"},{"internalType":"bytes32[]","name":"outputHashInOutputHashesSiblings","type":"bytes32[]"},{"internalType":"bytes32[]","name":"outputHashesInEpochSiblings","type":"bytes32[]"}],"internalType":"struct OutputValidityProof","name":"validity","type":"tuple"},{"internalType":"bytes","name":"context","type":"bytes"}],"internalType":"struct Proof","name":"_proof","type":"tuple"}],"name":"validateNotice","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_inputIndex","type":"uint256"},{"internalType":"uint256","name":"_outputIndexWithinInput","type":"uint256"}],"name":"wasVoucherExecuted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"withdrawEther","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60a06040523480156200001157600080fd5b506040516200171038038062001710833981016040819052620000349162000212565b6200003f33620000cb565b600180556200004e826200011b565b6080819052600380546001600160a01b0319166001600160a01b0385169081179091556040805163b688a36360e01b8152905163b688a3639160048082019260009290919082900301818387803b158015620000a957600080fd5b505af1158015620000be573d6000803e3d6000fd5b505050505050506200025a565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b620001256200019e565b6001600160a01b038116620001905760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b6200019b81620000cb565b50565b6000546001600160a01b03163314620001fa5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640162000187565b565b6001600160a01b03811681146200019b57600080fd5b6000806000606084860312156200022857600080fd5b83516200023581620001fc565b60208501519093506200024881620001fc565b80925050604084015190509250925092565b60805161149a6200027660003960006101ec015261149a6000f3fe6080604052600436106100e15760003560e01c80638da5cb5b1161007f578063bc197c8111610059578063bc197c8114610288578063f23a6e61146102b4578063f2fde38b146102e0578063fc4116831461030057600080fd5b80638da5cb5b1461022a57806396487d46146102485780639d9b11451461026857600080fd5b8063179e740b116100bb578063179e740b14610186578063522f6815146101b857806361b12c66146101da578063715018a61461021557600080fd5b806301ffc9a7146100ed5780631250482f14610122578063150b7a021461014257600080fd5b366100e857005b600080fd5b3480156100f957600080fd5b5061010d610108366004610d2a565b610320565b60405190151581526020015b60405180910390f35b34801561012e57600080fd5b5061010d61013d366004610dd0565b610357565b34801561014e57600080fd5b5061016d61015d366004610f00565b630a85bd0160e11b949350505050565b6040516001600160e01b03199091168152602001610119565b34801561019257600080fd5b506003546001600160a01b03165b6040516001600160a01b039091168152602001610119565b3480156101c457600080fd5b506101d86101d3366004610f5f565b61053c565b005b3480156101e657600080fd5b506040517f00000000000000000000000000000000000000000000000000000000000000008152602001610119565b34801561022157600080fd5b506101d86105d5565b34801561023657600080fd5b506000546001600160a01b03166101a0565b34801561025457600080fd5b5061010d610263366004610f8b565b6105e9565b34801561027457600080fd5b5061010d610283366004610ff3565b61063a565b34801561029457600080fd5b5061016d6102a3366004611094565b63bc197c8160e01b95945050505050565b3480156102c057600080fd5b5061016d6102cf366004611141565b63f23a6e6160e01b95945050505050565b3480156102ec57600080fd5b506101d86102fb3660046111a9565b61064c565b34801561030c57600080fd5b506101d861031b3660046111a9565b6106ca565b60006001600160e01b03198216630271189760e51b148061035157506301ffc9a760e01b6001600160e01b03198316145b92915050565b600061036161077f565b600080808061037b61037660208801886111c6565b6107d8565b919550935091506103988383610391898061120c565b919061085f565b90506103b4898989876103ab8b8061120c565b939291906108a5565b60006103e86103c3888061120c565b6103d490604081019060200161122c565b6001600160401b03168360809190911b1790565b90506103f3816108da565b15610411576040516370de22b760e01b815260040160405180910390fd5b60008a6001600160a01b03168a8a60405161042d929190611255565b6000604051808303816000865af19150503d806000811461046a576040519150601f19603f3d011682016040523d82523d6000602084013e61046f565b606091505b505090508015610524576040516306449da160e41b815260026004820152602481018390526001604482015273f5b2d8c81cde4d6238bbf20d3d77db37df13f73590636449da109060640160006040518083038186803b1580156104d257600080fd5b505af41580156104e6573d6000803e3d6000fd5b505050507f0eb7ee080f865f1cadc4f54daf58cc3b8879e888832867d13351edcec0fbdc548260405161051b91815260200190565b60405180910390a15b9550505050505061053460018055565b949350505050565b33301461055c5760405163a08d601d60e01b815260040160405180910390fd5b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146105a9576040519150601f19603f3d011682016040523d82523d6000602084013e6105ae565b606091505b50509050806105d057604051630ce8f45160e31b815260040160405180910390fd5b505050565b6105dd610958565b6105e760006109b2565b565b60008080806105fe61037660208701876111c6565b919450925090506106148282610391888061120c565b5061062d878785610625898061120c565b929190610a02565b5060019695505050505050565b6000608082901b8317610534816108da565b610654610958565b6001600160a01b0381166106be5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b6106c7816109b2565b50565b6106d2610958565b600380546001600160a01b0319166001600160a01b0383169081179091556040805163b688a36360e01b8152905163b688a3639160048082019260009290919082900301818387803b15801561072757600080fd5b505af115801561073b573d6000803e3d6000fd5b50506040516001600160a01b03841681527f4991c6f37185659e276ff918a96f3e20e6c5abcd8c9aab450dc19c2f7ad35cb59250602001905060405180910390a150565b6002600154036107d15760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016106b5565b6002600155565b60035460405163035e6a0960e61b8152600091829182916001600160a01b03169063d79a8240906108119030908990899060040161128e565b606060405180830381865afa15801561082e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061085291906112bc565b9250925092509250925092565b60008061086f602086018661122c565b610882906001600160401b0316856112ea565b9050828111156105345760405163fd9ae91f60e01b815260040160405180910390fd5b60006108b2858585610a29565b90506108d2868284606083013560255b6001600160401b03166015610a58565b505050505050565b6040516303fbaf7360e01b8152600260048201526024810182905260009073f5b2d8c81cde4d6238bbf20d3d77db37df13f735906303fbaf7390604401602060405180830381865af4158015610934573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610351919061130b565b6000546001600160a01b031633146105e75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016106b5565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000610a0e8484610cfe565b9050610a22858284608083013560256108c2565b5050505050565b6060838383604051602001610a409392919061128e565b60405160208183030381529060405290509392505050565b6040805160608089013560208301526080808a01359383019390935260a0890135908201528591016040516020818303038152906040528051906020012014610ab457604051636fbd3b7160e11b815260040160405180910390fd5b827333436035441927df1a73fe3aac5906854632e53d6379de4601610af0610adf60208b018b61122c565b60051b681fffffffffffffffe01690565b60058660408c0135610b0560e08e018e61132d565b6040518763ffffffff1660e01b8152600401610b2696959493929190611376565b602060405180830381865af4158015610b43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b6791906113d9565b14610b8557604051634371daa160e11b815260040160405180910390fd5b60007333436035441927df1a73fe3aac5906854632e53d63c84583a18780519060200120604051602001610bbb91815260200190565b60408051601f19818403018152908290526001600160e01b031960e084901b168252610bec916005906004016113f2565b602060405180830381865af4158015610c09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c2d91906113d9565b905086604001357333436035441927df1a73fe3aac5906854632e53d6379de4601610c648a6020016020810190610adf919061122c565b60058686610c7560c08f018f61132d565b6040518763ffffffff1660e01b8152600401610c9696959493929190611376565b602060405180830381865af4158015610cb3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cd791906113d9565b14610cf55760405163017c689560e61b815260040160405180910390fd5b50505050505050565b60608282604051602001610d13929190611450565b604051602081830303815290604052905092915050565b600060208284031215610d3c57600080fd5b81356001600160e01b031981168114610d5457600080fd5b9392505050565b6001600160a01b03811681146106c757600080fd5b60008083601f840112610d8257600080fd5b5081356001600160401b03811115610d9957600080fd5b602083019150836020828501011115610db157600080fd5b9250929050565b600060408284031215610dca57600080fd5b50919050565b60008060008060608587031215610de657600080fd5b8435610df181610d5b565b935060208501356001600160401b0380821115610e0d57600080fd5b610e1988838901610d70565b90955093506040870135915080821115610e3257600080fd5b50610e3f87828801610db8565b91505092959194509250565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715610e8957610e89610e4b565b604052919050565b600082601f830112610ea257600080fd5b81356001600160401b03811115610ebb57610ebb610e4b565b610ece601f8201601f1916602001610e61565b818152846020838601011115610ee357600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215610f1657600080fd5b8435610f2181610d5b565b93506020850135610f3181610d5b565b92506040850135915060608501356001600160401b03811115610f5357600080fd5b610e3f87828801610e91565b60008060408385031215610f7257600080fd5b8235610f7d81610d5b565b946020939093013593505050565b600080600060408486031215610fa057600080fd5b83356001600160401b0380821115610fb757600080fd5b610fc387838801610d70565b90955093506020860135915080821115610fdc57600080fd5b50610fe986828701610db8565b9150509250925092565b6000806040838503121561100657600080fd5b50508035926020909101359150565b600082601f83011261102657600080fd5b813560206001600160401b0382111561104157611041610e4b565b8160051b611050828201610e61565b928352848101820192828101908785111561106a57600080fd5b83870192505b8483101561108957823582529183019190830190611070565b979650505050505050565b600080600080600060a086880312156110ac57600080fd5b85356110b781610d5b565b945060208601356110c781610d5b565b935060408601356001600160401b03808211156110e357600080fd5b6110ef89838a01611015565b9450606088013591508082111561110557600080fd5b61111189838a01611015565b9350608088013591508082111561112757600080fd5b5061113488828901610e91565b9150509295509295909350565b600080600080600060a0868803121561115957600080fd5b853561116481610d5b565b9450602086013561117481610d5b565b9350604086013592506060860135915060808601356001600160401b0381111561119d57600080fd5b61113488828901610e91565b6000602082840312156111bb57600080fd5b8135610d5481610d5b565b6000808335601e198436030181126111dd57600080fd5b8301803591506001600160401b038211156111f757600080fd5b602001915036819003821315610db157600080fd5b6000823560fe1983360301811261122257600080fd5b9190910192915050565b60006020828403121561123e57600080fd5b81356001600160401b0381168114610d5457600080fd5b8183823760009101908152919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6001600160a01b03841681526040602082018190526000906112b39083018486611265565b95945050505050565b6000806000606084860312156112d157600080fd5b8351925060208401519150604084015190509250925092565b8082018082111561035157634e487b7160e01b600052601160045260246000fd5b60006020828403121561131d57600080fd5b81518015158114610d5457600080fd5b6000808335601e1984360301811261134457600080fd5b8301803591506001600160401b0382111561135e57600080fd5b6020019150600581901b3603821315610db157600080fd5b6001600160401b03878116825286166020820152604081018590526060810184905260a060808201819052810182905260006001600160fb1b038311156113bc57600080fd5b8260051b808560c08501379190910160c001979650505050505050565b6000602082840312156113eb57600080fd5b5051919050565b604081526000835180604084015260005b818110156114205760208187018101516060868401015201611403565b506000606082850101526060601f19601f8301168401019150506001600160401b03831660208301529392505050565b60208152600061053460208301848661126556fea2646970667358221220981835fbbf44aedaeb41e0c0c9001ffe55187a0b5606db0cdbf7500fc7c5e30e64736f6c634300081300330000000000000000000000009db17b9426e6d3d517a969994e7addadbca9c45f0000000000000000000000000e28a8f88c6266df0fe274c15c1d4b27f8b373c064523866b6437fd593d8c0c65f88f59717f2eefa81422cc4921214423c819bf2
Deployed Bytecode
0x6080604052600436106100e15760003560e01c80638da5cb5b1161007f578063bc197c8111610059578063bc197c8114610288578063f23a6e61146102b4578063f2fde38b146102e0578063fc4116831461030057600080fd5b80638da5cb5b1461022a57806396487d46146102485780639d9b11451461026857600080fd5b8063179e740b116100bb578063179e740b14610186578063522f6815146101b857806361b12c66146101da578063715018a61461021557600080fd5b806301ffc9a7146100ed5780631250482f14610122578063150b7a021461014257600080fd5b366100e857005b600080fd5b3480156100f957600080fd5b5061010d610108366004610d2a565b610320565b60405190151581526020015b60405180910390f35b34801561012e57600080fd5b5061010d61013d366004610dd0565b610357565b34801561014e57600080fd5b5061016d61015d366004610f00565b630a85bd0160e11b949350505050565b6040516001600160e01b03199091168152602001610119565b34801561019257600080fd5b506003546001600160a01b03165b6040516001600160a01b039091168152602001610119565b3480156101c457600080fd5b506101d86101d3366004610f5f565b61053c565b005b3480156101e657600080fd5b506040517f64523866b6437fd593d8c0c65f88f59717f2eefa81422cc4921214423c819bf28152602001610119565b34801561022157600080fd5b506101d86105d5565b34801561023657600080fd5b506000546001600160a01b03166101a0565b34801561025457600080fd5b5061010d610263366004610f8b565b6105e9565b34801561027457600080fd5b5061010d610283366004610ff3565b61063a565b34801561029457600080fd5b5061016d6102a3366004611094565b63bc197c8160e01b95945050505050565b3480156102c057600080fd5b5061016d6102cf366004611141565b63f23a6e6160e01b95945050505050565b3480156102ec57600080fd5b506101d86102fb3660046111a9565b61064c565b34801561030c57600080fd5b506101d861031b3660046111a9565b6106ca565b60006001600160e01b03198216630271189760e51b148061035157506301ffc9a760e01b6001600160e01b03198316145b92915050565b600061036161077f565b600080808061037b61037660208801886111c6565b6107d8565b919550935091506103988383610391898061120c565b919061085f565b90506103b4898989876103ab8b8061120c565b939291906108a5565b60006103e86103c3888061120c565b6103d490604081019060200161122c565b6001600160401b03168360809190911b1790565b90506103f3816108da565b15610411576040516370de22b760e01b815260040160405180910390fd5b60008a6001600160a01b03168a8a60405161042d929190611255565b6000604051808303816000865af19150503d806000811461046a576040519150601f19603f3d011682016040523d82523d6000602084013e61046f565b606091505b505090508015610524576040516306449da160e41b815260026004820152602481018390526001604482015273f5b2d8c81cde4d6238bbf20d3d77db37df13f73590636449da109060640160006040518083038186803b1580156104d257600080fd5b505af41580156104e6573d6000803e3d6000fd5b505050507f0eb7ee080f865f1cadc4f54daf58cc3b8879e888832867d13351edcec0fbdc548260405161051b91815260200190565b60405180910390a15b9550505050505061053460018055565b949350505050565b33301461055c5760405163a08d601d60e01b815260040160405180910390fd5b6000826001600160a01b03168260405160006040518083038185875af1925050503d80600081146105a9576040519150601f19603f3d011682016040523d82523d6000602084013e6105ae565b606091505b50509050806105d057604051630ce8f45160e31b815260040160405180910390fd5b505050565b6105dd610958565b6105e760006109b2565b565b60008080806105fe61037660208701876111c6565b919450925090506106148282610391888061120c565b5061062d878785610625898061120c565b929190610a02565b5060019695505050505050565b6000608082901b8317610534816108da565b610654610958565b6001600160a01b0381166106be5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b6106c7816109b2565b50565b6106d2610958565b600380546001600160a01b0319166001600160a01b0383169081179091556040805163b688a36360e01b8152905163b688a3639160048082019260009290919082900301818387803b15801561072757600080fd5b505af115801561073b573d6000803e3d6000fd5b50506040516001600160a01b03841681527f4991c6f37185659e276ff918a96f3e20e6c5abcd8c9aab450dc19c2f7ad35cb59250602001905060405180910390a150565b6002600154036107d15760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016106b5565b6002600155565b60035460405163035e6a0960e61b8152600091829182916001600160a01b03169063d79a8240906108119030908990899060040161128e565b606060405180830381865afa15801561082e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061085291906112bc565b9250925092509250925092565b60008061086f602086018661122c565b610882906001600160401b0316856112ea565b9050828111156105345760405163fd9ae91f60e01b815260040160405180910390fd5b60006108b2858585610a29565b90506108d2868284606083013560255b6001600160401b03166015610a58565b505050505050565b6040516303fbaf7360e01b8152600260048201526024810182905260009073f5b2d8c81cde4d6238bbf20d3d77db37df13f735906303fbaf7390604401602060405180830381865af4158015610934573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610351919061130b565b6000546001600160a01b031633146105e75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016106b5565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000610a0e8484610cfe565b9050610a22858284608083013560256108c2565b5050505050565b6060838383604051602001610a409392919061128e565b60405160208183030381529060405290509392505050565b6040805160608089013560208301526080808a01359383019390935260a0890135908201528591016040516020818303038152906040528051906020012014610ab457604051636fbd3b7160e11b815260040160405180910390fd5b827333436035441927df1a73fe3aac5906854632e53d6379de4601610af0610adf60208b018b61122c565b60051b681fffffffffffffffe01690565b60058660408c0135610b0560e08e018e61132d565b6040518763ffffffff1660e01b8152600401610b2696959493929190611376565b602060405180830381865af4158015610b43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b6791906113d9565b14610b8557604051634371daa160e11b815260040160405180910390fd5b60007333436035441927df1a73fe3aac5906854632e53d63c84583a18780519060200120604051602001610bbb91815260200190565b60408051601f19818403018152908290526001600160e01b031960e084901b168252610bec916005906004016113f2565b602060405180830381865af4158015610c09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c2d91906113d9565b905086604001357333436035441927df1a73fe3aac5906854632e53d6379de4601610c648a6020016020810190610adf919061122c565b60058686610c7560c08f018f61132d565b6040518763ffffffff1660e01b8152600401610c9696959493929190611376565b602060405180830381865af4158015610cb3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cd791906113d9565b14610cf55760405163017c689560e61b815260040160405180910390fd5b50505050505050565b60608282604051602001610d13929190611450565b604051602081830303815290604052905092915050565b600060208284031215610d3c57600080fd5b81356001600160e01b031981168114610d5457600080fd5b9392505050565b6001600160a01b03811681146106c757600080fd5b60008083601f840112610d8257600080fd5b5081356001600160401b03811115610d9957600080fd5b602083019150836020828501011115610db157600080fd5b9250929050565b600060408284031215610dca57600080fd5b50919050565b60008060008060608587031215610de657600080fd5b8435610df181610d5b565b935060208501356001600160401b0380821115610e0d57600080fd5b610e1988838901610d70565b90955093506040870135915080821115610e3257600080fd5b50610e3f87828801610db8565b91505092959194509250565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715610e8957610e89610e4b565b604052919050565b600082601f830112610ea257600080fd5b81356001600160401b03811115610ebb57610ebb610e4b565b610ece601f8201601f1916602001610e61565b818152846020838601011115610ee357600080fd5b816020850160208301376000918101602001919091529392505050565b60008060008060808587031215610f1657600080fd5b8435610f2181610d5b565b93506020850135610f3181610d5b565b92506040850135915060608501356001600160401b03811115610f5357600080fd5b610e3f87828801610e91565b60008060408385031215610f7257600080fd5b8235610f7d81610d5b565b946020939093013593505050565b600080600060408486031215610fa057600080fd5b83356001600160401b0380821115610fb757600080fd5b610fc387838801610d70565b90955093506020860135915080821115610fdc57600080fd5b50610fe986828701610db8565b9150509250925092565b6000806040838503121561100657600080fd5b50508035926020909101359150565b600082601f83011261102657600080fd5b813560206001600160401b0382111561104157611041610e4b565b8160051b611050828201610e61565b928352848101820192828101908785111561106a57600080fd5b83870192505b8483101561108957823582529183019190830190611070565b979650505050505050565b600080600080600060a086880312156110ac57600080fd5b85356110b781610d5b565b945060208601356110c781610d5b565b935060408601356001600160401b03808211156110e357600080fd5b6110ef89838a01611015565b9450606088013591508082111561110557600080fd5b61111189838a01611015565b9350608088013591508082111561112757600080fd5b5061113488828901610e91565b9150509295509295909350565b600080600080600060a0868803121561115957600080fd5b853561116481610d5b565b9450602086013561117481610d5b565b9350604086013592506060860135915060808601356001600160401b0381111561119d57600080fd5b61113488828901610e91565b6000602082840312156111bb57600080fd5b8135610d5481610d5b565b6000808335601e198436030181126111dd57600080fd5b8301803591506001600160401b038211156111f757600080fd5b602001915036819003821315610db157600080fd5b6000823560fe1983360301811261122257600080fd5b9190910192915050565b60006020828403121561123e57600080fd5b81356001600160401b0381168114610d5457600080fd5b8183823760009101908152919050565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b6001600160a01b03841681526040602082018190526000906112b39083018486611265565b95945050505050565b6000806000606084860312156112d157600080fd5b8351925060208401519150604084015190509250925092565b8082018082111561035157634e487b7160e01b600052601160045260246000fd5b60006020828403121561131d57600080fd5b81518015158114610d5457600080fd5b6000808335601e1984360301811261134457600080fd5b8301803591506001600160401b0382111561135e57600080fd5b6020019150600581901b3603821315610db157600080fd5b6001600160401b03878116825286166020820152604081018590526060810184905260a060808201819052810182905260006001600160fb1b038311156113bc57600080fd5b8260051b808560c08501379190910160c001979650505050505050565b6000602082840312156113eb57600080fd5b5051919050565b604081526000835180604084015260005b818110156114205760208187018101516060868401015201611403565b506000606082850101526060601f19601f8301168401019150506001600160401b03831660208301529392505050565b60208152600061053460208301848661126556fea2646970667358221220981835fbbf44aedaeb41e0c0c9001ffe55187a0b5606db0cdbf7500fc7c5e30e64736f6c63430008130033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000009db17b9426e6d3d517a969994e7addadbca9c45f0000000000000000000000000e28a8f88c6266df0fe274c15c1d4b27f8b373c064523866b6437fd593d8c0c65f88f59717f2eefa81422cc4921214423c819bf2
-----Decoded View---------------
Arg [0] : _consensus (address): 0x9DB17B9426E6d3d517a969994E7ADDadbCa9C45f
Arg [1] : _owner (address): 0x0e28A8f88C6266dF0FE274c15c1d4b27f8B373C0
Arg [2] : _templateHash (bytes32): 0x64523866b6437fd593d8c0c65f88f59717f2eefa81422cc4921214423c819bf2
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000009db17b9426e6d3d517a969994e7addadbca9c45f
Arg [1] : 0000000000000000000000000e28a8f88c6266df0fe274c15c1d4b27f8b373c0
Arg [2] : 64523866b6437fd593d8c0c65f88f59717f2eefa81422cc4921214423c819bf2
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.