Created
December 15, 2020 17:27
-
-
Save genecyber/5788f68ac37f425e165182c267d60ae7 to your computer and use it in GitHub Desktop.
Upgradable NFT Trading contract Set
This file contains hidden or 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.8; | |
import "./Resolver.sol"; | |
contract EtherRouter { | |
Resolver resolver; | |
function EtherRouter(Resolver _resolver) { | |
resolver = _resolver; | |
} | |
function() payable { | |
uint r; | |
// Get routing information for the called function | |
var (destination, outsize) = resolver.lookup(msg.sig, msg.data); | |
// Make the call | |
assembly { | |
calldatacopy(mload(0x40), 0, calldatasize) | |
r := delegatecall(sub(gas, 700), destination, mload(0x40), calldatasize, mload(0x40), outsize) | |
} | |
// Throw if the call failed | |
if (r != 1) { throw;} | |
// Pass on the return value | |
assembly { | |
return(mload(0x40), outsize) | |
} | |
} | |
} |
This file contains hidden or 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
// SPDX-License-Identifier: MIT | |
pragma experimental ABIEncoderV2; | |
pragma solidity ^0.6.12; | |
import "./SafeMath.sol"; | |
interface IERC20Token { | |
function transfer(address to, uint256 value) external returns (bool); | |
function approve(address spender, uint256 value) external returns (bool); | |
function transferFrom(address from, address to, uint256 value) external returns (bool); | |
function totalSupply() external view returns (uint256); | |
function balanceOf(address who) external view returns (uint256); | |
function allowance(address owner, address spender) external view returns (uint256); | |
event Transfer(address indexed from, address indexed to, uint256 value); | |
event Approval(address indexed owner, address indexed spender, uint256 value); | |
} | |
interface IERC721 { | |
function burn(uint256 tokenId) external; | |
function transferFrom(address from, address to, uint256 tokenId) external; | |
function mint( address _to, uint256 _tokenId, string calldata _uri, string calldata _payload) external; | |
function ownerOf(uint256 _tokenId) external returns (address _owner); | |
function getApproved(uint256 _tokenId) external returns (address); | |
function safeTransferFrom(address _from, address _to, uint256 _tokenId) external; | |
} | |
interface BasicERC20 { | |
function burn(uint256 value) external; | |
function mint(address account, uint256 amount) external; | |
function decimals() external view returns (uint8); | |
} | |
contract NFTrade { | |
address resolver; | |
address payable private owner; | |
bool public initialized; | |
address public nftAddress; | |
address public paymentAddress; | |
address public recipientAddress; | |
uint256 public offerPrice = 0; | |
bool public payToAcceptOffer = false; | |
bool public payToMakeOffer = false; | |
bool public locked = false; | |
struct Offer { | |
uint tokenId; | |
address _from; | |
} | |
// event for EVM logging | |
event OwnerSet(address indexed oldOwner, address indexed newOwner); | |
mapping(uint => Offer[]) offers; | |
mapping(uint => Offer[]) rejected; | |
mapping(address => mapping(uint => Offer[])) offered; | |
mapping(uint => Offer[]) accepted; | |
modifier isOwner() { | |
// If the first argument of 'require' evaluates to 'false', execution terminates and all | |
// changes to the state and to Ether balances are reverted. | |
// This used to consume all gas in old EVM versions, but not anymore. | |
// It is often a good idea to use 'require' to check if functions are called correctly. | |
// As a second argument, you can also provide an explanation about what went wrong. | |
require(msg.sender == owner, "Caller is not owner"); | |
_; | |
} | |
modifier notLocked() { | |
require(!locked, "Contract is locked"); | |
_; | |
} | |
constructor() public { | |
} | |
function init(address _nftAddress, address _paymentAddress, address _recipientAddress) public { | |
require(!initialized, 'Already initialized'); | |
initialized = true; | |
owner = msg.sender; // 'msg.sender' is sender of current call, contract deployer for a constructor | |
emit OwnerSet(address(0), owner); | |
nftAddress = _nftAddress; | |
paymentAddress = _paymentAddress; | |
recipientAddress = _recipientAddress; | |
} | |
function getVersion() public pure returns (uint) { | |
return 1; | |
} | |
/** | |
* @dev Change owner | |
* @param newOwner address of new owner | |
*/ | |
function transferOwnership(address payable newOwner) public isOwner { | |
emit OwnerSet(owner, newOwner); | |
owner = newOwner; | |
} | |
/** | |
* @dev Return owner address | |
* @return address of owner | |
*/ | |
function getOwner() external view returns (address) { | |
return owner; | |
} | |
function acceptOffer(uint _tokenId, uint index) public notLocked { | |
Offer memory _offer = offers[_tokenId][index]; | |
IERC721 nftToken = IERC721(nftAddress); | |
IERC20Token paymentToken = IERC20Token(paymentAddress); | |
require(nftToken.ownerOf(_tokenId) == msg.sender,'Sender is not owner of NFT'); | |
require(nftToken.ownerOf(_offer.tokenId) == _offer._from, 'NFT not owned by offerer'); | |
require(nftToken.getApproved(_offer.tokenId) == address(this), 'Handler unable to transfer offer NFT'); | |
require(nftToken.getApproved(_tokenId) == address(this), 'Handler unable to transfer NFT'); | |
if (offerPrice > 0 && payToAcceptOffer) { | |
require(paymentToken.allowance(msg.sender, address(this)) >= offerPrice, 'Handler unable take payment for offer'); | |
require(paymentToken.balanceOf(msg.sender) >= offerPrice, 'Insufficient Balance for payment'); | |
require(paymentToken.transferFrom(msg.sender, address(recipientAddress), offerPrice), 'Payment error'); | |
} | |
nftToken.safeTransferFrom(_offer._from, msg.sender, _offer.tokenId); | |
nftToken.safeTransferFrom(msg.sender, _offer._from, _tokenId); | |
delete offers[_tokenId]; | |
delete offered[_offer._from][_offer.tokenId]; | |
accepted[_tokenId].push(_offer); | |
} | |
function addOffer(uint256 _tokenId, uint256 _for) public notLocked { | |
IERC721 nftToken = IERC721(nftAddress); | |
IERC20Token paymentToken = IERC20Token(paymentAddress); | |
require(nftToken.ownerOf(_tokenId) == msg.sender, 'Sender not owner of NFT'); | |
require(nftToken.getApproved(_tokenId) == address(this), 'Handler unable to transfer NFT'); | |
if (offerPrice > 0 && payToMakeOffer) { | |
require(paymentToken.allowance(msg.sender, address(this)) >= offerPrice, 'Handler unable take payment for offer'); | |
require(paymentToken.balanceOf(msg.sender) >= offerPrice, 'Insufficient Balance for payment'); | |
require(paymentToken.transferFrom(msg.sender, address(recipientAddress), offerPrice), 'Payment error'); | |
} | |
offers[_for].push(Offer(_tokenId, msg.sender)); | |
offered[msg.sender][_tokenId].push(Offer(_for, msg.sender)); | |
} | |
function rejectOffer(uint256 _tokenId, uint index) public notLocked { | |
Offer memory _offer = offers[_tokenId][index]; | |
IERC721 nftToken = IERC721(nftAddress); | |
require(nftToken.ownerOf(_tokenId) == msg.sender,'Sender is not owner of NFT'); | |
rejected[_tokenId].push(_offer); | |
delete offers[_tokenId][index]; | |
delete offered[_offer._from][_offer.tokenId]; | |
} | |
function withdrawOffer(uint256 _tokenId, uint index) public notLocked { | |
Offer memory _offer = offers[_tokenId][index]; | |
IERC721 nftToken = IERC721(nftAddress); | |
require(nftToken.ownerOf(_offer.tokenId) == msg.sender,'Sender is not owner of offer NFT'); | |
delete offers[_tokenId][index]; | |
delete offered[_offer._from][_offer.tokenId]; | |
} | |
function togglePayToMakeOffer() public isOwner { | |
payToMakeOffer = !payToMakeOffer; | |
} | |
function togglePayToAcceptOffer() public isOwner { | |
payToAcceptOffer = !payToAcceptOffer; | |
} | |
function toggleLocked() public isOwner { | |
locked = !locked; | |
} | |
function getOffer(uint256 _tokenId, uint index) public view returns (Offer memory) { | |
return offers[_tokenId][index]; | |
} | |
function getOffered(uint256 _tokenId) public view returns (Offer[] memory) { | |
return offered[msg.sender][_tokenId]; | |
} | |
function getOfferCount(uint256 _tokenId) public view returns (uint) { | |
return offers[_tokenId].length; | |
} | |
function getAcceptedOffers(uint256 _tokenId) public view returns (Offer[] memory) { | |
return accepted[_tokenId]; | |
} | |
function getRejectedOffers(uint256 _tokenId) public view returns (Offer[] memory) { | |
return rejected[_tokenId]; | |
} | |
function changeOfferPrice(uint256 _price) public isOwner { | |
offerPrice = _price; | |
} | |
function changeRecipientAddress(address _recipientAddress) public isOwner { | |
recipientAddress = _recipientAddress; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment