Skip to content

Instantly share code, notes, and snippets.

@andy8052
Created September 13, 2018 03:12
Show Gist options
  • Save andy8052/f31b4ea8e77aae4811fb8683d6662674 to your computer and use it in GitHub Desktop.
Save andy8052/f31b4ea8e77aae4811fb8683d6662674 to your computer and use it in GitHub Desktop.
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