Skip to content

Commit

Permalink
inital commit of ERC1155 contracts
Browse files Browse the repository at this point in the history
  • Loading branch information
cblanquera committed Aug 1, 2021
1 parent 470a3f4 commit aa786cb
Show file tree
Hide file tree
Showing 16 changed files with 1,855 additions and 8 deletions.
63 changes: 63 additions & 0 deletions contracts/token/ERC1155/ERC1155AirDrop.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

//custom abstract implementation of ERC1155
//used to configure zero trust air drop scenario
import "./extensions/ERC1155AirDroppable.sol";

//custom abstract extension of ERC1155
//used to list tokens for sale and set royalties
import "./extensions/ERC1155ExchangableFees.sol";

contract ERC1155AirDrop is
ERC1155AirDroppable,
ERC1155ExchangableFees
{
//in only the contract owner can add a fee
address owner;

modifier onlyContractOwner {
require(
msg.sender == owner,
'Restricted method access to only the contract owner'
);
_;
}

/**
* @dev Constructor function
*/
constructor (string memory _uri) ERC1155(_uri) {
owner = msg.sender;
}

/**
* @dev Only the contract owner can airdrop a token
*/
function drop(uint256 tokenId, bytes32 merkleRoot) public onlyContractOwner {
_drop(tokenId, merkleRoot);
}

/**
* @dev Only the contract owner can add a fee
*/
function setFee(uint256 tokenId, address payable recipient, uint256 fee)
public
onlyContractOwner
{
_setFee(tokenId, recipient, fee);
}

/**
* @dev Only the contract owner can remove a fee
*/
function removeFee(uint256 tokenId, address payable recipient)
public
onlyContractOwner
{
_removeFee(tokenId, recipient);
}

//minting is disabled
}
66 changes: 66 additions & 0 deletions contracts/token/ERC1155/ERC1155Exchange.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

//custom abstract extension of ERC1155
//used to list tokens for sale and set royalties
import "./extensions/ERC1155ExchangableFees.sol";

contract ERC1155Exchange is ERC1155ExchangableFees {
//in only the contract owner can add a fee
address owner;

modifier onlyContractOwner {
require(msg.sender == owner, 'Restricted method access to only the contract owner');
_;
}

/**
* @dev Constructor function
*/
constructor (string memory _uri) ERC1155(_uri) {
owner = msg.sender;
}

/**
* @dev Only the contract owner can add a fee
*/
function setFee(uint256 tokenId, address payable recipient, uint256 fee)
public
onlyContractOwner
{
_setFee(tokenId, recipient, fee);
}

/**
* @dev Only the contract owner can remove a fee
*/
function removeFee(uint256 tokenId, address payable recipient)
public
onlyContractOwner
{
_removeFee(tokenId, recipient);
}

/**
* @dev Creates `quantity` new tokens for `to`, of token type `id`.
*/
function mint(address to, uint256 id, uint256 quantity, bytes memory data)
public
virtual
{
_mint(to, id, quantity, data);
}

/**
* @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] variant of {mint}.
*/
function mintBatch(
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) public virtual {
_mintBatch(to, ids, amounts, data);
}
}
43 changes: 43 additions & 0 deletions contracts/token/ERC1155/extensions/ERC1155AirDroppable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

//implementation of ERC1155
import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";

//crypto logic for merkle trees
import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";

abstract contract ERC1155AirDroppable is ERC1155 {
//token id -> merkle roots
mapping(uint256 => bytes32) private _merkleRoots;

function _drop(uint256 tokenId, bytes32 merkleRoot) internal {
//use logic to make it immutable
require(_merkleRoots[tokenId] == 0, "Merkle root is immutable");
_merkleRoots[tokenId] = merkleRoot;
}

/**
* @dev Allows recipients to generally redeem their token
*/
function redeem(
address recipient,
uint256 tokenId,
uint256 quantity,
bytes32[] calldata proof,
bytes memory data
) external {
require(
//this verifies that the recipient owns this token
MerkleProof.verify(
proof,
_merkleRoots[tokenId],
//this is the leaf hash
keccak256(abi.encodePacked(recipient, tokenId, quantity))
),
"Recipient does not own this token"
);
_mint(recipient, tokenId, quantity, data);
}
}
57 changes: 57 additions & 0 deletions contracts/token/ERC1155/extensions/ERC1155Exchangable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

//custom abstract implementation of ERC1155
import "./ERC1155Listable.sol";

