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.