Skip to content

Commit

Permalink
Merge pull request #14 from Mint-Gold-Dust/docs/review-and-clarificat…
Browse files Browse the repository at this point in the history
…ions

Docs/review and clarifications
  • Loading branch information
0xdcota authored Feb 5, 2024
2 parents e52d139 + 233e190 commit 9fe4d95
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 22 deletions.
136 changes: 127 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,149 @@
![Alt text](mgdlogo.png)

## Mint Gold Dust (MGD) L2 Smart Contracts Suite

**MGD is a decentralized NFT ecosystem built for artists and collectors.**

This repository contains the smart contracts that allow MGD to operate both in Ethereum and an Op-stack compatible layer 2 (such as [Base](https://base.org/) or [Optimism](https://www.optimism.io/)).
This repository contains the smart contracts that allow MGD to operate both in Ethereum and an Op-stack compatible layer 2 (such as [Base](https://base.org/) or [Optimism](https://www.optimism.io/)).

The smart contracts in this repository introduce the following high level functionality:

- **NFT Portability**: Bring your MGD NFTs from Ethereum to the L2 or viceverse via an escrow-voucher contract system.
- **L2 Usability**: Create, sell, or auction your art in more exciting and different ways, not to mention also affordable, by using the MGD L2 ecosystem.
- **Simpler Transferability**: Approve the sell, auction or transfer of your NFTs with the use of "permits" or signatures, instead of the current additional approval transaction.
- **NFT Portability**: Bring your MGD NFTs from Ethereum to the L2 or viceverse via an escrow-voucher contract system.
- **L2 Usability**: Create, sell, or auction your art in more exciting and different ways, not to mention also affordable, by using the MGD L2 ecosystem.
- **Simpler Transferability**: Approve the sell, auction or transfer of your NFTs with the use of "permits" or signatures, instead of the current additional approval transaction.

## Documentation

General statements
General statements

- These smart contracts are backward compatible (must be) with the MGD v2-core contracts.
- Ethereum is and will be MGD's ultimate layer of truth. This assures all our artists and collectors that their creations or collected art pieces will persist regardless of the direction any L2 takes in the future (including ceasing to exist).
- Ethereum is and will be MGD's ultimate layer of truth. This assures all our artists and collectors that their creations or collected art pieces will persist regardless of the direction any L2 takes in the future (including ceasing to exist).

## Audits

WIP

## Testing

WIP
```
forge test --via-ir
```

## Deploying

WIP
WIP

## User Flows

#### 1. <u>Entering into escrow</u>

A user enters into escrow by sending their MGD NFT (721 or 1155) to the escrow contract (MgdL2NFTEscrow.sol). You achieve this in several ways:
a) By making the user simply call any of the transfer functions from the NFT with the escrow contract as the destination or
b) by having the user sign an EIP712 message. The latter would be explained further in detail in another section.

Consequently, the "Transfer()" event is emitted from the corresponding nft contract, but in addition escrow contract emits:

```js
event EnterEscrow(
address nftcontract,
uint256 indexed tokenId,
uint256 amount,
address indexed owner,
bytes32 blockHash,
MgdL1MarketData marketData,
uint256 indexed voucherId
);
```

The `voucherId` is a unique identifier that will help create the representation of the NFT on the L2.

**NOTE** All the information on the `EnterEscrow(...)` event is needed to create the L2 voucher.
**NOTE** Only MGD nfts are currently supported for escrow, all others will revert.

#### 2. <u>Receiving clearance notice to mint voucher on L2</u>

Once a user enters a NFT into escrow, the L2-bridge system is responsible to send a message to the voucher contract on the L2 (either 721 or 1155 as applicable) to give "clearance" to create the specific `voucherId`.
This will result in the L2-bridge system calling the method "setL1NftMintClearance(uint256 voucherId, bool state)" in contracts either Mgd721L2Voucher.sol or Mgd1155Voucher.sol and to emit the following:

```js
event L1NftMintClearance(uint256 indexed voucherId, bool state);
```

#### 3. <u>Minting a voucher</u>

Once clearance is set, a user or anyone else can call the method function `mintVoucherFromL1Nft(...)` in the corresponding voucher contract (721 or 1155). This will emit:

```js
L1NftMinted(voucherId);
```

Alternatively, if it is a native L2 voucher (meaning that the user is creating a new NFT directly on the L2 that does not have an Ethereum nft representation yet) a user shall call `mintNft(...)` from either Mgd721L2Voucher.sol or Mgd1155Voucher.sol. This will emit the same event used in the MGD's v2-contracts:

```js
event MintGoldDustNFTMinted(
uint256 indexed voucherId,
string tokenURI,
address owner,
uint256 royalty,
uint256 amount,
bool isERC721,
uint256 collectorMintId,
bytes memoir
);
```

#### 4. <u>Starting the redeemption process</u>

At any point a user can decide to redeem their voucher and bring it to ethereum. This also applies to "L2 native vouchers". Which we can define them as a voucher that currently does not have an ethereum NFT representation.
To start the process a user will call the following method `redeemVoucherToL1(...)` from the applicable 721 or 1155 voucher contract.
**NOTE** The inputs for `redeemVoucherToL1` defer from the 721 and 1155 voucher contracts.
The voucher contract in L2 (either 721 or 1155) would then emit:

```js
event RedeemVoucher(
uint256 indexed voucherId,
address nft,
uint256 tokenId,
uint256 amount,
address indexed owner,
bytes32 blockHash,
MgdL1MarketData marketData,
uint256 indexed releaseKey
);
```

The `releaseKey` is a unique identifier that will help identify in the escrow contract what NFT can be released or created (in the case of a L2 native voucher).

**NOTE** All the information on the `RedeemVoucher(...)` event is needed to release the NFT from escrow on ethereum.

#### 5. <u>Receiving release clearance from the escrow</u>

The L2 bridge system receives a call when the redeemption process is started, and notifies the escrow contract on ethereum to give clearance for the `releaseKey` via the following method in the escrow contract: `setRedeemClearanceKey(uint256 key, bool state)`. Then the escrow contract emits:

```js
event RedeemClearanceKey(uint256 indexed key, bool state);

```

**NOTE** The process of releasing an NFT may take up to 7 days. However, MGD will explore ways to expedite such process.

#### 6. <u>Releasing from escrow</u>

Once clearance is given, the user can call in the escrow contract method `releaseFromEscrow(...)`. Then the escrow emits:

```js
event ReleasedEscrow(
address indexed receiver,
address nftcontract,
uint256 indexed tokenId,
uint256 amount,
uint256 indexed voucherId,
uint256 key
);
```

Within the same transaction the ethereum Mgd NFT contracts also emit an event indicating that the market data (mainly handling primary sales) has been updated:

```js
event EscrowUpdateMarketData(uint256 indexed tokenId, MgdL1MarketData marketData);
```
4 changes: 2 additions & 2 deletions src/voucher/Mgd721L2Voucher.sol
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ contract Mgd721L2Voucher is MgdL2BaseVoucher, ERC721Permit, Almost721Upgradeable
}

/// @inheritdoc MgdL2BaseVoucher
function mintL1Nft(
function mintVoucherFromL1Nft(
uint256 tokenId,
uint256, /*representedAmount*/
address owner,
Expand All @@ -107,7 +107,7 @@ contract Mgd721L2Voucher is MgdL2BaseVoucher, ERC721Permit, Almost721Upgradeable
public
override
{
return super.mintL1Nft(tokenId, 1, owner, blockHash, marketData);
return super.mintVoucherFromL1Nft(tokenId, 1, owner, blockHash, marketData);
}

/// @inheritdoc MgdL2BaseVoucher
Expand Down
2 changes: 1 addition & 1 deletion src/voucher/MgdL2BaseVoucher.sol
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ abstract contract MgdL2BaseVoucher is MgdL2BaseNFT {
/// @param owner of tokenId in `nft` contract in L1
/// @param blockHash when escrow tx occured
/// @param marketData params when escrow occured
function mintL1Nft(
function mintVoucherFromL1Nft(
uint256 tokenId,
uint256 representedAmount,
address owner,
Expand Down
16 changes: 8 additions & 8 deletions test/foundry/ReceivingL2EscrowNoticeTests.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ contract ReceivingL2EscrowNoticeTests is CommonSigners, BaseL2Constants, MgdTest
);
assertEq(l2voucher721.mintCleared(voucherId), true);

l2voucher721.mintL1Nft(tokenId, 1, Bob.addr, blockHash, marketData);
l2voucher721.mintVoucherFromL1Nft(tokenId, 1, Bob.addr, blockHash, marketData);

assertEq(l2voucher721.ownerOf(voucherId), Bob.addr);
assertEq(l2voucher721.mintCleared(voucherId), false);
Expand Down Expand Up @@ -313,7 +313,7 @@ contract ReceivingL2EscrowNoticeTests is CommonSigners, BaseL2Constants, MgdTest
);
assertEq(l2voucher1155.mintCleared(voucherId), true);

l2voucher1155.mintL1Nft(tokenId, amountToEscrow, Bob.addr, blockHash, marketData);
l2voucher1155.mintVoucherFromL1Nft(tokenId, amountToEscrow, Bob.addr, blockHash, marketData);

assertEq(l2voucher1155.balanceOf(Bob.addr, voucherId), amountToEscrow);
assertEq(l2voucher1155.mintCleared(voucherId), false);
Expand Down Expand Up @@ -351,10 +351,10 @@ contract ReceivingL2EscrowNoticeTests is CommonSigners, BaseL2Constants, MgdTest
CDMessenger(L2_CROSSDOMAIN_MESSENGER).relayMessage(
nonce, address(escrow), address(l2voucher721), 0, 1_000_000, message
);
l2voucher721.mintL1Nft(tokenId, 1, Bob.addr, blockHash, marketData);
l2voucher721.mintVoucherFromL1Nft(tokenId, 1, Bob.addr, blockHash, marketData);

vm.expectRevert(MgdL2BaseVoucher.MgdL2BaseVoucher__mintL1Nft_notClearedOrAlreadyMinted.selector);
l2voucher721.mintL1Nft(tokenId, 1, Bob.addr, blockHash, marketData);
l2voucher721.mintVoucherFromL1Nft(tokenId, 1, Bob.addr, blockHash, marketData);
}

function test_tryMintingVoucher1155AfterClearanceTwiceReverts() public {
Expand All @@ -375,10 +375,10 @@ contract ReceivingL2EscrowNoticeTests is CommonSigners, BaseL2Constants, MgdTest
CDMessenger(L2_CROSSDOMAIN_MESSENGER).relayMessage(
nonce, address(escrow), address(l2voucher1155), 0, 1_000_000, message
);
l2voucher1155.mintL1Nft(tokenId, amountToEscrow, Bob.addr, blockHash, marketData);
l2voucher1155.mintVoucherFromL1Nft(tokenId, amountToEscrow, Bob.addr, blockHash, marketData);

vm.expectRevert(MgdL2BaseVoucher.MgdL2BaseVoucher__mintL1Nft_notClearedOrAlreadyMinted.selector);
l2voucher1155.mintL1Nft(tokenId, amountToEscrow, Bob.addr, blockHash, marketData);
l2voucher1155.mintVoucherFromL1Nft(tokenId, amountToEscrow, Bob.addr, blockHash, marketData);
}

function test_minting721VoucherAfterClearanceEvent() public {
Expand All @@ -399,7 +399,7 @@ contract ReceivingL2EscrowNoticeTests is CommonSigners, BaseL2Constants, MgdTest

vm.expectEmit(true, false, false, true, address(l2voucher721));
emit L1NftMinted(voucherId);
l2voucher721.mintL1Nft(tokenId, 1, Bob.addr, blockHash, marketData);
l2voucher721.mintVoucherFromL1Nft(tokenId, 1, Bob.addr, blockHash, marketData);
}

function test_minting1155VoucherAfterClearanceEvent() public {
Expand All @@ -423,6 +423,6 @@ contract ReceivingL2EscrowNoticeTests is CommonSigners, BaseL2Constants, MgdTest

vm.expectEmit(true, false, false, true, address(l2voucher1155));
emit L1NftMinted(voucherId);
l2voucher1155.mintL1Nft(tokenId, amountToEscrow, Bob.addr, blockHash, marketData);
l2voucher1155.mintVoucherFromL1Nft(tokenId, amountToEscrow, Bob.addr, blockHash, marketData);
}
}
6 changes: 4 additions & 2 deletions test/foundry/RedeemingVouchersTests.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,10 @@ contract RedeemingVoucherTests is CommonSigners, BaseL2Constants, MgdTestConstan
l2voucher1155.setL1NftMintClearance(_1155VId, true);
vm.stopPrank();

l2voucher721.mintL1Nft(_721tokenId, 1, Bob.addr, blockHash721, marketData721);
l2voucher1155.mintL1Nft(_1155tokenId, _EDITIONS, Bob.addr, blockHash1155, marketData1155);
l2voucher721.mintVoucherFromL1Nft(_721tokenId, 1, Bob.addr, blockHash721, marketData721);
l2voucher1155.mintVoucherFromL1Nft(
_1155tokenId, _EDITIONS, Bob.addr, blockHash1155, marketData1155
);
}

function test_validateSetup() public {
Expand Down

0 comments on commit 9fe4d95

Please sign in to comment.