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

Platform airdropper #304

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 168 additions & 0 deletions contracts/modules/AddressAliasRegistry.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;

import { IAddressAliasRegistry } from "@modules/interfaces/IAddressAliasRegistry.sol";
import { LibZip } from "solady/utils/LibZip.sol";

/**
* @title AddressAliasRegistry
* @dev A registry for registering addresses with aliases.
*/
contract AddressAliasRegistry is IAddressAliasRegistry {
// =============================================================
// STORAGE
// =============================================================

/**
* @dev The current number of aliases.
*/
uint32 public numAliases;

/**
* @dev Maps an alias to its original address.
*/
mapping(address => address) internal _aliasToAddress;

/**
* @dev Maps an address to its alias.
*/
mapping(address => address) internal _addressToAlias;

// =============================================================
// PUBLIC / EXTERNAL WRITE FUNCTIONS
// =============================================================

/**
* @inheritdoc IAddressAliasRegistry
*/
function resolveAndRegister(address[] memory addressesOrAliases)
public
returns (address[] memory addresses, address[] memory aliases)
{
unchecked {
uint256 n = addressesOrAliases.length;
addresses = addressesOrAliases;
aliases = new address[](n);
for (uint256 i; i != n; ++i) {
(addresses[i], aliases[i]) = _resolveAndRegister(addressesOrAliases[i]);
}
}
}

// Misc functions:
// ---------------

/**
* @dev For calldata compression.
*/
fallback() external payable {
LibZip.cdFallback();
}

/**
* @dev For calldata compression.
*/
receive() external payable {
LibZip.cdFallback();
}

// =============================================================
// PUBLIC / EXTERNAL VIEW FUNCTIONS
// =============================================================

/**
* @inheritdoc IAddressAliasRegistry
*/
function resolve(address[] memory addressesOrAliases)
public
view
returns (address[] memory addresses, address[] memory aliases)
{
unchecked {
uint256 n = addressesOrAliases.length;
addresses = addressesOrAliases;
aliases = new address[](n);
for (uint256 i; i != n; ++i) {
(addresses[i], aliases[i]) = _resolve(addressesOrAliases[i]);
}
}
}

/**
* @inheritdoc IAddressAliasRegistry
*/
function addressOf(address addressOrAlias) public view returns (address) {
// If the `aliasOrAddress` is less than or equal to `2**32 - 1`, we will consider it an alias.
return uint160(addressOrAlias) <= type(uint32).max ? _aliasToAddress[addressOrAlias] : addressOrAlias;
}

/**
* @inheritdoc IAddressAliasRegistry
*/
function aliasOf(address addressOrAlias) public view returns (address) {
return _addressToAlias[addressOf(addressOrAlias)];
}

// =============================================================
// INTERNAL / PRIVATE HELPERS
// =============================================================

/**
* @dev Returns the alias and address for `addressOrAlias`.
* If the `addressOrAlias` is less than `2**31 - 1`, it is treated as an alias.
* Otherwise, it is treated as an address, and it's alias will be registered on-the-fly.
* @param addressOrAlias The alias or address.
* @return address_ The address.
* @return alias_ The alias.
*/
function _resolveAndRegister(address addressOrAlias) internal returns (address address_, address alias_) {
// If the `addressOrAlias` is less than or equal to `2**32 - 1`, we will consider it an alias.
if (uint160(addressOrAlias) <= type(uint32).max) {
alias_ = addressOrAlias;
address_ = _aliasToAddress[alias_];
if (address_ == address(0)) revert AliasNotFound();
} else {
address_ = addressOrAlias;
alias_ = _registerAlias(address_);
}
}

/**
* @dev Returns the alias and address for `addressOrAlias`.
* If the `addressOrAlias` is less than `2**31 - 1`, it is treated as an alias.
* Otherwise, it is treated as an address.
* @param addressOrAlias The alias or address.
* @return address_ The address.
* @return alias_ The alias.
*/
function _resolve(address addressOrAlias) internal view returns (address address_, address alias_) {
// If the `addressOrAlias` is less than or equal to `2**32 - 1`, we will consider it an alias.
if (uint160(addressOrAlias) <= type(uint32).max) {
alias_ = addressOrAlias;
address_ = _aliasToAddress[alias_];
} else {
address_ = addressOrAlias;
alias_ = _addressToAlias[address_];
}
}

/**
* @dev Registers the alias for the address on-the-fly.
* @param address_ The address.
* @return alias_ The alias registered for the address.
*/
function _registerAlias(address address_) internal returns (address alias_) {
if (uint160(address_) <= type(uint32).max) revert AddressTooSmall();

alias_ = _addressToAlias[address_];
// If the address has no alias, register it's alias.
if (alias_ == address(0)) {
// Increment the `numAliases` and cast it into an alias.
alias_ = address(uint160(++numAliases));
// Add to the mappings.
_aliasToAddress[alias_] = address_;
_addressToAlias[address_] = alias_;
emit RegisteredAlias(address_, alias_);
}
}
}
81 changes: 81 additions & 0 deletions contracts/modules/PlatformAirdropper.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;

import { ISuperMinterV2 } from "@modules/interfaces/ISuperMinterV2.sol";
import { IPlatformAirdropper } from "@modules/interfaces/IPlatformAirdropper.sol";
import { IAddressAliasRegistry } from "@modules/interfaces/IAddressAliasRegistry.sol";
import { LibZip } from "solady/utils/LibZip.sol";

