Skip to content

Commit

Permalink
Merge pull request #13 from Mint-Gold-Dust/test/redeeming-l2-vouchers…
Browse files Browse the repository at this point in the history
…-to-ethereum

Test/redeeming l2 vouchers to ethereum
  • Loading branch information
0xdcota authored Jan 31, 2024
2 parents 749197f + 93f4203 commit e52d139
Show file tree
Hide file tree
Showing 12 changed files with 855 additions and 114 deletions.
47 changes: 32 additions & 15 deletions src/MgdERC1155PermitEscrowable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
IERC1155Upgradeable
} from "@openzeppelin/contracts-upgradeable/token/ERC1155/ERC1155Upgradeable.sol";
import {IERC1271} from "@openzeppelin/contracts/interfaces/IERC1271.sol";
import {Counters} from "@openzeppelin/contracts/utils/Counters.sol";
import {MgdL1MarketData} from "./voucher/VoucherDataTypes.sol";
import {MgdCompanyL2Sync, ICrossDomainMessenger} from "./MgdCompanyL2Sync.sol";
import {MintGoldDustMarketplace} from "mgd-v2-contracts/marketplace/MintGoldDustMarketplace.sol";
Expand All @@ -23,6 +24,8 @@ import {MintGoldDustERC1155} from "mgd-v2-contracts/marketplace/MintGoldDustERC1
* https://github.com/Mint-Gold-Dust/v2-contracts
*/
contract MgdERC1155PermitEscrowable is MintGoldDustERC1155, ERC1155Permit {
using Counters for Counters.Counter;

// Events
/**
* @dev Emit when `escrow` address is set.
Expand Down Expand Up @@ -147,28 +150,43 @@ contract MgdERC1155PermitEscrowable is MintGoldDustERC1155, ERC1155Permit {
permit(owner, operator, tokenId, amount, deadline, v, r, s);
}

function updateMarketData(
uint256 tokenId,
function mintFromL2Native(
address receiver,
uint256 amount,
MgdL1MarketData calldata marketData,
bool isL2Native
string calldata tokenURI,
bytes calldata memoir
)
external
returns (uint256 newTokenId)
{
if (msg.sender != escrow) {
revert MgdERC1155PermitEscrowable__onlyEscrow_notAllowed();
}
if (isL2Native) {
tokenIdArtist[tokenId] = marketData.artist;
if (marketData.hasCollabs) {
hasTokenCollaborators[tokenId] = marketData.hasCollabs;
tokenIdCollaboratorsQuantity[tokenId] = marketData.collabsQuantity;
tokenCollaborators[tokenId] = marketData.collabs;
tokenIdCollaboratorsPercentage[tokenId] = marketData.collabsPercentage;
}
_tokenIds.increment();
newTokenId = _tokenIds.current();
_mint(receiver, newTokenId, amount, "");
_setURI(newTokenId, tokenURI);
tokenIdRoyaltyPercent[newTokenId] = marketData.royaltyPercent;
tokenIdMemoir[newTokenId] = memoir;
tokenIdArtist[newTokenId] = marketData.artist;
_tokenWasSold[newTokenId] = marketData.tokenWasSold;
_primarySaleQuantityToSell[newTokenId] += marketData.primarySaleL2QuantityToSell;
if (marketData.hasCollabs) {
hasTokenCollaborators[newTokenId] = marketData.hasCollabs;
tokenIdCollaboratorsQuantity[newTokenId] = marketData.collabsQuantity;
tokenCollaborators[newTokenId] = marketData.collabs;
tokenIdCollaboratorsPercentage[newTokenId] = marketData.collabsPercentage;
}
emit EscrowUpdateMarketData(newTokenId, marketData);
}

function updateMarketData(uint256 tokenId, MgdL1MarketData calldata marketData) external {
if (msg.sender != escrow) {
revert MgdERC1155PermitEscrowable__onlyEscrow_notAllowed();
}
_tokenWasSold[tokenId] = marketData.tokenWasSold;
_primarySaleQuantityToSell[tokenId] += marketData.primarySaleL2QuantityToSell;

emit EscrowUpdateMarketData(tokenId, marketData);
}

Expand Down Expand Up @@ -228,9 +246,8 @@ contract MgdERC1155PermitEscrowable is MintGoldDustERC1155, ERC1155Permit {
returns (uint40 primarySaleToCarry)
{
uint40 primarySaleRemaining = _safeCastToUint40(_primarySaleQuantityToSell[tokenId]);
primarySaleToCarry = primarySaleRemaining >= amountToEscrow
? primarySaleRemaining - amountToEscrow
: primarySaleRemaining;
primarySaleToCarry =
primarySaleRemaining >= amountToEscrow ? amountToEscrow : primarySaleRemaining;
}

function _safeCastToUint40(uint256 value) internal pure returns (uint40) {
Expand Down
88 changes: 59 additions & 29 deletions src/MgdERC721PermitEscrowable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
ERC721Upgradeable,
IERC721Upgradeable
} from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol";
import {Counters} from "@openzeppelin/contracts/utils/Counters.sol";
import {IERC1271} from "@openzeppelin/contracts/interfaces/IERC1271.sol";
import {MgdL1MarketData} from "./voucher/VoucherDataTypes.sol";
import {MintGoldDustERC721} from "mgd-v2-contracts/marketplace/MintGoldDustERC721.sol";
Expand All @@ -22,6 +23,8 @@ import {MintGoldDustMarketplace} from "mgd-v2-contracts/marketplace/MintGoldDust
* https://github.com/Mint-Gold-Dust/v2-contracts
*/
contract MgdERC721PermitEscrowable is MintGoldDustERC721, ERC721Permit {
using Counters for Counters.Counter;

/// Events
/**
* @dev Emit when `escrow` address is set.
Expand All @@ -44,6 +47,33 @@ contract MgdERC721PermitEscrowable is MintGoldDustERC721, ERC721Permit {
*/
uint256[50] private __gap;

/// @dev Overriden to route to `safeTransferFrom` without `data` in order to handle escrowing with proper `data`.
function transfer(
address from,
address to,
uint256 tokenId,
uint256
)
public
override
nonReentrant
{
safeTransferFrom(from, to, tokenId);
}

/// @dev Overriden to include `data` from `_getTokenIdData` to send when sending to `escrow` address.
/// @dev CAUTION! If sending to `escrow`, ensure the `from` address is an accesible acount in L2.
function transferFrom(
address from,
address to,
uint256 tokenId
)
public
override(ERC721Upgradeable, IERC721Upgradeable)
{
safeTransferFrom(from, to, tokenId);
}

/// @dev Overriden to include `data` from `_getTokenIdData` to send when sending to `escrow` address.
/// @dev CAUTION! If sending to `escrow`, ensure the `from` address is an accesible acount in L2.
function safeTransferFrom(
Expand All @@ -62,20 +92,6 @@ contract MgdERC721PermitEscrowable is MintGoldDustERC721, ERC721Permit {
safeTransferFrom(from, to, tokenId, data);
}

/// @dev Overriden to route to `safeTransferFrom` without `data` in order to handle escrowing with proper `data`.
function transfer(
address _from,
address _to,
uint256 _tokenId,
uint256
)
public
override
nonReentrant
{
safeTransferFrom(_from, _to, _tokenId);
}

/**
*
* @param spender of this allowance
Expand Down Expand Up @@ -142,28 +158,43 @@ contract MgdERC721PermitEscrowable is MintGoldDustERC721, ERC721Permit {
permit(spender, tokenId, deadline, v, r, s);
}

function updateMarketData(
uint256 tokenId,
function mintFromL2Native(
address receiver,
uint256, /* amount */
MgdL1MarketData calldata marketData,
bool isL2Native
string calldata tokenURI,
bytes calldata memoir
)
external
returns (uint256 newTokenId)
{
if (msg.sender != escrow) {
revert MgdERC721PermitEscrowable__onlyEscrow_notAllowed();
}
if (isL2Native) {
tokenIdArtist[tokenId] = marketData.artist;
if (marketData.hasCollabs) {
hasTokenCollaborators[tokenId] = marketData.hasCollabs;
tokenIdCollaboratorsQuantity[tokenId] = marketData.collabsQuantity;
tokenCollaborators[tokenId] = marketData.collabs;
tokenIdCollaboratorsPercentage[tokenId] = marketData.collabsPercentage;
}
_tokenIds.increment();
newTokenId = _tokenIds.current();
_safeMint(receiver, newTokenId);
_setTokenURI(newTokenId, tokenURI);
tokenIdRoyaltyPercent[newTokenId] = marketData.royaltyPercent;
tokenIdMemoir[newTokenId] = memoir;
tokenIdArtist[newTokenId] = marketData.artist;
_tokenWasSold[newTokenId] = marketData.tokenWasSold;
_primarySaleQuantityToSell[newTokenId] += marketData.primarySaleL2QuantityToSell;
if (marketData.hasCollabs) {
hasTokenCollaborators[newTokenId] = marketData.hasCollabs;
tokenIdCollaboratorsQuantity[newTokenId] = marketData.collabsQuantity;
tokenCollaborators[newTokenId] = marketData.collabs;
tokenIdCollaboratorsPercentage[newTokenId] = marketData.collabsPercentage;
}
emit EscrowUpdateMarketData(newTokenId, marketData);
}

function updateMarketData(uint256 tokenId, MgdL1MarketData calldata marketData) external {
if (msg.sender != escrow) {
revert MgdERC721PermitEscrowable__onlyEscrow_notAllowed();
}
_tokenWasSold[tokenId] = marketData.tokenWasSold;
_primarySaleQuantityToSell[tokenId] += marketData.primarySaleL2QuantityToSell;

emit EscrowUpdateMarketData(tokenId, marketData);
}

Expand Down Expand Up @@ -212,9 +243,8 @@ contract MgdERC721PermitEscrowable is MintGoldDustERC721, ERC721Permit {
returns (uint40 primarySaleToCarry)
{
uint40 primarySaleRemaining = _safeCastToUint40(_primarySaleQuantityToSell[tokenId]);
primarySaleToCarry = primarySaleRemaining >= amountToEscrow
? primarySaleRemaining - amountToEscrow
: primarySaleRemaining;
primarySaleToCarry =
primarySaleRemaining >= amountToEscrow ? amountToEscrow : primarySaleRemaining;
}

function _safeCastToUint40(uint256 value) internal pure returns (uint40) {
Expand Down
24 changes: 13 additions & 11 deletions src/MgdL2NFTEscrow.sol
Original file line number Diff line number Diff line change
Expand Up @@ -164,19 +164,20 @@ contract MgdL2NFTEscrow is Initializable, IERC721Receiver, IERC1155Receiver {
/// @notice Releases NFT from escrow to owner.
/// @param voucherId used while in L2
/// @param nft contract address of NFT to release
/// @param tokenId of NFT to release
/// @param tokenId of NFT to release
/// @param amount of editions of NFT to release
/// @param owner who will receive NFT
/// @param receiver who will receive NFT
/// @param blockHash when {MgdL2NFTVoucher.redeemVoucherToL1(...)} was called in L2
/// @param marketData latest status when {MgdL2NFTVoucher.redeemVoucherToL1(...)} was called in L2
/// @param tokenURI ?required only when releasing a L2 natively created voucher
/// @param memoir ?optional only when releasing a L2 natively created voucher (suggest to use the same as L2)
/// @dev For L2 natively created vouchers, the `tokenId` must be `_REF_NUMBER` and a `tokenURI` must be passed.
function releaseFromEscrow(
uint256 voucherId,
address nft,
uint256 tokenId,
uint256 amount,
address owner,
address receiver,
bytes32 blockHash,
MgdL1MarketData calldata marketData,
string calldata tokenURI,
Expand All @@ -185,22 +186,23 @@ contract MgdL2NFTEscrow is Initializable, IERC721Receiver, IERC1155Receiver {
external
{
uint256 key =
_generateL1RedeemKey(voucherId, nft, tokenId, amount, owner, blockHash, marketData);
_generateL1RedeemKey(voucherId, nft, tokenId, amount, receiver, blockHash, marketData);
if (!redeemClearance[key]) {
revert MgdL2NFTEscrow__releaseFromEscrow_notClearedOrAlreadyReleased();
}
uint256 newTokenId;
if (tokenId == _REF_NUMBER) {
require(bytes(tokenURI).length > 0, "pass tokenURI");
newTokenId = IEscrowableNFT(nft).mintNft(tokenURI, marketData.royaltyPercent, amount, memoir);
newTokenId =
IEscrowableNFT(nft).mintFromL2Native(receiver, amount, marketData, tokenURI, memoir);
}
if (newTokenId > 0) {
IEscrowableNFT(nft).transfer(address(this), owner, newTokenId, amount);
IEscrowableNFT(nft).updateMarketData(newTokenId, marketData, true);
} else {
IEscrowableNFT(nft).transfer(address(this), owner, tokenId, amount);
IEscrowableNFT(nft).updateMarketData(tokenId, marketData, false);
if (newTokenId == 0) {
IEscrowableNFT(nft).transfer(address(this), receiver, tokenId, amount);
IEscrowableNFT(nft).updateMarketData(tokenId, marketData);
}
emit ReleasedEscrow(
receiver, nft, tokenId == _REF_NUMBER ? newTokenId : tokenId, amount, voucherId, key
);
}

function onERC721Received(
Expand Down
17 changes: 6 additions & 11 deletions src/interfaces/IEscrowableNFT.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,15 @@ interface IEscrowableNFT {

function transfer(address from, address to, uint256 tokenId, uint256 amount) external;

function updateMarketData(
uint256 tokenId,
MgdL1MarketData calldata marketData,
bool isL2Native
)
external;
function updateMarketData(uint256 tokenId, MgdL1MarketData calldata marketData) external;

function mintNft(
string calldata tokenURI,
uint256 royaltyPercent,
function mintFromL2Native(
address receiver,
uint256 amount,
MgdL1MarketData calldata marketData,
string calldata tokenURI,
bytes calldata memoir
)
external
payable
returns (uint256);
returns (uint256 newTokenId);
}
16 changes: 16 additions & 0 deletions src/utils/Almost1155Upgradeable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ contract Almost1155Upgradeable {
// Mapping from account to operator approvals
mapping(address => mapping(address => bool)) private _operatorApprovals;

// Mapping from token ID to totalSupply
mapping(uint256 => uint256) private _totalSupply;

/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
Expand Down Expand Up @@ -103,6 +106,14 @@ contract Almost1155Upgradeable {
return batchBalances;
}

/**
* @dev Returns the total supply of token `id`
* @param id to get supply
*/
function totalSupply(uint256 id) public view virtual returns (uint256) {
return _totalSupply[id];
}

/**
* @dev See {IERC1155-setApprovalForAll}.
*/
Expand Down Expand Up @@ -268,6 +279,8 @@ contract Almost1155Upgradeable {
_beforeTokenTransfer(operator, address(0), to, ids, amounts, data);

_balances[id][to] += amount;
_totalSupply[id] += amount;

emit TransferSingle(operator, address(0), to, id, amount);

_afterTokenTransfer(operator, address(0), to, ids, amounts, data);
Expand Down Expand Up @@ -304,6 +317,7 @@ contract Almost1155Upgradeable {

for (uint256 i = 0; i < ids.length; i++) {
_balances[ids[i]][to] += amounts[i];
_totalSupply[ids[i]] += amounts[i];
}

emit TransferBatch(operator, address(0), to, ids, amounts);
Expand Down Expand Up @@ -336,6 +350,7 @@ contract Almost1155Upgradeable {
require(fromBalance >= amount, "ERC1155: burn amount exceeds balance");
unchecked {
_balances[id][from] = fromBalance - amount;
_totalSupply[id] -= amount;
}

emit TransferSingle(operator, from, address(0), id, amount);
Expand Down Expand Up @@ -375,6 +390,7 @@ contract Almost1155Upgradeable {
require(fromBalance >= amount, "ERC1155: burn amount exceeds balance");
unchecked {
_balances[id][from] = fromBalance - amount;
_totalSupply[id] -= amount;
}
}

Expand Down
Loading

0 comments on commit e52d139

Please sign in to comment.