abstract contract ERC1155Exchangable is ERC1155Listable {
/**
* @dev Allows for a sender to avail of the offer price
*/
function exchange(
address owner,
uint256 tokenId,
uint256 quantity,
bytes memory data
) public payable {
//get listing
uint256 listingAmount = _listingAmounts[tokenId][owner];
//get quantity
uint256 listingQuantity = _listingQuantities[tokenId][owner];
//should be a valid listing
require(
listingAmount > 0 && listingQuantity > 0,
'Owner token is not listed'
);
//quantity should be lte to the listing quantity
require(
quantity <= listingQuantity,
'Quantity is more than what was listed'
);
//value should equal the listing amount
require(
msg.value == (listingAmount * quantity),
"Amount sent does not match the listing amount"
);
//get the token owner
address payable tokenOwner = payable(owner);

//distribute payment to the token owner ...
tokenOwner.transfer(msg.value);
//transfer token
_safeTransferFrom(owner, msg.sender, tokenId, quantity, data);

//if no more available
if (quantity == listingQuantity) {
//delist
delete _listingAmounts[tokenId][owner];
delete _listingQuantities[tokenId][owner];
//emit that something was delisted
emit Delisted(owner, tokenId);
} else {
//otherwise, adjust the quantity
_listingQuantities[tokenId][owner] -= quantity;
}
}
}
70 changes: 70 additions & 0 deletions contracts/token/ERC1155/extensions/ERC1155ExchangableFees.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

//custom abstract implementation of ERC721
import "./ERC1155TransferFees.sol";

//custom abstract implementation of ERC1155
import "./ERC1155Listable.sol";

abstract contract ERC1155ExchangableFees is ERC1155TransferFees, ERC1155Listable {
/**
* @dev Allows for a sender to avail of the offer price
*/
function exchange(
address owner,
uint256 tokenId,
uint256 quantity,
bytes memory data
) public payable {
//get listing
uint256 listingAmount = _listingAmounts[tokenId][owner];
//get quantity
uint256 listingQuantity = _listingQuantities[tokenId][owner];
//should be a valid listing
require(
listingAmount > 0 && listingQuantity > 0,
'Owner token is not listed'
);
//quantity should be lte to the listing quantity
require(
quantity <= listingQuantity,
'Quantity is more than what was listed'
);
//value should equal the listing amount
require(
msg.value == (listingAmount * quantity),
"Amount sent does not match the listing amount"
);

//release payments to recipients
for (uint i = 0; i < _recipients[tokenId].length; i++) {
// (10 eth * 2000) / 10000 =
payable(_recipients[tokenId][i]).transfer(
(msg.value * _fees[tokenId][_recipients[tokenId][i]]) / TOTAL_ALLOWABLE_FEES
);
}

//get the token owner
address payable tokenOwner = payable(owner);
//determine the remaining fee
uint256 remainingFee = TOTAL_ALLOWABLE_FEES - _totalFees[tokenId];
//send the remaining fee to the token owner
tokenOwner.transfer((msg.value * remainingFee) / TOTAL_ALLOWABLE_FEES);
//transfer token
_safeTransferFrom(owner, msg.sender, tokenId, quantity, data);

//if no more available
if (quantity == listingQuantity) {
//delist
delete _listingAmounts[tokenId][owner];
delete _listingQuantities[tokenId][owner];
//emit that something was delisted
emit Delisted(owner, tokenId);
} else {
//otherwise, adjust the quantity
_listingQuantities[tokenId][owner] -= quantity;
}
}
}
84 changes: 84 additions & 0 deletions contracts/token/ERC1155/extensions/ERC1155Listable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

//implementation of ERC1155
import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";

abstract contract ERC1155Listable is ERC1155 {
//allow others to watch for listed tokens
event Listed(
address indexed owner,
uint256 indexed tokenId,
uint256[2] indexed listing
);
//allow others to watch for delisted tokens
event Delisted(address indexed owner, uint256 indexed tokenId);

//map for all listings
//token id -> recipient -> amount
mapping(uint256 => mapping(address => uint256)) internal _listingAmounts;

//map for all listings
//token id -> recipient -> quantity
mapping(uint256 => mapping(address => uint256)) internal _listingQuantities;

struct Listing {
address owner;
uint256 tokenId;
uint256 amount;
uint256 quantity;
}

/**
* @dev Allows token owners to list their tokens for sale
*/
function list(uint256 tokenId, uint256 amount, uint256 quantity) public {
uint256 balance = balanceOf(msg.sender, tokenId);
//error if the sender is not the owner
// even the contract owner cannot list a token
require(balance > 0, "Only the token owner can list a token");
//error if the balance is less than the quantity to be listed
require(quantity <= balance, "Token owner listing more than available");
//add the listing
//if the listing exists, update
_listingAmounts[tokenId][msg.sender] = amount;
_listingQuantities[tokenId][msg.sender] = quantity;

//emit that something was listed
emit Listed(msg.sender, tokenId, [amount, quantity]);
}

/**
* @dev Allows token owners to remove their token sale listing
*/
function delist(uint256 tokenId) public {
//error if the sender is not the owner
// even the contract owner cannot delist a token
require(
balanceOf(msg.sender, tokenId) > 0,
"Only the token owner can delist a token"
);
//remove the listing
delete _listingAmounts[tokenId][msg.sender];
delete _listingQuantities[tokenId][msg.sender];
//emit that something was delisted
emit Delisted(msg.sender, tokenId);
}

/**
* @dev Returns the amount being sold for
*/
function getListing(address owner, uint256 tokenId)
public
view
returns(Listing memory)
{
return Listing(
owner,
tokenId,
_listingAmounts[tokenId][msg.sender],
_listingQuantities[tokenId][msg.sender]
);
}
}
Loading

0 comments on commit aa786cb

Please sign in to comment.