/**
* @title PlatformAirdropper
* @dev The `PlatformAirdropper` utility class to batch airdrop tokens.
*/
contract PlatformAirdropper is IPlatformAirdropper {
// =============================================================
// IMMUTABLES
// =============================================================

/**
* @dev The address alias registry.
*/
address public immutable addressAliasRegistry;

// =============================================================
// CONSTRUCTOR
// =============================================================

constructor(address addressAliasRegistry_) payable {
addressAliasRegistry = addressAliasRegistry_;
}

// =============================================================
// PUBLIC / EXTERNAL WRITE FUNCTIONS
// =============================================================

/**
* @inheritdoc IPlatformAirdropper
*/
function platformAirdrop(address superMinter, ISuperMinterV2.PlatformAirdrop memory p)
public
returns (uint256 fromTokenId, address[] memory aliases)
{
unchecked {
(p.to, aliases) = IAddressAliasRegistry(addressAliasRegistry).resolveAndRegister(p.to);
fromTokenId = ISuperMinterV2(superMinter).platformAirdrop(p);
}
}

/**
* @inheritdoc IPlatformAirdropper
*/
function platformAirdropMulti(address superMinter, ISuperMinterV2.PlatformAirdrop[] memory p)
public
returns (uint256[] memory fromTokenIds, address[][] memory aliases)
{
unchecked {
uint256 n = p.length;
fromTokenIds = new uint256[](n);
aliases = new address[][](n);
for (uint256 i; i != n; ++i) {
(fromTokenIds[i], aliases[i]) = platformAirdrop(superMinter, p[i]);
}
}
}

// Misc functions:
// ---------------

/**
* @dev For calldata compression.
*/
fallback() external payable {
LibZip.cdFallback();
}

/**
* @dev For calldata compression.
*/
receive() external payable {
LibZip.cdFallback();
}
}
83 changes: 83 additions & 0 deletions contracts/modules/interfaces/IAddressAliasRegistry.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;

/**
* @title AddressAliasRegistry
* @dev A registry for registering addresses with aliases.
*/
interface IAddressAliasRegistry {
// =============================================================
// EVENTS
// =============================================================

/**
* @dev Emitted when an address is registered with an alias.
*/
event RegisteredAlias(address address_, address alias_);

// =============================================================
// ERRORS
// =============================================================

/**
* @dev The alias has not been registered.
*/
error AliasNotFound();

/**
* @dev The address to be registered must be larger than `2**32 - 1`.
*/
error AddressTooSmall();

// =============================================================
// PUBLIC / EXTERNAL WRITE FUNCTIONS
// =============================================================

/**
* @dev Resolve the addresses or aliases.
* If an address does not have an aliases, an alias will be registered for it.
* @param addressesOrAliases An array of addresses, which can be aliases.
* @return addresses The resolved addresses.
* @return aliases The aliases for the addresses.
*/
function resolveAndRegister(address[] memory addressesOrAliases)
external
returns (address[] memory addresses, address[] memory aliases);

// =============================================================
// PUBLIC / EXTERNAL VIEW FUNCTIONS
// =============================================================

/**
* @dev Returns the current number of aliases.
* @return The latest value.
*/
function numAliases() external view returns (uint32);

/**
* @dev Resolve the addresses or aliases.
* If an address does not have an alias, it's corresponding returned alias will be zero.
* If an alias does not have an address, it's corresponding returned address will be zero.
* @param addressesOrAliases An array of addresses, which can be aliases.
* @return addresses The resolved addresses.
* @return aliases The aliases for the addresses.
*/
function resolve(address[] memory addressesOrAliases)
external
view
returns (address[] memory addresses, address[] memory aliases);

/**
* @dev Resolve the address or alias.
* @param addressesOrAliases An address or alias.
* @return The resolved address.
*/
function addressOf(address addressesOrAliases) external view returns (address);

/**
* @dev Resolve the address or alias.
* @param addressesOrAliases An address or alias.
* @return The resolved alias.
*/
function aliasOf(address addressesOrAliases) external view returns (address);
}
50 changes: 50 additions & 0 deletions contracts/modules/interfaces/IPlatformAirdropper.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;

import { ISuperMinterV2 } from "./ISuperMinterV2.sol";

/**
* @title PlatformAirdropper
* @dev The `PlatformAirdropper` utility class to batch airdrop tokens.
*/
interface IPlatformAirdropper {
// =============================================================
// PUBLIC / EXTERNAL WRITE FUNCTIONS
// =============================================================

/**
* @dev Performs a platform airdrop.
* To save on calldata costs, you can optionally replace each address entry in `p.to` with its alias.
* Aliases are registered on-the-fly when a new address is seen.
* @param superMinter The superminter which has a `platformAirdrop` function.
* @param p The platform airdrop parameters.
* @return fromTokenId The first token ID minted.
* @return aliases The aliases of `p.to`.
*/
function platformAirdrop(address superMinter, ISuperMinterV2.PlatformAirdrop memory p)
external
returns (uint256 fromTokenId, address[] memory aliases);

/**
* @dev Performs a platform airdrop.
* To save on calldata costs, you can optionally replace each address entry in `p.to` with its alias.
* Aliases are registered on-the-fly when a new address is seen.
* @param superMinter The superminter which has a `platformAirdrop` function.
* @param p The platform airdrop parameters.
* @return fromTokenIds The first token IDs minted.
* @return aliases The aliases of each `p.to`.
*/
function platformAirdropMulti(address superMinter, ISuperMinterV2.PlatformAirdrop[] memory p)
external
returns (uint256[] memory fromTokenIds, address[][] memory aliases);

// =============================================================
// PUBLIC / EXTERNAL VIEW FUNCTIONS
// =============================================================

/**
* @dev Returns the address alias registry.
* @return The immutable value.
*/
function addressAliasRegistry() external view returns (address);
}
2 changes: 1 addition & 1 deletion lib/solady
Submodule solady updated 107 files
Loading
Loading