Shipment POAPs
Shipment POAPs
We can write a contract, ApePackageCreator, that tacks on an ApePOAP NFT to any user shipment that includes a Bored Ape Yacht Club NFT to another user via the PostOffice contract.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol";
import "./PostOffice.sol";
import "./ApePOAP.sol";
interface CapsuleData {
    enum CapsuleType {
        SIMPLE,
        ERC20,
        ERC721,
        ERC1155
    }
    struct CapsuleContent {
        CapsuleType capsuleType;
        address[] tokenAddresses;
        uint256[] tokenIds;
        uint256[] amounts;
        string tokenURI;
    }
}
contract ApePackageCreator is ERC721Holder {
    PostOffice private postOffice;
    ApePOAP private apePOAP;
    IERC721 private boredApe;
    // replace these with the actual contract addresses
    address constant POST_OFFICE_ADDRESS = 0x3b61403AdE9240699042D3663814a3679dc15d56;
    address constant APE_POAP_ADDRESS = 0xC67F5E3a5B697AE004Edd8F84925189a81c6DC4b;
    address constant BORED_APE_ADDRESS = 0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D;
    constructor() {
        postOffice = PostOffice(POST_OFFICE_ADDRESS);
        apePOAP = ApePOAP(APE_POAP_ADDRESS);
        boredApe = IERC721(BORED_APE_ADDRESS);
    }
    function createApePackage(
        address to_,
        uint256 tokenId,
        bytes32 passwordHash_,
        uint64 unlockTimestamp_
    ) external returns (uint256) {
        // Transfer Bored Ape from user to this contract
        boredApe.safeTransferFrom(msg.sender, address(this), tokenId);
        // Mint a new Ape POAP
        apePOAP.mint(address(this));
        address[] memory _tokenAddresses = new address[](2);
        _tokenAddresses[0] = address(boredApe);
        _tokenAddresses[1] = address(apePOAP);
        uint256[] memory _tokenIds = new uint256[](2);
        _tokenIds[0] = tokenId;
        _tokenIds[1] = apePOAP.tokenOfOwnerByIndex(address(this), apePOAP.balanceOf(address(this)) - 1);
        CapsuleData.CapsuleContent memory _packageContent = CapsuleData.CapsuleContent({
            capsuleType: CapsuleData.CapsuleType.ERC721,
            tokenAddresses: _tokenAddresses,
            tokenIds: _tokenIds,
            amounts: new uint256[](2),
            tokenURI: "https://apepoap.io/metadata"
        });
        SecurityInfo memory _securityInfo = SecurityInfo({
            passwordHash: passwordHash_,
            unlockTimestamp: unlockTimestamp_,
            keyAddress: address(0),
            keyId: 0
        });
        // ship package through PostOffice
        uint256 packageId = postOffice.shipPackage(_packageContent, _securityInfo, to_);
        return packageId;
    }
    function pickup(
        uint256 packageId_,
        string calldata rawPassword_,
        string calldata salt_,
        bool shouldRedeem_
    ) external {
        postOffice.pickup(packageId_, rawPassword_, salt_, shouldRedeem_);
    }
}ApePackageCreator accepts the recipient's address, the Bored Ape's token ID, a security hash, and an unlock timestamp. It then transfers the Bored Ape NFT from the sender to itself, mints a new ApePOAP NFT for the sender, and creates a new package in the PostOffice contract containing both NFTs. The new package can then be redeemed by the recipient using the PostOffice's methods.
Last updated
