Created
September 13, 2018 03:12
-
-
Save andy8052/f31b4ea8e77aae4811fb8683d6662674 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.24; | |
import 'github.com/OpenZeppelin/zeppelin-solidity/contracts/token/ERC721/ERC721Full.sol'; | |
import "github.com/OpenZeppelin/zeppelin-solidity/contracts/ownership/Ownable.sol"; | |
contract KorroDAO is Ownable { | |
using SafeMath for uint; | |
mapping(uint => address) public tokenToOwner; | |
mapping(uint => uint) public tokenToOwnerTokensIndex; | |
mapping(address => uint[]) public ownerToTokens; | |
mapping(address => uint) public nonce; | |
mapping(address => uint) public memberIndex; | |
address[] members; | |
constructor() public {} | |
function newMember(address _member) public onlyOwner { | |
uint id = members.push(_member); | |
memberIndex[_member] = id; | |
emit NewMember(_member); | |
} | |
event NewMember(address); | |
// Now we wrap all functions | |
// We keep a registery of tokens to owners and require owner sig to move them | |
// wrapper for approve | |
function delegatedApprove(address _member, address _tokenContractAddress, address _to, uint256 _tokenId, uint8 v, bytes32 r, bytes32 s) public { | |
ERC721 tokenContract = ERC721(_tokenContractAddress); | |
require(tokenContract.ownerOf(_tokenId) == address(this)); | |
require(tokenToOwner[_tokenId] == _member); | |
require( | |
isSigned(_member, keccak256(abi.encodePacked(_to,_tokenId, nonce[_member])), v, r, s), | |
"Permission denied." | |
); | |
// up the nonce | |
nonce[_member]++; | |
tokenContract.approve(_to, _tokenId); | |
} | |
// wrapper for set approve for all | |
function delegatedSetApprovalForAll(address _member, address _tokenContractAddress, address _operator, bool _approval, uint8 v, bytes32 r, bytes32 s) public { | |
ERC721 tokenContract = ERC721(_tokenContractAddress); | |
require( | |
isSigned(_member, keccak256(abi.encodePacked(_operator,_approval, nonce[_member])), v, r, s), | |
"Permission denied." | |
); | |
// up the nonce | |
nonce[_member]++; | |
tokenContract.setApprovalForAll(_operator, _approval); | |
} | |
// wrapper for set approve for all | |
function delegatedTransferFrom(address _member, address _tokenContractAddress, address _to, uint256 _tokenId, uint8 v, bytes32 r, bytes32 s) public { | |
ERC721 tokenContract = ERC721(_tokenContractAddress); | |
require(tokenContract.ownerOf(_tokenId) == address(this)); | |
require(tokenToOwner[_tokenId] == _member); | |
require( | |
isSigned(_member, keccak256(abi.encodePacked(_to,_tokenId, nonce[_member])), v, r, s), | |
"Permission denied." | |
); | |
// up the nonce | |
nonce[_member]++; | |
tokenContract.transferFrom(_member, _to, _tokenId); | |
removeTokenFrom(_member, _tokenId); | |
} | |
// wrapper for set approve for all | |
function delegatedSafeTransferFrom(address _member, address _tokenContractAddress, address _to, uint256 _tokenId, uint8 v, bytes32 r, bytes32 s) public { | |
ERC721 tokenContract = ERC721(_tokenContractAddress); | |
require(tokenContract.ownerOf(_tokenId) == address(this)); | |
require(tokenToOwner[_tokenId] == _member); | |
require( | |
isSigned(_member, keccak256(abi.encodePacked(_to,_tokenId, nonce[_member])), v, r, s), | |
"Permission denied." | |
); | |
// up the nonce | |
nonce[_member]++; | |
tokenContract.safeTransferFrom(_member, _to, _tokenId); | |
removeTokenFrom(_member, _tokenId); | |
} | |
// wrapper for set approve for all | |
function delegatedSafeTransferFrom(address _member, address _tokenContractAddress, address _to, uint256 _tokenId, bytes32 _data, uint8 v, bytes32 r, bytes32 s) public { | |
ERC721 tokenContract = ERC721(_tokenContractAddress); | |
require(tokenContract.ownerOf(_tokenId) == address(this)); | |
require(tokenToOwner[_tokenId] == _member); | |
require( | |
isSigned(_member, keccak256(abi.encodePacked(_to,_tokenId, _data, nonce[_member])), v, r, s), | |
"Permission denied." | |
); | |
// up the nonce | |
nonce[_member]++; | |
tokenContract.safeTransferFrom(_member, _to, _tokenId); | |
removeTokenFrom(_member, _tokenId); | |
} | |
function onERC721Received(address operator, address from, uint256 tokenId, bytes data) public returns(bytes4) { | |
require(data.length == 20); | |
address member = bytesToAddress(data); | |
require(memberIndex[member] > 0); | |
ownerToTokens[member].push(tokenId); | |
tokenToOwner[tokenId] = member; | |
} | |
function bytesToAddress(bytes bys) private pure returns (address addr) { | |
assembly { | |
addr := mload(add(bys,20)) | |
} | |
} | |
function removeTokenFrom(address from, uint256 tokenId) internal { | |
require(tokenToOwner[tokenId] == from); | |
tokenToOwner[tokenId] = address(0); | |
// To prevent a gap in the array, we store the last token in the index of the token to delete, and | |
// then delete the last slot. | |
uint256 tokenIndex = tokenToOwnerTokensIndex[tokenId]; | |
uint256 lastTokenIndex = ownerToTokens[from].length.sub(1); | |
uint256 lastToken = ownerToTokens[from][lastTokenIndex]; | |
ownerToTokens[from][tokenIndex] = lastToken; | |
// This also deletes the contents at the last position of the array | |
ownerToTokens[from].length--; | |
// Note that this will handle single-element arrays. In that case, both tokenIndex and lastTokenIndex are going to | |
// be zero. Then we can make sure that we will remove tokenId from the ownedTokens list since we are first swapping | |
// the lastToken to the first position, and then dropping the element placed in the last position of the list | |
tokenToOwnerTokensIndex[tokenId] = 0; | |
tokenToOwnerTokensIndex[lastToken] = tokenIndex; | |
} | |
// Checks whether the provided (v, r, s) signature was created by the private key associated with _address | |
function isSigned(address _address, bytes32 messageHash, uint8 v, bytes32 r, bytes32 s) public pure returns (bool) { | |
return (_isSigned(_address, messageHash, v, r, s) || _isSignedPrefixed(_address, messageHash, v, r, s)); | |
} | |
// Checks unprefixed signatures | |
function _isSigned(address _address, bytes32 messageHash, uint8 v, bytes32 r, bytes32 s) | |
internal | |
pure | |
returns (bool) | |
{ | |
return ecrecover(messageHash, v, r, s) == _address; | |
} | |
// Checks prefixed signatures (e.g. those created with web3.eth.sign) | |
function _isSignedPrefixed(address _address, bytes32 messageHash, uint8 v, bytes32 r, bytes32 s) | |
internal | |
pure | |
returns (bool) | |
{ | |
bytes memory prefix = "\x19Ethereum Signed Message:\n32"; | |
bytes32 prefixedMessageHash = keccak256(abi.encodePacked(prefix, messageHash)); | |
return ecrecover(prefixedMessageHash, v, r, s) == _address; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment