pragmasolidity ^0.5.2;contractAdmin{
addressinternal _admin;
eventAdminChanged(address oldAdmin, address newAdmin);
/// @notice gives the current administrator of this contract./// @return the current administrator of this contract.functiongetAdmin() externalviewreturns (address) {
return _admin;
}
/// @notice change the administrator to be `newAdmin`./// @param newAdmin address of the new administrator.functionchangeAdmin(address newAdmin) external{
require(msg.sender== _admin, "only admin can change admin");
emit AdminChanged(_admin, newAdmin);
_admin = newAdmin;
}
modifieronlyAdmin() {
require (msg.sender== _admin, "only admin allowed");
_;
}
}
Contract Source Code
File 3 of 10: ERC721BaseToken.sol
/* solhint-disable func-order, code-complexity */pragmasolidity 0.5.9;import"../../../contracts_common/src/Libraries/AddressUtils.sol";
import"../../../contracts_common/src/Interfaces/ERC721TokenReceiver.sol";
import"../../../contracts_common/src/Interfaces/ERC721Events.sol";
import"../../../contracts_common/src/BaseWithStorage/SuperOperators.sol";
import"../../../contracts_common/src/BaseWithStorage/MetaTransactionReceiver.sol";
import"../../../contracts_common/src/Interfaces/ERC721MandatoryTokenReceiver.sol";
contractERC721BaseTokenisERC721Events, SuperOperators, MetaTransactionReceiver{
usingAddressUtilsforaddress;
bytes4internalconstant _ERC721_RECEIVED =0x150b7a02;
bytes4internalconstant _ERC721_BATCH_RECEIVED =0x4b808c46;
bytes4internalconstant ERC165ID =0x01ffc9a7;
bytes4internalconstant ERC721_MANDATORY_RECEIVER =0x5e8bf644;
mapping (address=>uint256) public _numNFTPerAddress;
mapping (uint256=>uint256) public _owners;
mapping (address=>mapping(address=>bool)) public _operatorsForAll;
mapping (uint256=>address) public _operators;
constructor(address metaTransactionContract,
address admin
) internal{
_admin = admin;
_setMetaTransactionProcessor(metaTransactionContract, true);
}
function_transferFrom(addressfrom, address to, uint256 id) internal{
_numNFTPerAddress[from]--;
_numNFTPerAddress[to]++;
_owners[id] =uint256(to);
emit Transfer(from, to, id);
}
/**
* @notice Return the number of Land owned by an address
* @param owner The address to look for
* @return The number of Land token owned by the address
*/functionbalanceOf(address owner) externalviewreturns (uint256) {
require(owner !=address(0), "owner is zero address");
return _numNFTPerAddress[owner];
}
function_ownerOf(uint256 id) internalviewreturns (address) {
returnaddress(_owners[id]);
}
function_ownerAndOperatorEnabledOf(uint256 id) internalviewreturns (address owner, bool operatorEnabled) {
uint256 data = _owners[id];
owner =address(data);
operatorEnabled = (data /2**255) ==1;
}
/**
* @notice Return the owner of a Land
* @param id The id of the Land
* @return The address of the owner
*/functionownerOf(uint256 id) externalviewreturns (address owner) {
owner = _ownerOf(id);
require(owner !=address(0), "token does not exist");
}
function_approveFor(address owner, address operator, uint256 id) internal{
if(operator ==address(0)) {
_owners[id] =uint256(owner); // no need to resset the operator, it will be overriden next time
} else {
_owners[id] =uint256(owner) +2**255;
_operators[id] = operator;
}
emit Approval(owner, operator, id);
}
/**
* @notice Approve an operator to spend tokens on the sender behalf
* @param sender The address giving the approval
* @param operator The address receiving the approval
* @param id The id of the token
*/functionapproveFor(address sender,
address operator,
uint256 id
) external{
address owner = _ownerOf(id);
require(sender !=address(0), "sender is zero address");
require(
msg.sender== sender ||
_metaTransactionContracts[msg.sender] ||
_superOperators[msg.sender] ||
_operatorsForAll[sender][msg.sender],
"not authorized to approve"
);
require(owner == sender, "owner != sender");
_approveFor(owner, operator, id);
}
/**
* @notice Approve an operator to spend tokens on the sender behalf
* @param operator The address receiving the approval
* @param id The id of the token
*/functionapprove(address operator, uint256 id) external{
address owner = _ownerOf(id);
require(owner !=address(0), "token does not exist");
require(
owner ==msg.sender||
_superOperators[msg.sender] ||
_operatorsForAll[owner][msg.sender],
"not authorized to approve"
);
_approveFor(owner, operator, id);
}
/**
* @notice Get the approved operator for a specific token
* @param id The id of the token
* @return The address of the operator
*/functiongetApproved(uint256 id) externalviewreturns (address) {
(address owner, bool operatorEnabled) = _ownerAndOperatorEnabledOf(id);
require(owner !=address(0), "token does not exist");
if (operatorEnabled) {
return _operators[id];
} else {
returnaddress(0);
}
}
function_checkTransfer(addressfrom, address to, uint256 id) internalviewreturns (bool isMetaTx) {
(address owner, bool operatorEnabled) = _ownerAndOperatorEnabledOf(id);
require(owner !=address(0), "token does not exist");
require(owner ==from, "not owner in _checkTransfer");
require(to !=address(0), "can't send to zero address");
isMetaTx =msg.sender!=from&& _metaTransactionContracts[msg.sender];
if (msg.sender!=from&&!isMetaTx) {
require(
_superOperators[msg.sender] ||
_operatorsForAll[from][msg.sender] ||
(operatorEnabled && _operators[id] ==msg.sender),
"not approved to transfer"
);
}
}
function_checkInterfaceWith10000Gas(address _contract, bytes4 interfaceId)
internalviewreturns (bool)
{
bool success;
bool result;
bytesmemory call_data =abi.encodeWithSelector(
ERC165ID,
interfaceId
);
// solium-disable-next-line security/no-inline-assemblyassembly {
let call_ptr :=add(0x20, call_data)
let call_size :=mload(call_data)
let output :=mload(0x40) // Find empty storage location using "free memory pointer"mstore(output, 0x0)
success :=staticcall(
10000,
_contract,
call_ptr,
call_size,
output,
0x20
) // 32 bytes
result :=mload(output)
}
// (10000 / 63) "not enough for supportsInterface(...)" // consume all gas, so caller can potentially know that there was not enough gasassert(gasleft() >158);
return success && result;
}
/**
* @notice Transfer a token between 2 addresses
* @param from The sender of the token
* @param to The recipient of the token
* @param id The id of the token
*/functiontransferFrom(addressfrom, address to, uint256 id) external{
bool metaTx = _checkTransfer(from, to, id);
_transferFrom(from, to, id);
if (to.isContract() && _checkInterfaceWith10000Gas(to, ERC721_MANDATORY_RECEIVER)) {
require(
_checkOnERC721Received(metaTx ? from : msg.sender, from, to, id, ""),
"erc721 transfer rejected by to"
);
}
}
/**
* @notice Transfer a token between 2 addresses letting the receiver knows of the transfer
* @param from The sender of the token
* @param to The recipient of the token
* @param id The id of the token
* @param data Additional data
*/functionsafeTransferFrom(addressfrom, address to, uint256 id, bytesmemory data) public{
bool metaTx = _checkTransfer(from, to, id);
_transferFrom(from, to, id);
if (to.isContract()) {
require(
_checkOnERC721Received(metaTx ? from : msg.sender, from, to, id, data),
"ERC721: transfer rejected by to"
);
}
}
/**
* @notice Transfer a token between 2 addresses letting the receiver knows of the transfer
* @param from The send of the token
* @param to The recipient of the token
* @param id The id of the token
*/functionsafeTransferFrom(addressfrom, address to, uint256 id) external{
safeTransferFrom(from, to, id, "");
}
/**
* @notice Transfer many tokens between 2 addresses
* @param from The sender of the token
* @param to The recipient of the token
* @param ids The ids of the tokens
* @param data additional data
*/functionbatchTransferFrom(addressfrom, address to, uint256[] calldata ids, bytescalldata data) external{
_batchTransferFrom(from, to, ids, data, false);
}
function_batchTransferFrom(addressfrom, address to, uint256[] memory ids, bytesmemory data, bool safe) internal{
bool metaTx =msg.sender!=from&& _metaTransactionContracts[msg.sender];
bool authorized =msg.sender==from||
metaTx ||
_superOperators[msg.sender] ||
_operatorsForAll[from][msg.sender];
require(from!=address(0), "from is zero address");
require(to !=address(0), "can't send to zero address");
uint256 numTokens = ids.length;
for(uint256 i =0; i < numTokens; i ++) {
uint256 id = ids[i];
(address owner, bool operatorEnabled) = _ownerAndOperatorEnabledOf(id);
require(owner ==from, "not owner in batchTransferFrom");
require(authorized || (operatorEnabled && _operators[id] ==msg.sender), "not authorized");
_owners[id] =uint256(to);
emit Transfer(from, to, id);
}
if (from!= to) {
_numNFTPerAddress[from] -= numTokens;
_numNFTPerAddress[to] += numTokens;
}
if (to.isContract() && (safe || _checkInterfaceWith10000Gas(to, ERC721_MANDATORY_RECEIVER))) {
require(
_checkOnERC721BatchReceived(metaTx ? from : msg.sender, from, to, ids, data),
"erc721 batch transfer rejected by to"
);
}
}
/**
* @notice Transfer many tokens between 2 addresses ensuring the receiving contract has a receiver method
* @param from The sender of the token
* @param to The recipient of the token
* @param ids The ids of the tokens
* @param data additional data
*/functionsafeBatchTransferFrom(addressfrom, address to, uint256[] calldata ids, bytescalldata data) external{
_batchTransferFrom(from, to, ids, data, true);
}
/**
* @notice Check if the contract supports an interface
* 0x01ffc9a7 is ERC-165
* 0x80ac58cd is ERC-721
* @param id The id of the interface
* @return True if the interface is supported
*/functionsupportsInterface(bytes4 id) externalpurereturns (bool) {
return id ==0x01ffc9a7|| id ==0x80ac58cd;
}
/**
* @notice Set the approval for an operator to manage all the tokens of the sender
* @param sender The address giving the approval
* @param operator The address receiving the approval
* @param approved The determination of the approval
*/functionsetApprovalForAllFor(address sender,
address operator,
bool approved
) external{
require(sender !=address(0), "Invalid sender address");
require(
msg.sender== sender ||
_metaTransactionContracts[msg.sender] ||
_superOperators[msg.sender],
"not authorized to approve for all"
);
_setApprovalForAll(sender, operator, approved);
}
/**
* @notice Set the approval for an operator to manage all the tokens of the sender
* @param operator The address receiving the approval
* @param approved The determination of the approval
*/functionsetApprovalForAll(address operator, bool approved) external{
_setApprovalForAll(msg.sender, operator, approved);
}
function_setApprovalForAll(address sender,
address operator,
bool approved
) internal{
require(
!_superOperators[operator],
"super operator can't have their approvalForAll changed"
);
_operatorsForAll[sender][operator] = approved;
emit ApprovalForAll(sender, operator, approved);
}
/**
* @notice Check if the sender approved the operator
* @param owner The address of the owner
* @param operator The address of the operator
* @return The status of the approval
*/functionisApprovedForAll(address owner, address operator)
externalviewreturns (bool isOperator)
{
return _operatorsForAll[owner][operator] || _superOperators[operator];
}
function_burn(addressfrom, address owner, uint256 id) public{
require(from== owner, "not owner");
_owners[id] =2**160; // cannot mint it again
_numNFTPerAddress[from]--;
emit Transfer(from, address(0), id);
}
/// @notice Burns token `id`./// @param id token which will be burnt.functionburn(uint256 id) external{
_burn(msg.sender, _ownerOf(id), id);
}
/// @notice Burn token`id` from `from`./// @param from address whose token is to be burnt./// @param id token which will be burnt.functionburnFrom(addressfrom, uint256 id) external{
require(from!=address(0), "Invalid sender address");
(address owner, bool operatorEnabled) = _ownerAndOperatorEnabledOf(id);
require(
msg.sender==from||
_metaTransactionContracts[msg.sender] ||
(operatorEnabled && _operators[id] ==msg.sender) ||
_superOperators[msg.sender] ||
_operatorsForAll[from][msg.sender],
"not authorized to burn"
);
_burn(from, owner, id);
}
function_checkOnERC721Received(address operator, addressfrom, address to, uint256 tokenId, bytesmemory _data)
internalreturns (bool)
{
bytes4 retval = ERC721TokenReceiver(to).onERC721Received(operator, from, tokenId, _data);
return (retval == _ERC721_RECEIVED);
}
function_checkOnERC721BatchReceived(address operator, addressfrom, address to, uint256[] memory ids, bytesmemory _data)
internalreturns (bool)
{
bytes4 retval = ERC721MandatoryTokenReceiver(to).onERC721BatchReceived(operator, from, ids, _data);
return (retval == _ERC721_BATCH_RECEIVED);
}
}
pragmasolidity ^0.5.2;/**
Note: The ERC-165 identifier for this interface is 0x5e8bf644.
*/interfaceERC721MandatoryTokenReceiver{
functiononERC721BatchReceived(address operator,
addressfrom,
uint256[] calldata ids,
bytescalldata data
) externalreturns (bytes4); // needs to return 0x4b808c46functiononERC721Received(address operator,
addressfrom,
uint256 tokenId,
bytescalldata data
) externalreturns (bytes4); // needs to return 0x150b7a02// needs to implements EIP-165// function supportsInterface(bytes4 interfaceId)// external// view// returns (bool);
}
Contract Source Code
File 6 of 10: ERC721TokenReceiver.sol
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This code has not been reviewed.
* Do not use or deploy this code before reviewing it personally first.
*/// solhint-disable-next-line compiler-fixedpragmasolidity ^0.5.2;interfaceERC721TokenReceiver{
functiononERC721Received(address operator,
addressfrom,
uint256 tokenId,
bytescalldata data
) externalreturns (bytes4);
}
Contract Source Code
File 7 of 10: Land.sol
/* solhint-disable no-empty-blocks */pragmasolidity 0.5.9;import"./Land/erc721/LandBaseToken.sol";
contractLandisLandBaseToken{
constructor(address metaTransactionContract,
address admin
) publicLandBaseToken(
metaTransactionContract,
admin
) {
}
/**
* @notice Return the name of the token contract
* @return The name of the token contract
*/functionname() externalpurereturns (stringmemory) {
return"Sandbox's LANDs";
}
/**
* @notice Return the symbol of the token contract
* @return The symbol of the token contract
*/functionsymbol() externalpurereturns (stringmemory) {
return"LAND";
}
// solium-disable-next-line security/no-assign-paramsfunctionuint2str(uint _i) internalpurereturns (stringmemory) {
if (_i ==0) {
return"0";
}
uint j = _i;
uint len;
while (j !=0) {
len++;
j /=10;
}
bytesmemory bstr =newbytes(len);
uint k = len -1;
while (_i !=0) {
bstr[k--] =byte(uint8(48+ _i %10));
_i /=10;
}
returnstring(bstr);
}
/**
* @notice Return the URI of a specific token
* @param id The id of the token
* @return The URI of the token
*/functiontokenURI(uint256 id) publicviewreturns (stringmemory) {
require(_ownerOf(id) !=address(0), "Id does not exist");
returnstring(
abi.encodePacked(
"https://api.sandbox.game/lands/",
uint2str(id),
"/metadata.json"
)
);
}
/**
* @notice Check if the contract supports an interface
* 0x01ffc9a7 is ERC-165
* 0x80ac58cd is ERC-721
* 0x5b5e139f is ERC-721 metadata
* @param id The id of the interface
* @return True if the interface is supported
*/functionsupportsInterface(bytes4 id) externalpurereturns (bool) {
return id ==0x01ffc9a7|| id ==0x80ac58cd|| id ==0x5b5e139f;
}
}
Contract Source Code
File 8 of 10: LandBaseToken.sol
/* solhint-disable func-order, code-complexity */pragmasolidity 0.5.9;import"./ERC721BaseToken.sol";
contractLandBaseTokenisERC721BaseToken{
// Our grid is 408 x 408 landsuint256internalconstant GRID_SIZE =408;
uint256internalconstant LAYER =0xFF00000000000000000000000000000000000000000000000000000000000000;
uint256internalconstant LAYER_1x1 =0x0000000000000000000000000000000000000000000000000000000000000000;
uint256internalconstant LAYER_3x3 =0x0100000000000000000000000000000000000000000000000000000000000000;
uint256internalconstant LAYER_6x6 =0x0200000000000000000000000000000000000000000000000000000000000000;
uint256internalconstant LAYER_12x12 =0x0300000000000000000000000000000000000000000000000000000000000000;
uint256internalconstant LAYER_24x24 =0x0400000000000000000000000000000000000000000000000000000000000000;
mapping(address=>bool) internal _minters;
eventMinter(address superOperator, bool enabled);
/// @notice Enable or disable the ability of `minter` to mint tokens/// @param minter address that will be given/removed minter right./// @param enabled set whether the minter is enabled or disabled.functionsetMinter(address minter, bool enabled) external{
require(
msg.sender== _admin,
"only admin is allowed to add minters"
);
_minters[minter] = enabled;
emit Minter(minter, enabled);
}
/// @notice check whether address `who` is given minter rights./// @param who The address to query./// @return whether the address has minter rights.functionisMinter(address who) publicviewreturns (bool) {
return _minters[who];
}
constructor(address metaTransactionContract,
address admin
) publicERC721BaseToken(metaTransactionContract, admin) {
}
/// @notice total width of the map/// @return widthfunctionwidth() externalreturns(uint256) {
return GRID_SIZE;
}
/// @notice total height of the map/// @return heightfunctionheight() externalreturns(uint256) {
return GRID_SIZE;
}
/// @notice x coordinate of Land token/// @param id tokenId/// @return the x coordinatesfunctionx(uint256 id) externalreturns(uint256) {
require(_ownerOf(id) !=address(0), "token does not exist");
return id % GRID_SIZE;
}
/// @notice y coordinate of Land token/// @param id tokenId/// @return the y coordinatesfunctiony(uint256 id) externalreturns(uint256) {
require(_ownerOf(id) !=address(0), "token does not exist");
return id / GRID_SIZE;
}
/**
* @notice Mint a new quad (aligned to a quad tree with size 3, 6, 12 or 24 only)
* @param to The recipient of the new quad
* @param size The size of the new quad
* @param x The top left x coordinate of the new quad
* @param y The top left y coordinate of the new quad
* @param data extra data to pass to the transfer
*/functionmintQuad(address to, uint256 size, uint256 x, uint256 y, bytescalldata data) external{
require(to !=address(0), "to is zero address");
require(
isMinter(msg.sender),
"Only a minter can mint"
);
require(x % size ==0&& y % size ==0, "Invalid coordinates");
require(x <= GRID_SIZE - size && y <= GRID_SIZE - size, "Out of bounds");
uint256 quadId;
uint256 id = x + y * GRID_SIZE;
if (size ==1) {
quadId = id;
} elseif (size ==3) {
quadId = LAYER_3x3 + id;
} elseif (size ==6) {
quadId = LAYER_6x6 + id;
} elseif (size ==12) {
quadId = LAYER_12x12 + id;
} elseif (size ==24) {
quadId = LAYER_24x24 + id;
} else {
require(false, "Invalid size");
}
require(_owners[LAYER_24x24 + (x/24) *24+ ((y/24) *24) * GRID_SIZE] ==0, "Already minted as 24x24");
uint256 toX = x+size;
uint256 toY = y+size;
if (size <=12) {
require(
_owners[LAYER_12x12 + (x/12) *12+ ((y/12) *12) * GRID_SIZE] ==0,
"Already minted as 12x12"
);
} else {
for (uint256 x12i = x; x12i < toX; x12i +=12) {
for (uint256 y12i = y; y12i < toY; y12i +=12) {
uint256 id12x12 = LAYER_12x12 + x12i + y12i * GRID_SIZE;
require(_owners[id12x12] ==0, "Already minted as 12x12");
}
}
}
if (size <=6) {
require(_owners[LAYER_6x6 + (x/6) *6+ ((y/6) *6) * GRID_SIZE] ==0, "Already minted as 6x6");
} else {
for (uint256 x6i = x; x6i < toX; x6i +=6) {
for (uint256 y6i = y; y6i < toY; y6i +=6) {
uint256 id6x6 = LAYER_6x6 + x6i + y6i * GRID_SIZE;
require(_owners[id6x6] ==0, "Already minted as 6x6");
}
}
}
if (size <=3) {
require(_owners[LAYER_3x3 + (x/3) *3+ ((y/3) *3) * GRID_SIZE] ==0, "Already minted as 3x3");
} else {
for (uint256 x3i = x; x3i < toX; x3i +=3) {
for (uint256 y3i = y; y3i < toY; y3i +=3) {
uint256 id3x3 = LAYER_3x3 + x3i + y3i * GRID_SIZE;
require(_owners[id3x3] ==0, "Already minted as 3x3");
}
}
}
for (uint256 i =0; i < size*size; i++) {
uint256 id = _idInPath(i, size, x, y);
require(_owners[id] ==0, "Already minted");
emit Transfer(address(0), to, id);
}
_owners[quadId] =uint256(to);
_numNFTPerAddress[to] += size * size;
_checkBatchReceiverAcceptQuad(msg.sender, address(0), to, size, x, y, data);
}
function_idInPath(uint256 i, uint256 size, uint256 x, uint256 y) internalpurereturns(uint256) {
uint256 row = i / size;
if(row %2==0) { // alow ids to follow a path in a quadreturn (x + (i%size)) + ((y + row) * GRID_SIZE);
} else {
return ((x + size) - (1+ i%size)) + ((y + row) * GRID_SIZE);
}
}
/// @notice transfer one quad (aligned to a quad tree with size 3, 6, 12 or 24 only)/// @param from current owner of the quad/// @param to destination/// @param size size of the quad/// @param x The top left x coordinate of the quad/// @param y The top left y coordinate of the quad/// @param data additional datafunctiontransferQuad(addressfrom, address to, uint256 size, uint256 x, uint256 y, bytescalldata data) external{
require(from!=address(0), "from is zero address");
require(to !=address(0), "can't send to zero address");
bool metaTx =msg.sender!=from&& _metaTransactionContracts[msg.sender];
if (msg.sender!=from&&!metaTx) {
require(
_superOperators[msg.sender] ||
_operatorsForAll[from][msg.sender],
"not authorized to transferQuad"
);
}
_transferQuad(from, to, size, x, y);
_numNFTPerAddress[from] -= size * size;
_numNFTPerAddress[to] += size * size;
_checkBatchReceiverAcceptQuad(metaTx ? from : msg.sender, from, to, size, x, y, data);
}
function_checkBatchReceiverAcceptQuad(address operator,
addressfrom,
address to,
uint256 size,
uint256 x,
uint256 y,
bytesmemory data
) internal{
if (to.isContract() && _checkInterfaceWith10000Gas(to, ERC721_MANDATORY_RECEIVER)) {
uint256[] memory ids =newuint256[](size*size);
for (uint256 i =0; i < size*size; i++) {
ids[i] = _idInPath(i, size, x, y);
}
require(
_checkOnERC721BatchReceived(operator, from, to, ids, data),
"erc721 batch transfer rejected by to"
);
}
}
/// @notice transfer multiple quad (aligned to a quad tree with size 3, 6, 12 or 24 only)/// @param from current owner of the quad/// @param to destination/// @param sizes list of sizes for each quad/// @param xs list of top left x coordinates for each quad/// @param ys list of top left y coordinates for each quad/// @param data additional datafunctionbatchTransferQuad(addressfrom,
address to,
uint256[] calldata sizes,
uint256[] calldata xs,
uint256[] calldata ys,
bytescalldata data
) external{
require(from!=address(0), "from is zero address");
require(to !=address(0), "can't send to zero address");
require(sizes.length== xs.length&& xs.length== ys.length, "invalid data");
bool metaTx =msg.sender!=from&& _metaTransactionContracts[msg.sender];
if (msg.sender!=from&&!metaTx) {
require(
_superOperators[msg.sender] ||
_operatorsForAll[from][msg.sender],
"not authorized to transferMultiQuads"
);
}
uint256 numTokensTransfered =0;
for (uint256 i =0; i < sizes.length; i++) {
uint256 size = sizes[i];
_transferQuad(from, to, size, xs[i], ys[i]);
numTokensTransfered += size * size;
}
_numNFTPerAddress[from] -= numTokensTransfered;
_numNFTPerAddress[to] += numTokensTransfered;
if (to.isContract() && _checkInterfaceWith10000Gas(to, ERC721_MANDATORY_RECEIVER)) {
uint256[] memory ids =newuint256[](numTokensTransfered);
uint256 counter =0;
for (uint256 j =0; j < sizes.length; j++) {
uint256 size = sizes[j];
for (uint256 i =0; i < size*size; i++) {
ids[counter] = _idInPath(i, size, xs[j], ys[j]);
counter++;
}
}
require(
_checkOnERC721BatchReceived(metaTx ? from : msg.sender, from, to, ids, data),
"erc721 batch transfer rejected by to"
);
}
}
function_transferQuad(addressfrom, address to, uint256 size, uint256 x, uint256 y) internal{
if (size ==1) {
uint256 id1x1 = x + y * GRID_SIZE;
address owner = _ownerOf(id1x1);
require(owner !=address(0), "token does not exist");
require(owner ==from, "not owner in _transferQuad");
_owners[id1x1] =uint256(to);
} else {
_regroup(from, to, size, x, y);
}
for (uint256 i =0; i < size*size; i++) {
emit Transfer(from, to, _idInPath(i, size, x, y));
}
}
function_checkAndClear(addressfrom, uint256 id) internalreturns(bool) {
uint256 owner = _owners[id];
if (owner !=0) {
require(address(owner) ==from, "not owner");
_owners[id] =0;
returntrue;
}
returnfalse;
}
function_regroup(addressfrom, address to, uint256 size, uint256 x, uint256 y) internal{
require(x % size ==0&& y % size ==0, "Invalid coordinates");
require(x <= GRID_SIZE - size && y <= GRID_SIZE - size, "Out of bounds");
if (size ==3) {
_regroup3x3(from, to, x, y, true);
} elseif (size ==6) {
_regroup6x6(from, to, x, y, true);
} elseif (size ==12) {
_regroup12x12(from, to, x, y, true);
} elseif (size ==24) {
_regroup24x24(from, to, x, y, true);
} else {
require(false, "Invalid size");
}
}
function_regroup3x3(addressfrom, address to, uint256 x, uint256 y, bool set) internalreturns (bool) {
uint256 id = x + y * GRID_SIZE;
uint256 quadId = LAYER_3x3 + id;
bool ownerOfAll =true;
for (uint256 xi = x; xi < x+3; xi++) {
for (uint256 yi = y; yi < y+3; yi++) {
ownerOfAll = _checkAndClear(from, xi + yi * GRID_SIZE) && ownerOfAll;
}
}
if(set) {
if(!ownerOfAll) {
require(
_owners[quadId] ==uint256(from) ||
_owners[LAYER_6x6 + (x/6) *6+ ((y/6) *6) * GRID_SIZE] ==uint256(from) ||
_owners[LAYER_12x12 + (x/12) *12+ ((y/12) *12) * GRID_SIZE] ==uint256(from) ||
_owners[LAYER_24x24 + (x/24) *24+ ((y/24) *24) * GRID_SIZE] ==uint256(from),
"not owner of all sub quads nor parent quads"
);
}
_owners[quadId] =uint256(to);
returntrue;
}
return ownerOfAll;
}
function_regroup6x6(addressfrom, address to, uint256 x, uint256 y, bool set) internalreturns (bool) {
uint256 id = x + y * GRID_SIZE;
uint256 quadId = LAYER_6x6 + id;
bool ownerOfAll =true;
for (uint256 xi = x; xi < x+6; xi +=3) {
for (uint256 yi = y; yi < y+6; yi +=3) {
bool ownAllIndividual = _regroup3x3(from, to, xi, yi, false);
uint256 id3x3 = LAYER_3x3 + xi + yi * GRID_SIZE;
uint256 owner3x3 = _owners[id3x3];
if (owner3x3 !=0) {
if(!ownAllIndividual) {
require(owner3x3 ==uint256(from), "not owner of 3x3 quad");
}
_owners[id3x3] =0;
}
ownerOfAll = (ownAllIndividual || owner3x3 !=0) && ownerOfAll;
}
}
if(set) {
if(!ownerOfAll) {
require(
_owners[quadId] ==uint256(from) ||
_owners[LAYER_12x12 + (x/12) *12+ ((y/12) *12) * GRID_SIZE] ==uint256(from) ||
_owners[LAYER_24x24 + (x/24) *24+ ((y/24) *24) * GRID_SIZE] ==uint256(from),
"not owner of all sub quads nor parent quads"
);
}
_owners[quadId] =uint256(to);
returntrue;
}
return ownerOfAll;
}
function_regroup12x12(addressfrom, address to, uint256 x, uint256 y, bool set) internalreturns (bool) {
uint256 id = x + y * GRID_SIZE;
uint256 quadId = LAYER_12x12 + id;
bool ownerOfAll =true;
for (uint256 xi = x; xi < x+12; xi +=6) {
for (uint256 yi = y; yi < y+12; yi +=6) {
bool ownAllIndividual = _regroup6x6(from, to, xi, yi, false);
uint256 id6x6 = LAYER_6x6 + xi + yi * GRID_SIZE;
uint256 owner6x6 = _owners[id6x6];
if (owner6x6 !=0) {
if(!ownAllIndividual) {
require(owner6x6 ==uint256(from), "not owner of 6x6 quad");
}
_owners[id6x6] =0;
}
ownerOfAll = (ownAllIndividual || owner6x6 !=0) && ownerOfAll;
}
}
if(set) {
if(!ownerOfAll) {
require(
_owners[quadId] ==uint256(from) ||
_owners[LAYER_24x24 + (x/24) *24+ ((y/24) *24) * GRID_SIZE] ==uint256(from),
"not owner of all sub quads nor parent quads"
);
}
_owners[quadId] =uint256(to);
returntrue;
}
return ownerOfAll;
}
function_regroup24x24(addressfrom, address to, uint256 x, uint256 y, bool set) internalreturns (bool) {
uint256 id = x + y * GRID_SIZE;
uint256 quadId = LAYER_24x24 + id;
bool ownerOfAll =true;
for (uint256 xi = x; xi < x+24; xi +=12) {
for (uint256 yi = y; yi < y+24; yi +=12) {
bool ownAllIndividual = _regroup12x12(from, to, xi, yi, false);
uint256 id12x12 = LAYER_12x12 + xi + yi * GRID_SIZE;
uint256 owner12x12 = _owners[id12x12];
if (owner12x12 !=0) {
if(!ownAllIndividual) {
require(owner12x12 ==uint256(from), "not owner of 12x12 quad");
}
_owners[id12x12] =0;
}
ownerOfAll = (ownAllIndividual || owner12x12 !=0) && ownerOfAll;
}
}
if(set) {
if(!ownerOfAll) {
require(
_owners[quadId] ==uint256(from),
"not owner of all sub quads not parent quad"
);
}
_owners[quadId] =uint256(to);
returntrue;
}
return ownerOfAll || _owners[quadId] ==uint256(from);
}
function_ownerOf(uint256 id) internalviewreturns (address) {
require(id & LAYER ==0, "Invalid token id");
uint256 x = id % GRID_SIZE;
uint256 y = id / GRID_SIZE;
uint256 owner1x1 = _owners[id];
if (owner1x1 !=0) {
returnaddress(owner1x1); // cast to zero
} else {
address owner3x3 =address(_owners[LAYER_3x3 + (x/3) *3+ ((y/3) *3) * GRID_SIZE]);
if (owner3x3 !=address(0)) {
return owner3x3;
} else {
address owner6x6 =address(_owners[LAYER_6x6 + (x/6) *6+ ((y/6) *6) * GRID_SIZE]);
if (owner6x6 !=address(0)) {
return owner6x6;
} else {
address owner12x12 =address(_owners[LAYER_12x12 + (x/12) *12+ ((y/12) *12) * GRID_SIZE]);
if (owner12x12 !=address(0)) {
return owner12x12;
} else {
returnaddress(_owners[LAYER_24x24 + (x/24) *24+ ((y/24) *24) * GRID_SIZE]);
}
}
}
}
}
function_ownerAndOperatorEnabledOf(uint256 id) internalviewreturns (address owner, bool operatorEnabled) {
require(id & LAYER ==0, "Invalid token id");
uint256 x = id % GRID_SIZE;
uint256 y = id / GRID_SIZE;
uint256 owner1x1 = _owners[id];
if (owner1x1 !=0) {
owner =address(owner1x1);
operatorEnabled = (owner1x1 /2**255) ==1;
} else {
address owner3x3 =address(_owners[LAYER_3x3 + (x/3) *3+ ((y/3) *3) * GRID_SIZE]);
if (owner3x3 !=address(0)) {
owner = owner3x3;
operatorEnabled =false;
} else {
address owner6x6 =address(_owners[LAYER_6x6 + (x/6) *6+ ((y/6) *6) * GRID_SIZE]);
if (owner6x6 !=address(0)) {
owner = owner6x6;
operatorEnabled =false;
} else {
address owner12x12 =address(_owners[LAYER_12x12 + (x/12) *12+ ((y/12) *12) * GRID_SIZE]);
if (owner12x12 !=address(0)) {
owner = owner12x12;
operatorEnabled =false;
} else {
owner =address(_owners[LAYER_24x24 + (x/24) *24+ ((y/24) *24) * GRID_SIZE]);
operatorEnabled =false;
}
}
}
}
}
}
Contract Source Code
File 9 of 10: MetaTransactionReceiver.sol
pragmasolidity ^0.5.2;import"./Admin.sol";
contractMetaTransactionReceiverisAdmin{
mapping(address=>bool) internal _metaTransactionContracts;
eventMetaTransactionProcessor(address metaTransactionProcessor, bool enabled);
/// @notice Enable or disable the ability of `metaTransactionProcessor` to perform meta-tx (metaTransactionProcessor rights)./// @param metaTransactionProcessor address that will be given/removed metaTransactionProcessor rights./// @param enabled set whether the metaTransactionProcessor is enabled or disabled.functionsetMetaTransactionProcessor(address metaTransactionProcessor, bool enabled) public{
require(
msg.sender== _admin,
"only admin can setup metaTransactionProcessors"
);
_setMetaTransactionProcessor(metaTransactionProcessor, enabled);
}
function_setMetaTransactionProcessor(address metaTransactionProcessor, bool enabled) internal{
_metaTransactionContracts[metaTransactionProcessor] = enabled;
emit MetaTransactionProcessor(metaTransactionProcessor, enabled);
}
/// @notice check whether address `who` is given meta-transaction execution rights./// @param who The address to query./// @return whether the address has meta-transaction execution rights.functionisMetaTransactionProcessor(address who) externalviewreturns(bool) {
return _metaTransactionContracts[who];
}
}
Contract Source Code
File 10 of 10: SuperOperators.sol
pragmasolidity ^0.5.2;import"./Admin.sol";
contractSuperOperatorsisAdmin{
mapping(address=>bool) internal _superOperators;
eventSuperOperator(address superOperator, bool enabled);
/// @notice Enable or disable the ability of `superOperator` to transfer tokens of all (superOperator rights)./// @param superOperator address that will be given/removed superOperator right./// @param enabled set whether the superOperator is enabled or disabled.functionsetSuperOperator(address superOperator, bool enabled) external{
require(
msg.sender== _admin,
"only admin is allowed to add super operators"
);
_superOperators[superOperator] = enabled;
emit SuperOperator(superOperator, enabled);
}
/// @notice check whether address `who` is given superOperator rights./// @param who The address to query./// @return whether the address has superOperator rights.functionisSuperOperator(address who) publicviewreturns (bool) {
return _superOperators[who];
}
}