The airdrop technology created by Gutter Punks allows projects of any size to efficiently airdrop NFT rewards to holders of their tokens. A typical 10,000 item airdrop would cost a project over 20 ETH to complete, with our technology the same airdrop can be completed for under 1 ETH.
This technology works by using ownership of the Gutter Punk (our "parent token") as a reference to who owns the "airdropped token" until either the parent or airdropped token are transferred to a new owner, at which time the airdropped token's owner is written to the blockchain as a separate data element.
When airdrops are initiated by the project to holders the airdropped token contract only emits event logs to notify NFT platforms that the token exists and to place it into the owner's wallet.
Implementation requires the parent token to call the airdropped token contract to trigger the owner data storage when the parent token is transferred.
A complete example of the implementation is available from our GitHub.
Parent Token Code Snippet
/// @notice Array of contract addresses to be notified when base-token is transferred.
address[] public airdrops;
function addAirdropContract(address contAddress) external onlyOwner {
for(uint256 i = 0;i < airdrops.length;i++) {
if(airdrops[i] == contAddress) return;
}
airdrops.push(contAddress);
}
function removeAirdropContract(address contAddress) external onlyOwner {
uint256 contIndex = 0;
bool found = false;
for(uint256 i = 0;i < airdrops.length;i++) {
if(airdrops[i] == contAddress) {
found = true;
contIndex = i;
break;
}
}
require(found, "Airdrop contract not in list.");
if(contIndex != (airdrops.length - 1)) {
airdrops[contIndex] = airdrops[airdrops.length - 1];
}
airdrops.pop();
}
function _beforeTokenTransfers(
address from,
address to,
uint256 startTokenId,
uint256 quantity
) internal override {
for(uint256 i = 0;i < airdrops.length;i++) {
AirdropToken adt = AirdropToken(airdrops[i]);
for(uint256 j = 0;j < quantity;j++) {
adt.parentTokenTransferred(from, to, startTokenId + j);
}
}
}
}
abstract contract AirdropToken {
function parentTokenTransferred(address from, address to, uint256 tokenId) virtual public;
}
Airdropped Token Code Snippet
function parentTokenTransferred(address from, address to, uint256 tokenId) public virtual {
require(_msgSender() == _baseAddress, "This function must be called by the airdrop token parent.");
// Only update token owner if current owner is unset
if(tokenId >= 0 && tokenId <= 1000) {
tokenId = tokenId - BASE_OFFSET; // offset for base token # if necessary
if(_owners[tokenId] == address(0)) { _owners[tokenId] = from; }
}
}
}
abstract contract Base721 {
function ownerOf(uint256 tokenId) public view virtual returns (address);
function balanceOf(address owner) public view virtual returns (uint256);
function getApproved(uint256 tokenId) public view virtual returns (address);
function isApprovedForAll(address owner, address operator) public view virtual returns (bool);
}