// SPDX-License-Identifier: MIXED
// _____ _ _ _____
// | __ (_) | | |_ _|
// | |__) |__ _____| | | | _ __ ___
// | ___/ \ \/ / _ \ | | | | '_ \ / __|
// | | | |> < __/ | _| |_| | | | (__
// |_| |_/_/\_\___|_| |_____|_| |_|\___| on Ethereum!
//
// Flung together by BoringCrypto during COVID-19 lockdown in 2021
// Project started on Polygon for 2 weeks and this is the migrated to Ethereum version
// The canvas starts where it left off on Polygon (as well as PIXEL balances and ambassador program info)
// This version has a lot of gas optimizations vs the Polygon one
// WARNING: No audits were done on this code...
// Stay safe!
// Get your alpha here https://bit.ly/3icxSru
// File @boringcrypto/boring-solidity/contracts/libraries/BoringMath.sol@v1.2.3
// License-Identifier: MIT
pragma solidity 0.6.12;
/// @notice A library for performing overflow-/underflow-safe math,
/// updated with awesomeness from of DappHub (https://github.com/dapphub/ds-math).
library BoringMath {
function add(uint256 a, uint256 b) internal pure returns (uint256 c) {
require((c = a + b) >= b, "BoringMath: Add Overflow");
}
function sub(uint256 a, uint256 b) internal pure returns (uint256 c) {
require((c = a - b) <= a, "BoringMath: Underflow");
}
function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
require(b == 0 || (c = a * b) / b == a, "BoringMath: Mul Overflow");
}
function to128(uint256 a) internal pure returns (uint128 c) {
require(a <= uint128(-1), "BoringMath: uint128 Overflow");
c = uint128(a);
}
function to64(uint256 a) internal pure returns (uint64 c) {
require(a <= uint64(-1), "BoringMath: uint64 Overflow");
c = uint64(a);
}
function to32(uint256 a) internal pure returns (uint32 c) {
require(a <= uint32(-1), "BoringMath: uint32 Overflow");
c = uint32(a);
}
}
/// @notice A library for performing overflow-/underflow-safe addition and subtraction on uint128.
library BoringMath128 {
function add(uint128 a, uint128 b) internal pure returns (uint128 c) {
require((c = a + b) >= b, "BoringMath: Add Overflow");
}
function sub(uint128 a, uint128 b) internal pure returns (uint128 c) {
require((c = a - b) <= a, "BoringMath: Underflow");
}
}
/// @notice A library for performing overflow-/underflow-safe addition and subtraction on uint64.
library BoringMath64 {
function add(uint64 a, uint64 b) internal pure returns (uint64 c) {
require((c = a + b) >= b, "BoringMath: Add Overflow");
}
function sub(uint64 a, uint64 b) internal pure returns (uint64 c) {
require((c = a - b) <= a, "BoringMath: Underflow");
}
}
/// @notice A library for performing overflow-/underflow-safe addition and subtraction on uint32.
library BoringMath32 {
function add(uint32 a, uint32 b) internal pure returns (uint32 c) {
require((c = a + b) >= b, "BoringMath: Add Overflow");
}
function sub(uint32 a, uint32 b) internal pure returns (uint32 c) {
require((c = a - b) <= a, "BoringMath: Underflow");
}
}
// File @boringcrypto/boring-solidity/contracts/interfaces/IERC20.sol@v1.2.3
// License-Identifier: MIT
pragma solidity 0.6.12;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
/// @notice EIP 2612
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
}
// File @boringcrypto/boring-solidity/contracts/libraries/BoringERC20.sol@v1.2.3
// License-Identifier: MIT
pragma solidity 0.6.12;
// solhint-disable avoid-low-level-calls
library BoringERC20 {
bytes4 private constant SIG_SYMBOL = 0x95d89b41; // symbol()
bytes4 private constant SIG_NAME = 0x06fdde03; // name()
bytes4 private constant SIG_DECIMALS = 0x313ce567; // decimals()
bytes4 private constant SIG_BALANCE_OF = 0x70a08231; // balanceOf(address)
bytes4 private constant SIG_TRANSFER = 0xa9059cbb; // transfer(address,uint256)
bytes4 private constant SIG_TRANSFER_FROM = 0x23b872dd; // transferFrom(address,address,uint256)
function returnDataToString(bytes memory data) internal pure returns (string memory) {
if (data.length >= 64) {
return abi.decode(data, (string));
} else if (data.length == 32) {
uint8 i = 0;
while(i < 32 && data[i] != 0) {
i++;
}
bytes memory bytesArray = new bytes(i);
for (i = 0; i < 32 && data[i] != 0; i++) {
bytesArray[i] = data[i];
}
return string(bytesArray);
} else {
return "???";
}
}
/// @notice Provides a safe ERC20.symbol version which returns '???' as fallback string.
/// @param token The address of the ERC-20 token contract.
/// @return (string) Token symbol.
function safeSymbol(IERC20 token) internal view returns (string memory) {
(bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(SIG_SYMBOL));
return success ? returnDataToString(data) : "???";
}
/// @notice Provides a safe ERC20.name version which returns '???' as fallback string.
/// @param token The address of the ERC-20 token contract.
/// @return (string) Token name.
function safeName(IERC20 token) internal view returns (string memory) {
(bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(SIG_NAME));
return success ? returnDataToString(data) : "???";
}
/// @notice Provides a safe ERC20.decimals version which returns '18' as fallback value.
/// @param token The address of the ERC-20 token contract.
/// @return (uint8) Token decimals.
function safeDecimals(IERC20 token) internal view returns (uint8) {
(bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(SIG_DECIMALS));
return success && data.length == 32 ? abi.decode(data, (uint8)) : 18;
}
/// @notice Provides a gas-optimized balance check to avoid a redundant extcodesize check in addition to the returndatasize check.
/// @param token The address of the ERC-20 token.
/// @param to The address of the user to check.
/// @return amount The token amount.
function safeBalanceOf(IERC20 token, address to) internal view returns (uint256 amount) {
(bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(SIG_BALANCE_OF, to));
require(success && data.length >= 32, "BoringERC20: BalanceOf failed");
amount = abi.decode(data, (uint256));
}
/// @notice Provides a safe ERC20.transfer version for different ERC-20 implementations.
/// Reverts on a failed transfer.
/// @param token The address of the ERC-20 token.
/// @param to Transfer tokens to.
/// @param amount The token amount.
function safeTransfer(
IERC20 token,
address to,
uint256 amount
) internal {
(bool success, bytes memory data) = address(token).call(abi.encodeWithSelector(SIG_TRANSFER, to, amount));
require(success && (data.length == 0 || abi.decode(data, (bool))), "BoringERC20: Transfer failed");
}
/// @notice Provides a safe ERC20.transferFrom version for different ERC-20 implementations.
/// Reverts on a failed transfer.
/// @param token The address of the ERC-20 token.
/// @param from Transfer tokens from.
/// @param to Transfer tokens to.
/// @param amount The token amount.
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 amount
) internal {
(bool success, bytes memory data) = address(token).call(abi.encodeWithSelector(SIG_TRANSFER_FROM, from, to, amount));
require(success && (data.length == 0 || abi.decode(data, (bool))), "BoringERC20: TransferFrom failed");
}
}
// File @boringcrypto/boring-solidity/contracts/BoringOwnable.sol@v1.2.3
// License-Identifier: MIT
pragma solidity 0.6.12;
// Audit on 5-Jan-2021 by Keno and BoringCrypto
// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol + Claimable.sol
// Edited by BoringCrypto
contract BoringOwnableData {
address public owner;
address public pendingOwner;
}
contract BoringOwnable is BoringOwnableData {
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/// @notice `owner` defaults to msg.sender on construction.
constructor() public {
owner = msg.sender;
emit OwnershipTransferred(address(0), msg.sender);
}
/// @notice Transfers ownership to `newOwner`. Either directly or claimable by the new pending owner.
/// Can only be invoked by the current `owner`.
/// @param newOwner Address of the new owner.
/// @param direct True if `newOwner` should be set immediately. False if `newOwner` needs to use `claimOwnership`.
/// @param renounce Allows the `newOwner` to be `address(0)` if `direct` and `renounce` is True. Has no effect otherwise.
function transferOwnership(
address newOwner,
bool direct,
bool renounce
) public onlyOwner {
if (direct) {
// Checks
require(newOwner != address(0) || renounce, "Ownable: zero address");
// Effects
emit OwnershipTransferred(owner, newOwner);
owner = newOwner;
pendingOwner = address(0);
} else {
// Effects
pendingOwner = newOwner;
}
}
/// @notice Needs to be called by `pendingOwner` to claim ownership.
function claimOwnership() public {
address _pendingOwner = pendingOwner;
// Checks
require(msg.sender == _pendingOwner, "Ownable: caller != pending owner");
// Effects
emit OwnershipTransferred(owner, _pendingOwner);
owner = _pendingOwner;
pendingOwner = address(0);
}
/// @notice Only allows the `owner` to execute the function.
modifier onlyOwner() {
require(msg.sender == owner, "Ownable: caller is not the owner");
_;
}
}
// File @boringcrypto/boring-solidity/contracts/Domain.sol@v1.2.3
// License-Identifier: MIT
// Based on code and smartness by Ross Campbell and Keno
// Uses immutable to store the domain separator to reduce gas usage
// If the chain id changes due to a fork, the forked chain will calculate on the fly.
pragma solidity 0.6.12;
// solhint-disable no-inline-assembly
contract Domain {
bytes32 private constant DOMAIN_SEPARATOR_SIGNATURE_HASH = keccak256("EIP712Domain(uint256 chainId,address verifyingContract)");
// See https://eips.ethereum.org/EIPS/eip-191
string private constant EIP191_PREFIX_FOR_EIP712_STRUCTURED_DATA = "\x19\x01";
// solhint-disable var-name-mixedcase
bytes32 private immutable _DOMAIN_SEPARATOR;
uint256 private immutable DOMAIN_SEPARATOR_CHAIN_ID;
/// @dev Calculate the DOMAIN_SEPARATOR
function _calculateDomainSeparator(uint256 chainId) private view returns (bytes32) {
return keccak256(
abi.encode(
DOMAIN_SEPARATOR_SIGNATURE_HASH,
chainId,
address(this)
)
);
}
constructor() public {
uint256 chainId; assembly {chainId := chainid()}
_DOMAIN_SEPARATOR = _calculateDomainSeparator(DOMAIN_SEPARATOR_CHAIN_ID = chainId);
}
/// @dev Return the DOMAIN_SEPARATOR
// It's named internal to allow making it public from the contract that uses it by creating a simple view function
// with the desired public name, such as DOMAIN_SEPARATOR or domainSeparator.
// solhint-disable-next-line func-name-mixedcase
function _domainSeparator() internal view returns (bytes32) {
uint256 chainId; assembly {chainId := chainid()}
return chainId == DOMAIN_SEPARATOR_CHAIN_ID ? _DOMAIN_SEPARATOR : _calculateDomainSeparator(chainId);
}
function _getDigest(bytes32 dataHash) internal view returns (bytes32 digest) {
digest =
keccak256(
abi.encodePacked(
EIP191_PREFIX_FOR_EIP712_STRUCTURED_DATA,
_domainSeparator(),
dataHash
)
);
}
}
// File @boringcrypto/boring-solidity/contracts/ERC20.sol@v1.2.3
// License-Identifier: MIT
pragma solidity 0.6.12;
// solhint-disable no-inline-assembly
// solhint-disable not-rely-on-time
// Data part taken out for building of contracts that receive delegate calls
contract ERC20Data {
/// @notice owner > balance mapping.
mapping(address => uint256) public balanceOf;
/// @notice owner > spender > allowance mapping.
mapping(address => mapping(address => uint256)) public allowance;
/// @notice owner > nonce mapping. Used in `permit`.
mapping(address => uint256) public nonces;
}
abstract contract ERC20 is IERC20, Domain {
/// @notice owner > balance mapping.
mapping(address => uint256) public override balanceOf;
/// @notice owner > spender > allowance mapping.
mapping(address => mapping(address => uint256)) public override allowance;
/// @notice owner > nonce mapping. Used in `permit`.
mapping(address => uint256) public nonces;
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
/// @notice Transfers `amount` tokens from `msg.sender` to `to`.
/// @param to The address to move the tokens.
/// @param amount of the tokens to move.
/// @return (bool) Returns True if succeeded.
function transfer(address to, uint256 amount) public returns (bool) {
// If `amount` is 0, or `msg.sender` is `to` nothing happens
if (amount != 0 || msg.sender == to) {
uint256 srcBalance = balanceOf[msg.sender];
require(srcBalance >= amount, "ERC20: balance too low");
if (msg.sender != to) {
require(to != address(0), "ERC20: no zero address"); // Moved down so low balance calls safe some gas
balanceOf[msg.sender] = srcBalance - amount; // Underflow is checked
balanceOf[to] += amount;
}
}
emit Transfer(msg.sender, to, amount);
return true;
}
/// @notice Transfers `amount` tokens from `from` to `to`. Caller needs approval for `from`.
/// @param from Address to draw tokens from.
/// @param to The address to move the tokens.
/// @param amount The token amount to move.
/// @return (bool) Returns True if succeeded.
function transferFrom(
address from,
address to,
uint256 amount
) public returns (bool) {
// If `amount` is 0, or `from` is `to` nothing happens
if (amount != 0) {
uint256 srcBalance = balanceOf[from];
require(srcBalance >= amount, "ERC20: balance too low");
if (from != to) {
uint256 spenderAllowance = allowance[from][msg.sender];
// If allowance is infinite, don't decrease it to save on gas (breaks with EIP-20).
if (spenderAllowance != type(uint256).max) {
require(spenderAllowance >= amount, "ERC20: allowance too low");
allowance[from][msg.sender] = spenderAllowance - amount; // Underflow is checked
}
require(to != address(0), "ERC20: no zero address"); // Moved down so other failed calls safe some gas
balanceOf[from] = srcBalance - amount; // Underflow is checked
balanceOf[to] += amount;
}
}
emit Transfer(from, to, amount);
return true;
}
/// @notice Approves `amount` from sender to be spend by `spender`.
/// @param spender Address of the party that can draw from msg.sender's account.
/// @param amount The maximum collective amount that `spender` can draw.
/// @return (bool) Returns True if approved.
function approve(address spender, uint256 amount) public override returns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32) {
return _domainSeparator();
}
// keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
bytes32 private constant PERMIT_SIGNATURE_HASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
/// @notice Approves `value` from `owner_` to be spend by `spender`.
/// @param owner_ Address of the owner.
/// @param spender The address of the spender that gets approved to draw from `owner_`.
/// @param value The maximum collective amount that `spender` can draw.
/// @param deadline This permit must be redeemed before this deadline (UTC timestamp in seconds).
function permit(
address owner_,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external override {
require(owner_ != address(0), "ERC20: Owner cannot be 0");
require(block.timestamp < deadline, "ERC20: Expired");
require(
ecrecover(_getDigest(keccak256(abi.encode(PERMIT_SIGNATURE_HASH, owner_, spender, value, nonces[owner_]++, deadline))), v, r, s) ==
owner_,
"ERC20: Invalid Signature"
);
allowance[owner_][spender] = value;
emit Approval(owner_, spender, value);
}
}
contract ERC20WithSupply is IERC20, ERC20 {
uint256 public override totalSupply;
function _mint(address user, uint256 amount) internal {
uint256 newTotalSupply = totalSupply + amount;
require(newTotalSupply >= totalSupply, "Mint overflow");
totalSupply = newTotalSupply;
balanceOf[user] += amount;
emit Transfer(address(0), user, amount);
}
function _burn(address user, uint256 amount) internal {
require(balanceOf[user] >= amount, "Burn too much");
totalSupply -= amount;
balanceOf[user] -= amount;
emit Transfer(user, address(0), amount);
}
}
// File contracts/Pixel.sol
//License-Identifier: MIT
pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;
// solhint-disable avoid-low-level-calls
contract AddressList {
address[] public addresses;
function addressesCount() public view returns (uint256) { return addresses.length; }
constructor() public {
addresses.push(address(0));
}
function addAddresses(
address[] calldata addresses_
) public {
for (uint256 i = 0; i < addresses_.length; i++) { addresses.push(addresses_[i]); }
}
function getAddresses() public view returns (address[] memory) { return addresses; }
function getAddressesRange(
uint256 start,
uint256 end
) public view returns (address[] memory) {
address[] memory result = new address[](end - start);
for (uint256 i = start; i < (end == 0 ? addresses.length : end); i++)
{
result[i - start] = addresses[i];
}
return result;
}
}
// Simple Multi Level Marketing contract with 3 tiers
contract MLM is AddressList {
using BoringMath for uint256;
struct RepInfo {
uint32 upline;
uint32 earnings1;
uint32 earnings2;
uint32 earnings3;
uint16 tier1;
uint16 tier2;
uint16 tier3;
}
mapping (address => RepInfo) public mlm;
event MLMAddRep(address rep, address upline);
event MLMEarn(address rep, uint32 amount, uint8 lvl);
function _set(address rep, uint32 upline_, uint32 earnings1, uint32 earnings2, uint32 earnings3, uint16 tier1, uint16 tier2, uint16 tier3) internal {
mlm[rep] = RepInfo({
upline: upline_,
earnings1: earnings1,
earnings2: earnings2,
earnings3: earnings3,
tier1: tier1,
tier2: tier2,
tier3: tier3
});
}
function _mlm(address rep, uint32 upline_, uint32 earnings1, uint32 earnings2, uint32 earnings3) internal returns (address lvl1, address lvl2, address lvl3) {
RepInfo memory info = mlm[rep];
bool added;
if (info.upline == 0) {
if (upline_ != 0) {
lvl1 = addresses[upline_];
require(rep != lvl1, "MLM: Can't refer yourself");
if (lvl1 != address(0)) {
info.upline = upline_;
mlm[rep] = info;
emit MLMAddRep(rep, lvl1);
added = true;
}
}
} else {
lvl1 = addresses[info.upline];
}
if (lvl1 != address(0)) {
RepInfo memory info1 = mlm[lvl1];
if (added) {
info1.tier1++;
info1.tier2 += info.tier1;
info1.tier3 += info.tier2;
}
info1.earnings1 += earnings1;
emit MLMEarn(lvl1, earnings1, 1);
mlm[lvl1] = info1;
if (info1.upline != 0) {
lvl2 = addresses[info1.upline];
RepInfo memory info2 = mlm[lvl2];
if (added) {
info2.tier2++;
info2.tier3 += info.tier1;
}
info2.earnings2 += earnings2;
emit MLMEarn(lvl2, earnings2, 2);
mlm[lvl2] = info2;
if (info2.upline != 0) {
lvl3 = addresses[info2.upline];
RepInfo memory info3 = mlm[lvl3];
if (added) {
info3.tier3++;
}
info3.earnings3 += earnings3;
emit MLMEarn(lvl3, earnings3, 3);
mlm[lvl3] = info3;
}
}
}
}
}
contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() internal {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
require(_status != _ENTERED, 'ReentrancyGuard: reentrant call');
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
}
contract PixelV2 is ERC20WithSupply, BoringOwnable, MLM, ReentrancyGuard {
using BoringMath for uint256;
using BoringERC20 for IERC20;
event PixelBlockTransfer(address from, address to, uint256 pricePerPixel);
string public constant symbol = "PIXEL";
string public constant name = "Pixel";
uint8 public constant decimals = 18;
uint256 private constant START_BLOCK_PRICE = 5e15; // Price starts at 0.00005 ETH/pixel = 0.005 ETH/block
uint256 public START_TIMESTAMP;
uint256 public LOCK_TIMESTAMP;
// Block info compressed into a single storage slot
struct Block {
uint32 owner; // current owner nr of the block
uint32 url; // Data nr for url
uint32 description; // Data nr for description
uint32 pixels; // Data nr for pixels
uint128 lastPrice; // last sale price - 0 = never sold
}
struct ExportBlock {
address owner; // current owner of the block
string url; // url for this block (should be < 256 characters)
string description; // description for this block (should be < 256 characters)
bytes pixels; // pixels as bytes
uint128 lastPrice; // last sale price - 0 = never sold
uint32 number;
}
struct ExportRawBlock {
uint32 owner; // current owner nr of the block
uint32 url; // Data nr for url
uint32 description; // Data nr for description
uint32 pixels; // Data nr for pixels
uint128 lastPrice; // last sale price - 0 = never sold
uint32 number;
}
// lookup tables
bytes[] public data;
string[] public text;
function dataCount() public view returns (uint256) { return data.length; }
function textCount() public view returns (uint256) { return text.length; }
// data is organized in blocks of 10x10. There are 100x100 blocks. Base is 0 and counting goes left to right, then top to bottom.
Block[10000] public blk;
uint256[] public updates;
constructor() public payable {
// Set data[0] to blank
text.push("");
data.push(bytes(""));
}
modifier onlyCreationPhase() {
require(block.timestamp >= START_TIMESTAMP && block.timestamp < LOCK_TIMESTAMP, "Not in creation phase");
_;
}
function getBlocks(uint256[] calldata blockNumbers) public view returns (ExportBlock[] memory blocks) {
blocks = new ExportBlock[](blockNumbers.length);
for (uint256 i = 0; i < blockNumbers.length; i++) {
Block memory _blk = blk[blockNumbers[i]];
blocks[i].number = blockNumbers[i].to32();
blocks[i].owner = addresses[_blk.owner];
blocks[i].url = text[_blk.url];
blocks[i].description = text[_blk.description];
blocks[i].pixels = data[_blk.pixels];
blocks[i].lastPrice = _blk.lastPrice;
}
}
function getRawBlocks(uint256[] calldata blockNumbers) public view returns (ExportRawBlock[] memory blocks) {
blocks = new ExportRawBlock[](blockNumbers.length);
for (uint256 i = 0; i < blockNumbers.length; i++) {
Block memory _blk = blk[blockNumbers[i]];
blocks[i].number = blockNumbers[i].to32();
blocks[i].owner = _blk.owner;
blocks[i].url = _blk.url;
blocks[i].description = _blk.description;
blocks[i].pixels = _blk.pixels;
blocks[i].lastPrice = _blk.lastPrice;
}
}
function updatesCount() public view returns (uint256) {
return updates.length;
}
function getUpdates(uint256 since, uint256 max) public view returns (uint256[] memory updatesSince) {
uint256 length = updates.length - since;
if (length > max) {
length = max;
}
updatesSince = new uint256[](length);
for (uint256 i = 0; i < length; i++) {
updatesSince[i] = updates[since + i];
}
}
function addText(
string[] calldata text_
) public {
for (uint256 i = 0; i < text_.length; i++) { text.push(text_[i]); }
}
function addData(
bytes[] calldata data_
) public {
for (uint256 i = 0; i < data_.length; i++) { data.push(data_[i]); }
}
function getText() public view returns (string[] memory) { return text; }
function getTextRange(
uint256 start,
uint256 end
) public view returns (string[] memory) {
string[] memory result = new string[](end - start);
for (uint256 i = start; i < (end == 0 ? text.length : end); i++)
{
result[i - start] = text[i];
}
return result;
}
function getDataRange(
uint256 start,
uint256 end
) public view returns (bytes[] memory) {
bytes[] memory result = new bytes[](end - start);
for (uint256 i = start; i < (end == 0 ? data.length : end); i++)
{
result[i - start] = data[i];
}
return result;
}
function mint(address[] calldata to, uint256[] calldata amount) public onlyOwner {
require(START_TIMESTAMP == 0, "Initialization finished");
for (uint256 i = 0; i < to.length; i++) {
_mint(to[i], amount[i]);
}
}
function initMLM(
address[] memory reps,
uint32[] memory upline,
uint32[] memory earn1,
uint32[] memory earn2,
uint32[] memory earn3,
uint16[] memory tier1,
uint16[] memory tier2,
uint16[] memory tier3
) public onlyOwner {
require(START_TIMESTAMP == 0, "Initialization finished");
for (uint256 i = 0; i < reps.length; i++) {
_set(reps[i], upline[i], earn1[i], earn2[i], earn3[i], tier1[i], tier2[i], tier3[i]);
}
}
function initBlocks(
uint256[] calldata blockNumbers,
uint128[] calldata lastPrice,
uint32[] calldata ownerNr,
uint32[] calldata urlNr,
uint32[] calldata descriptionNr,
uint32[] calldata pixelsNr
) public onlyOwner {
require(START_TIMESTAMP == 0, "Initialization finished");
for (uint256 i = 0; i < blockNumbers.length; i++) {
uint256 blockNumber = blockNumbers[i];
blk[blockNumber] = Block({
owner: ownerNr[i],
url: urlNr[i],
description: descriptionNr[i],
pixels: pixelsNr[i],
lastPrice: lastPrice[i]
});
}
}
function finishInit() public onlyOwner {
START_TIMESTAMP = block.timestamp + 2 hours;
LOCK_TIMESTAMP = block.timestamp + 14 days + 2 hours;
updates.push(10000); // Update of 10000 means: update all blocks from 0 to 9999
}
function _setBlock(
uint256 blockNumber,
uint32 ownerNr,
uint32 urlNr,
uint32 descriptionNr,
uint32 pixelsNr
) private returns(uint256 blockCost) {
require(pixelsNr < data.length, "Wrong pixelNr");
Block memory block_ = blk[blockNumber];
// Forward a maximum of 20000 gas to the previous owner for accepting the refund to avoid griefing attacks
bool success;
address previousOwner = addresses[block_.owner];
uint256 lastPrice = block_.lastPrice;
(success, ) = previousOwner.call{value: lastPrice, gas: 20000}("");
blockCost = lastPrice == 0 ? START_BLOCK_PRICE : lastPrice.mul(2);
block_.owner = ownerNr;
block_.url = urlNr;
block_.description = descriptionNr;
block_.lastPrice = blockCost.to128();
block_.pixels = pixelsNr;
blk[blockNumber] = block_;
updates.push(blockNumber);
emit PixelBlockTransfer(previousOwner, addresses[ownerNr], blockCost);
}
function setBlocks(
address owner,
uint32 ownerNr,
string memory url,
uint32 urlNr,
string memory description,
uint32 descriptionNr,
uint256[] memory blockNumbers,
bytes[] memory pixels,
// Positive numbers refer to existing data. Negative numbers refer to the index in the passed in pixels array
int32[] memory pixelsNr,
address referrer,
uint32 referrerNr
) public payable onlyCreationPhase() nonReentrant() {
if (ownerNr == uint32(-1)) {
ownerNr = addresses.length.to32();
addresses.push(owner);
}
require(ownerNr < addresses.length, "Wrong owner");
if (urlNr == uint32(-1)) {
urlNr = text.length.to32();
text.push(url);
}
require(urlNr < text.length, "Wrong url");
if (descriptionNr == uint32(-1)) {
descriptionNr = text.length.to32();
text.push(description);
}
require(descriptionNr < text.length, "Wrong description");
if (referrerNr == uint32(-1)) {
referrerNr = addresses.length.to32();
addresses.push(referrer);
}
require(referrerNr < addresses.length, "Wrong referrer");
uint256 startPixelNr = data.length;
for (uint256 i = 0; i < pixels.length; i++) { data.push(pixels[i]); }
uint256 cost;
for (uint256 i = 0; i < blockNumbers.length; i++) {
cost = cost.add(_setBlock(blockNumbers[i], ownerNr, urlNr, descriptionNr, (pixelsNr[i] >=0 ? uint256(pixelsNr[i]) : startPixelNr + uint256(-1-pixelsNr[i])).to32()));
}
require(msg.value == cost, "Pixel: not enough funds");
// Mint a PIXEL token for each pixel bought
uint256 blocks = blockNumbers.length;
(address lvl1, address lvl2, address lvl3) = _mlm(msg.sender, referrerNr, blocks.mul(20).to32(), blocks.mul(10).to32(), blocks.mul(5).to32());
_mint(msg.sender, blocks.mul(100e18));
if (lvl1 != address(0)) { _mint(lvl1, blocks.mul(20e18)); }
if (lvl2 != address(0)) { _mint(lvl2, blocks.mul(10e18)); }
if (lvl3 != address(0)) { _mint(lvl3, blocks.mul(5e18)); }
}
function getCost(uint256 blockNumber) public view returns (uint256 cost) {
uint256 last = blk[blockNumber].lastPrice;
cost = last == 0 ? START_BLOCK_PRICE : last.mul(2);
}
function getCost(uint256[] calldata blockNumbers) public view returns (uint256 cost) {
for (uint256 i = 0; i < blockNumbers.length; i++) {
cost = cost.add(getCost(blockNumbers[i]));
}
}
function withdraw(IERC20 token) public onlyOwner {
if (token != IERC20(0)) {
// Withdraw any accidental token deposits
token.safeTransfer(owner, token.balanceOf(address(this)));
} else {
bool success;
(success, ) = owner.call{value: address(this).balance}("");
}
}
function poll(address user) public view returns (uint256 updates_, uint256 addresses_, uint256 text_, uint256 data_, uint256 balance, uint256 supply, RepInfo memory mlm_, address upline_) {
updates_ = updates.length;
addresses_ = addresses.length;
text_ = text.length;
data_ = data.length;
balance = balanceOf[user];
supply = totalSupply;
mlm_ = mlm[user];
upline_ = addresses[mlm[user].upline];
}
function burn(uint256 amount) public {
_burn(msg.sender, amount);
}
}
{
"compilationTarget": {
"PixelV2.sol": "PixelV2"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 10000
},
"remappings": []
}
[{"inputs":[],"stateMutability":"payable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_owner","type":"address"},{"indexed":true,"internalType":"address","name":"_spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"rep","type":"address"},{"indexed":false,"internalType":"address","name":"upline","type":"address"}],"name":"MLMAddRep","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"rep","type":"address"},{"indexed":false,"internalType":"uint32","name":"amount","type":"uint32"},{"indexed":false,"internalType":"uint8","name":"lvl","type":"uint8"}],"name":"MLMEarn","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":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"pricePerPixel","type":"uint256"}],"name":"PixelBlockTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_from","type":"address"},{"indexed":true,"internalType":"address","name":"_to","type":"address"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LOCK_TIMESTAMP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"START_TIMESTAMP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"addresses_","type":"address[]"}],"name":"addAddresses","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data_","type":"bytes[]"}],"name":"addData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string[]","name":"text_","type":"string[]"}],"name":"addText","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"addresses","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"addressesCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"blk","outputs":[{"internalType":"uint32","name":"owner","type":"uint32"},{"internalType":"uint32","name":"url","type":"uint32"},{"internalType":"uint32","name":"description","type":"uint32"},{"internalType":"uint32","name":"pixels","type":"uint32"},{"internalType":"uint128","name":"lastPrice","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"data","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dataCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"finishInit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAddresses","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"end","type":"uint256"}],"name":"getAddressesRange","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"blockNumbers","type":"uint256[]"}],"name":"getBlocks","outputs":[{"components":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"string","name":"url","type":"string"},{"internalType":"string","name":"description","type":"string"},{"internalType":"bytes","name":"pixels","type":"bytes"},{"internalType":"uint128","name":"lastPrice","type":"uint128"},{"internalType":"uint32","name":"number","type":"uint32"}],"internalType":"struct PixelV2.ExportBlock[]","name":"blocks","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"getCost","outputs":[{"internalType":"uint256","name":"cost","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"blockNumbers","type":"uint256[]"}],"name":"getCost","outputs":[{"internalType":"uint256","name":"cost","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"end","type":"uint256"}],"name":"getDataRange","outputs":[{"internalType":"bytes[]","name":"","type":"bytes[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"blockNumbers","type":"uint256[]"}],"name":"getRawBlocks","outputs":[{"components":[{"internalType":"uint32","name":"owner","type":"uint32"},{"internalType":"uint32","name":"url","type":"uint32"},{"internalType":"uint32","name":"description","type":"uint32"},{"internalType":"uint32","name":"pixels","type":"uint32"},{"internalType":"uint128","name":"lastPrice","type":"uint128"},{"internalType":"uint32","name":"number","type":"uint32"}],"internalType":"struct PixelV2.ExportRawBlock[]","name":"blocks","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getText","outputs":[{"internalType":"string[]","name":"","type":"string[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"end","type":"uint256"}],"name":"getTextRange","outputs":[{"internalType":"string[]","name":"","type":"string[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"since","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"name":"getUpdates","outputs":[{"internalType":"uint256[]","name":"updatesSince","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"blockNumbers","type":"uint256[]"},{"internalType":"uint128[]","name":"lastPrice","type":"uint128[]"},{"internalType":"uint32[]","name":"ownerNr","type":"uint32[]"},{"internalType":"uint32[]","name":"urlNr","type":"uint32[]"},{"internalType":"uint32[]","name":"descriptionNr","type":"uint32[]"},{"internalType":"uint32[]","name":"pixelsNr","type":"uint32[]"}],"name":"initBlocks","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"reps","type":"address[]"},{"internalType":"uint32[]","name":"upline","type":"uint32[]"},{"internalType":"uint32[]","name":"earn1","type":"uint32[]"},{"internalType":"uint32[]","name":"earn2","type":"uint32[]"},{"internalType":"uint32[]","name":"earn3","type":"uint32[]"},{"internalType":"uint16[]","name":"tier1","type":"uint16[]"},{"internalType":"uint16[]","name":"tier2","type":"uint16[]"},{"internalType":"uint16[]","name":"tier3","type":"uint16[]"}],"name":"initMLM","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"to","type":"address[]"},{"internalType":"uint256[]","name":"amount","type":"uint256[]"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"mlm","outputs":[{"internalType":"uint32","name":"upline","type":"uint32"},{"internalType":"uint32","name":"earnings1","type":"uint32"},{"internalType":"uint32","name":"earnings2","type":"uint32"},{"internalType":"uint32","name":"earnings3","type":"uint32"},{"internalType":"uint16","name":"tier1","type":"uint16"},{"internalType":"uint16","name":"tier2","type":"uint16"},{"internalType":"uint16","name":"tier3","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner_","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"poll","outputs":[{"internalType":"uint256","name":"updates_","type":"uint256"},{"internalType":"uint256","name":"addresses_","type":"uint256"},{"internalType":"uint256","name":"text_","type":"uint256"},{"internalType":"uint256","name":"data_","type":"uint256"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"supply","type":"uint256"},{"components":[{"internalType":"uint32","name":"upline","type":"uint32"},{"internalType":"uint32","name":"earnings1","type":"uint32"},{"internalType":"uint32","name":"earnings2","type":"uint32"},{"internalType":"uint32","name":"earnings3","type":"uint32"},{"internalType":"uint16","name":"tier1","type":"uint16"},{"internalType":"uint16","name":"tier2","type":"uint16"},{"internalType":"uint16","name":"tier3","type":"uint16"}],"internalType":"struct MLM.RepInfo","name":"mlm_","type":"tuple"},{"internalType":"address","name":"upline_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint32","name":"ownerNr","type":"uint32"},{"internalType":"string","name":"url","type":"string"},{"internalType":"uint32","name":"urlNr","type":"uint32"},{"internalType":"string","name":"description","type":"string"},{"internalType":"uint32","name":"descriptionNr","type":"uint32"},{"internalType":"uint256[]","name":"blockNumbers","type":"uint256[]"},{"internalType":"bytes[]","name":"pixels","type":"bytes[]"},{"internalType":"int32[]","name":"pixelsNr","type":"int32[]"},{"internalType":"address","name":"referrer","type":"address"},{"internalType":"uint32","name":"referrerNr","type":"uint32"}],"name":"setBlocks","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"text","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"textCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"},{"internalType":"bool","name":"direct","type":"bool"},{"internalType":"bool","name":"renounce","type":"bool"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"updates","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"updatesCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]