Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add trait redemptions to ERC7498Redeemables #15

Merged
merged 18 commits into from
Nov 2, 2023
Merged
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
- name: Run Forge build
run: |
forge --version
forge build --sizes
forge build
id: build

- name: Run Forge tests
Expand Down
8 changes: 3 additions & 5 deletions script/DeployAndConfigure1155Receive.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@ import {Test} from "forge-std/Test.sol";
import {ItemType} from "seaport-types/src/lib/ConsiderationEnums.sol";
import {OfferItem, ConsiderationItem} from "seaport-types/src/lib/ConsiderationStructs.sol";
import {CampaignParams, CampaignRequirements} from "../src/lib/RedeemablesStructs.sol";
import {BURN_ADDRESS} from "../src/lib/RedeemablesConstants.sol";
import {ERC721RedemptionMintable} from "../src/extensions/ERC721RedemptionMintable.sol";
import {ERC721OwnerMintable} from "../src/test/ERC721OwnerMintable.sol";
import {ERC1155ShipyardRedeemableMintable} from "../src/extensions/ERC1155ShipyardRedeemableMintable.sol";

contract DeployAndConfigure1155Receive is Script, Test {
address constant _BURN_ADDRESS = 0x000000000000000000000000000000000000dEaD;

function run() external {
vm.startBroadcast();

Expand Down Expand Up @@ -51,7 +50,7 @@ contract DeployAndConfigure1155Receive is Script, Test {
identifierOrCriteria: 0,
startAmount: 1,
endAmount: 1,
recipient: payable(_BURN_ADDRESS)
recipient: payable(BURN_ADDRESS)
});

CampaignRequirements[] memory requirements = new CampaignRequirements[](
Expand All @@ -68,8 +67,7 @@ contract DeployAndConfigure1155Receive is Script, Test {
maxCampaignRedemptions: 1_000,
manager: msg.sender
});
uint256 campaignId =
receiveToken.createCampaign(params, "ipfs://QmQjubc6guHReNW5Es5ZrgDtJRwXk2Aia7BkVoLJGaCRqP");
receiveToken.createCampaign(params, "ipfs://QmQjubc6guHReNW5Es5ZrgDtJRwXk2Aia7BkVoLJGaCRqP");

// To test updateCampaign, update to proper start/end times.
params.startTime = uint32(block.timestamp);
Expand Down
5 changes: 2 additions & 3 deletions script/DeployAndConfigureExampleCampaign.s.sol.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {ItemType} from "seaport-types/src/lib/ConsiderationEnums.sol";
import {OfferItem, ConsiderationItem} from "seaport-types/src/lib/ConsiderationStructs.sol";
import {RedeemableContractOfferer} from "../src/RedeemableContractOfferer.sol";
import {CampaignParams} from "../src/lib/RedeemablesStructs.sol";
import {BURN_ADDRESS} from "../src/lib/RedeemablesConstants.sol";
import {ERC721RedemptionMintable} from "../src/extensions/ERC721RedemptionMintable.sol";
import {TestERC721} from "../test/utils/mocks/TestERC721.sol";

Expand All @@ -16,8 +17,6 @@ contract DeployAndConfigureExampleCampaign is Script {
address conduit = 0x1E0049783F008A0085193E00003D00cd54003c71;
bytes32 conduitKey = 0x0000007b02230091a7ed01230072f7006a004d60a8d4e71d599b8104250f0000;

address constant _BURN_ADDRESS = 0x000000000000000000000000000000000000dEaD;

function run() external {
vm.startBroadcast();

Expand Down Expand Up @@ -49,7 +48,7 @@ contract DeployAndConfigureExampleCampaign is Script {
identifierOrCriteria: 0,
startAmount: 1,
endAmount: 1,
recipient: payable(_BURN_ADDRESS)
recipient: payable(BURN_ADDRESS)
});

CampaignParams memory params = CampaignParams({
Expand Down
11 changes: 6 additions & 5 deletions script/DeployAndRedeemTokens-CampaignOnReceiveToken.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@ import {Test} from "forge-std/Test.sol";
import {ItemType} from "seaport-types/src/lib/ConsiderationEnums.sol";
import {OfferItem, ConsiderationItem} from "seaport-types/src/lib/ConsiderationStructs.sol";
import {CampaignParams, CampaignRequirements} from "../src/lib/RedeemablesStructs.sol";
import {BURN_ADDRESS} from "../src/lib/RedeemablesConstants.sol";
import {ERC721RedemptionMintable} from "../src/extensions/ERC721RedemptionMintable.sol";
import {ERC721OwnerMintable} from "../src/test/ERC721OwnerMintable.sol";
import {ERC721ShipyardRedeemableMintable} from "../src/extensions/ERC721ShipyardRedeemableMintable.sol";

contract DeployAndRedeemTokens_CampaignOnReceiveToken is Script, Test {
address constant _BURN_ADDRESS = 0x000000000000000000000000000000000000dEaD;

function run() external {
vm.startBroadcast();

Expand All @@ -37,7 +36,7 @@ contract DeployAndRedeemTokens_CampaignOnReceiveToken is Script, Test {
identifierOrCriteria: 0,
startAmount: 1,
endAmount: 1,
recipient: payable(_BURN_ADDRESS)
recipient: payable(BURN_ADDRESS)
});

CampaignRequirements[] memory requirements = new CampaignRequirements[](
Expand All @@ -62,8 +61,10 @@ contract DeployAndRedeemTokens_CampaignOnReceiveToken is Script, Test {

// Let's redeem them!
uint256 requirementsIndex = 0;
bytes32 redemptionHash = bytes32(0);
bytes memory data = abi.encode(campaignId, requirementsIndex, redemptionHash);
bytes32 redemptionHash;
uint256 salt;
bytes memory signature;
bytes memory data = abi.encode(campaignId, requirementsIndex, redemptionHash, salt, signature);

uint256[] memory tokenIds = new uint256[](1);
tokenIds[0] = 1;
Expand Down
5 changes: 2 additions & 3 deletions script/DeployAndRedeemTokens.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,11 @@ import {Test} from "forge-std/Test.sol";
import {ItemType} from "seaport-types/src/lib/ConsiderationEnums.sol";
import {OfferItem, ConsiderationItem} from "seaport-types/src/lib/ConsiderationStructs.sol";
import {CampaignParams, CampaignRequirements} from "../src/lib/RedeemablesStructs.sol";
import {BURN_ADDRESS} from "../src/lib/RedeemablesConstants.sol";
import {ERC721RedemptionMintable} from "../src/extensions/ERC721RedemptionMintable.sol";
import {ERC721ShipyardRedeemableOwnerMintable} from "../src/test/ERC721ShipyardRedeemableOwnerMintable.sol";

contract DeployAndRedeemTokens is Script, Test {
address constant _BURN_ADDRESS = 0x000000000000000000000000000000000000dEaD;

function run() external {
vm.startBroadcast();

Expand Down Expand Up @@ -44,7 +43,7 @@ contract DeployAndRedeemTokens is Script, Test {
identifierOrCriteria: 0,
startAmount: 1,
endAmount: 1,
recipient: payable(_BURN_ADDRESS)
recipient: payable(BURN_ADDRESS)
});

CampaignRequirements[] memory requirements = new CampaignRequirements[](
Expand Down
113 changes: 113 additions & 0 deletions script/DeployAndRedeemTrait.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import {Script} from "forge-std/Script.sol";
import {Test} from "forge-std/Test.sol";
import {ItemType} from "seaport-types/src/lib/ConsiderationEnums.sol";
import {OfferItem, ConsiderationItem} from "seaport-types/src/lib/ConsiderationStructs.sol";
import {IERC7496} from "shipyard-core/src/dynamic-traits/interfaces/IERC7496.sol";
import {CampaignParams, CampaignRequirements, TraitRedemption} from "../src/lib/RedeemablesStructs.sol";
import {ERC721RedemptionMintable} from "../src/extensions/ERC721RedemptionMintable.sol";
import {ERC721ShipyardRedeemableMintable} from "../src/extensions/ERC721ShipyardRedeemableMintable.sol";
import {ERC721ShipyardRedeemablePreapprovedTraitSetters} from
"../src/test/ERC721ShipyardRedeemablePreapprovedTraitSetters.sol";

contract DeployAndRedeemTrait is Script, Test {
function run() external {
vm.startBroadcast();

// deploy the receive token first
ERC721ShipyardRedeemableMintable receiveToken = new ERC721ShipyardRedeemableMintable(
"TestRedeemablesRecieveToken",
"TEST"
);

// add the receive token address to allowed trait setters array
address[] memory allowedTraitSetters = new address[](1);
allowedTraitSetters[0] = address(receiveToken);

// deploy the redeem token with the receive token as an allowed trait setter
ERC721ShipyardRedeemablePreapprovedTraitSetters redeemToken =
new ERC721ShipyardRedeemablePreapprovedTraitSetters(
"DynamicTraitsRedeemToken",
"TEST",
allowedTraitSetters
);

// configure the campaign.
OfferItem[] memory offer = new OfferItem[](1);

// offer is receive token
offer[0] = OfferItem({
itemType: ItemType.ERC721_WITH_CRITERIA,
token: address(receiveToken),
identifierOrCriteria: 0,
startAmount: 1,
endAmount: 1
});

// consideration is empty
ConsiderationItem[] memory consideration = new ConsiderationItem[](0);

TraitRedemption[] memory traitRedemptions = new TraitRedemption[](1);

// trait key is "hasRedeemed"
bytes32 traitKey = bytes32("hasRedeemed");

// previous trait value (`substandardValue`) should be 0
bytes32 substandardValue = bytes32(uint256(0));

// new trait value should be 1
bytes32 traitValue = bytes32(uint256(1));

traitRedemptions[0] = TraitRedemption({
substandard: 1,
token: address(redeemToken),
identifier: 0, // unused field
traitKey: traitKey,
traitValue: traitValue,
substandardValue: substandardValue
});

CampaignRequirements[] memory requirements = new CampaignRequirements[](
1
);
requirements[0].offer = offer;
requirements[0].consideration = consideration;
requirements[0].traitRedemptions = traitRedemptions;

CampaignParams memory params = CampaignParams({
requirements: requirements,
signer: address(0),
startTime: uint32(block.timestamp),
endTime: uint32(block.timestamp + 1_000_000),
maxCampaignRedemptions: 1_000,
manager: msg.sender
});
receiveToken.createCampaign(params, "");

// Mint token 1 to redeem for token 1.
redeemToken.mint(msg.sender, 1);

// Let's redeem them!
uint256[] memory traitRedemptionTokenIds = new uint256[](1);
traitRedemptionTokenIds[0] = 1;

bytes memory data = abi.encode(
1, // campaignId
0, // requirementsIndex
bytes32(0), // redemptionHash
traitRedemptionTokenIds,
uint256(0), // salt
bytes("") // signer
);

receiveToken.redeem(new uint256[](0), msg.sender, data);

// Assert new trait has been set and redemption token is minted.
bytes32 actualTraitValue = IERC7496(address(redeemToken)).getTraitValue(1, traitKey);
// "hasRedeemed" should be 1 (true)
assertEq(bytes32(uint256(1)), actualTraitValue);
assertEq(receiveToken.ownerOf(1), msg.sender);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import {Script} from "forge-std/Script.sol";
import {Test} from "forge-std/Test.sol";
import {ItemType} from "seaport-types/src/lib/ConsiderationEnums.sol";
import {OfferItem, ConsiderationItem} from "seaport-types/src/lib/ConsiderationStructs.sol";
import {CampaignParams, CampaignRequirements} from "../src/lib/RedeemablesStructs.sol";
import {BURN_ADDRESS} from "../src/lib/RedeemablesConstants.sol";
import {ERC721RedemptionMintable} from "../src/extensions/ERC721RedemptionMintable.sol";
import {ERC721OwnerMintable} from "../src/test/ERC721OwnerMintable.sol";
import {ERC721ShipyardRedeemableMintable} from "../src/extensions/ERC721ShipyardRedeemableMintable.sol";

contract DeployERC721ReceiveTokenWithPredeployedSeadropRedeemToken is Script, Test {
function run() external {
vm.startBroadcast();

ERC721ShipyardRedeemableMintable redeemToken =
ERC721ShipyardRedeemableMintable(0xa1783E74857736b2AEE610A36b537B31CC333048);
ERC721ShipyardRedeemableMintable receiveToken =
ERC721ShipyardRedeemableMintable(0x343B9aEC7fAB02d07c6747Bace112920822334B4);

// Configure the campaign.
OfferItem[] memory offer = new OfferItem[](1);
offer[0] = OfferItem({
itemType: ItemType.ERC721_WITH_CRITERIA,
token: address(receiveToken),
identifierOrCriteria: 0,
startAmount: 1,
endAmount: 1
});

ConsiderationItem[] memory consideration = new ConsiderationItem[](1);
consideration[0] = ConsiderationItem({
itemType: ItemType.ERC721_WITH_CRITERIA,
token: address(redeemToken),
identifierOrCriteria: 0,
startAmount: 1,
endAmount: 1,
recipient: payable(BURN_ADDRESS)
});

CampaignRequirements[] memory requirements = new CampaignRequirements[](
1
);
requirements[0].offer = offer;
requirements[0].consideration = consideration;

CampaignParams memory params = CampaignParams({
requirements: requirements,
signer: address(0),
startTime: uint32(block.timestamp),
endTime: uint32(block.timestamp + 1_000_000),
maxCampaignRedemptions: 1_000,
manager: msg.sender
});
uint256 campaignId =
receiveToken.createCampaign(params, "ipfs://QmQKc93y2Ev5k9Kz54mCw48ZM487bwGDktZYPLtrjJ3r1d");

// redeemToken.setBaseURI(
// "ipfs://QmYTSupCtriDLBHgPBBhZ98wYdp6N9S8jTL5sKSZwbASeT"
// );

// receiveToken.setBaseURI(
// "ipfs://QmWxgnz8T9wsMBmpCY4Cvanj3RR1obFD2hqDKPZhKN5Tsq/"
// );

// Let's redeem them!
uint256 requirementsIndex = 0;
bytes32 redemptionHash = bytes32(0);
bytes memory data = abi.encode(campaignId, requirementsIndex, redemptionHash);

uint256[] memory tokenIds = new uint256[](1);
tokenIds[0] = 1;

redeemToken.setApprovalForAll(address(receiveToken), true);

receiveToken.redeem(tokenIds, msg.sender, data);

// Assert redeemable token is burned and redemption token is minted.
assertEq(redeemToken.balanceOf(msg.sender), 2);
assertEq(receiveToken.ownerOf(1), msg.sender);
}
}
4 changes: 2 additions & 2 deletions script/RedeemTokens.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ contract RedeemTokens is Script, Test {
function run() external {
vm.startBroadcast();

address redeemToken = 0x1eCC76De3f9E4e9f8378f6ade61A02A10f976c45;
// address redeemToken = 0x1eCC76De3f9E4e9f8378f6ade61A02A10f976c45;
ERC1155ShipyardRedeemableMintable receiveToken =
ERC1155ShipyardRedeemableMintable(0x3D0fa2a8D07dfe357905a4cB4ed51b0Aea8385B9);

// Let's redeem them!
uint256 campaignId = 1;
uint256 requirementsIndex = 0;
bytes32 redemptionHash = bytes32(0);
bytes memory data = abi.encode(campaignId, requirementsIndex, redemptionHash);
bytes memory data = abi.encode(campaignId, requirementsIndex, redemptionHash, bytes32(0), "");

uint256[] memory redeemTokenIds = new uint256[](1);
redeemTokenIds[0] = 1;
Expand Down
7 changes: 6 additions & 1 deletion src/ERC721ShipyardRedeemable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,12 @@ contract ERC721ShipyardRedeemable is ERC721ShipyardContractMetadata, ERC7498NFTR
return true;
}

function _internalBurn(address, /* from */ uint256 id, uint256 /* amount */ ) internal virtual override {
function _internalBurn(
address,
/* from */
uint256 id,
uint256 /* amount */
) internal virtual override {
_burn(id);
}

Expand Down
2 changes: 1 addition & 1 deletion src/extensions/ERC1155RedemptionMintable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ contract ERC1155RedemptionMintable is ERC1155ShipyardContractMetadata, IRedempti
function mintRedemption(
uint256, /* campaignId */
address recipient,
ConsiderationItem[] calldata consideration,
ConsiderationItem[] calldata, /* consideration */
TraitRedemption[] calldata /* traitRedemptions */
) external {
bool validSender;
Expand Down
Loading