// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol)// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.pragmasolidity ^0.8.0;/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/libraryEnumerableSet{
// To implement this library for multiple types with as little code// repetition as possible, we write it in terms of a generic Set type with// bytes32 values.// The Set implementation uses private functions, and user-facing// implementations (such as AddressSet) are just wrappers around the// underlying Set.// This means that we can only create new EnumerableSets for types that fit// in bytes32.structSet {
// Storage of set valuesbytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0// means a value is not in the set.mapping(bytes32=>uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/function_add(Set storage set, bytes32 value) privatereturns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
returntrue;
} else {
returnfalse;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/function_remove(Set storage set, bytes32 value) privatereturns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slotuint256 valueIndex = set._indexes[value];
if (valueIndex !=0) {
// Equivalent to contains(set, value)// To delete an element from the _values array in O(1), we swap the element to delete with the last one in// the array, and then remove the last element (sometimes called as 'swap and pop').// This modifies the order of the array, as noted in {at}.uint256 toDeleteIndex = valueIndex -1;
uint256 lastIndex = set._values.length-1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastValue;
// Update the index for the moved value
set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slotdelete set._indexes[value];
returntrue;
} else {
returnfalse;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/function_contains(Set storage set, bytes32 value) privateviewreturns (bool) {
return set._indexes[value] !=0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/function_length(Set storage set) privateviewreturns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/function_at(Set storage set, uint256 index) privateviewreturns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/function_values(Set storage set) privateviewreturns (bytes32[] memory) {
return set._values;
}
// Bytes32SetstructBytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/functionadd(Bytes32Set storage set, bytes32 value) internalreturns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/functionremove(Bytes32Set storage set, bytes32 value) internalreturns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/functioncontains(Bytes32Set storage set, bytes32 value) internalviewreturns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/functionlength(Bytes32Set storage set) internalviewreturns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/functionat(Bytes32Set storage set, uint256 index) internalviewreturns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/functionvalues(Bytes32Set storage set) internalviewreturns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assemblyassembly {
result := store
}
return result;
}
// AddressSetstructAddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/functionadd(AddressSet storage set, address value) internalreturns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/functionremove(AddressSet storage set, address value) internalreturns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/functioncontains(AddressSet storage set, address value) internalviewreturns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/functionlength(AddressSet storage set) internalviewreturns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/functionat(AddressSet storage set, uint256 index) internalviewreturns (address) {
returnaddress(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/functionvalues(AddressSet storage set) internalviewreturns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assemblyassembly {
result := store
}
return result;
}
// UintSetstructUintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/functionadd(UintSet storage set, uint256 value) internalreturns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/functionremove(UintSet storage set, uint256 value) internalreturns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/functioncontains(UintSet storage set, uint256 value) internalviewreturns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/functionlength(UintSet storage set) internalviewreturns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/functionat(UintSet storage set, uint256 index) internalviewreturns (uint256) {
returnuint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/functionvalues(UintSet storage set) internalviewreturns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assemblyassembly {
result := store
}
return result;
}
}
// SPDX-License-Identifier: UNLICENSEDpragmasolidity ^0.8.0;contractNativeTransferer{
uint256internalconstant GAS_STIPEND_NO_STORAGE_WRITES =2300;
/**
* @dev Internal function to transfer native tokens from a given originator
* to a multiple recipients
*
* @param offset Calldata offset of the recipients of the transfer.
* @param length Calldata length of the recipients of the transfer.
* @param amount The amount to transfer.
*/function_performMultiNativeTransfer(uint256 offset, uint256 length, uint256 amount) internal{
assembly {
for { let i :=0 } lt(i, length) { i :=add(i, 1) } {
let to :=calldataload(add(offset, mul(i, 0x20)))
ifiszero( call(
GAS_STIPEND_NO_STORAGE_WRITES,
to,
amount,
0,
0,
0,
0
)) {
revert(0,0)
}
}
}
}
/**
* @dev Internal function to transfer native tokens from a given originator
* to a multiple recipients
*
* @param recipientsOffset Calldata offset of the recipients of the transfer.
* @param length Calldata length of the recipients of the transfer.
* @param amountsOffset Calldata offset of the amounts to transfer
*/function_performMultiNativeTransferCustom(uint256 recipientsOffset, uint256 length, uint256 amountsOffset) internalreturns (uint256 totalAmount){
assembly {
for { let i :=0 } lt(i, length) { i :=add(i, 1) } {
let to :=calldataload(add(recipientsOffset, mul(i, 0x20)))
let amount :=calldataload(add(amountsOffset, mul(i, 0x20)))
totalAmount :=add(totalAmount, amount)
ifiszero( call(
GAS_STIPEND_NO_STORAGE_WRITES,
to,
amount,
0,
0,
0,
0
)) {
revert(0,0)
}
}
}
}
}
Contract Source Code
File 4 of 10: PremiumSubscriptionRegistryEvents.sol
// SPDX-License-Identifier: MIT// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)pragmasolidity ^0.8.0;/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/abstractcontractReentrancyGuard{
// Booleans are more expensive than uint256 or any type that takes up a full// word because each write operation emits an extra SLOAD to first read the// slot's contents, replace the bits taken up by the boolean, and then write// back. This is the compiler's defense against contract upgrades and// pointer aliasing, and it cannot be disabled.// The values being non-zero value makes deployment a bit more expensive,// but in exchange the refund on every call to nonReentrant will be lower in// amount. Since refunds are capped to a percentage of the total// transaction's gas, it is best to keep them low in cases like this one, to// increase the likelihood of the full refund coming into effect.uint256privateconstant _NOT_ENTERED =1;
uint256privateconstant _ENTERED =2;
uint256private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/modifiernonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function_nonReentrantBefore() private{
// On the first call to nonReentrant, _status will be _NOT_ENTEREDrequire(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function_nonReentrantAfter() private{
// By storing the original value once again, a refund is triggered (see// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/function_reentrancyGuardEntered() internalviewreturns (bool) {
return _status == _ENTERED;
}
}
Contract Source Code
File 6 of 10: SlashToken.sol
// SPDX-License-Identifier: UNLICENSEDpragmasolidity 0.8.19;import"../handshake-drop-libs/TokenTransferer.sol";
import"../handshake-drop-types/interfaces/SlashTokenEvents.sol";
import"../handshake-drop-libs/NativeTransferer.sol";
import"@openzeppelin/contracts/security/ReentrancyGuard.sol";
//import "hardhat/console.sol";import"../handshake-drop-libs/SubscriptionRegistry.sol";
/// @author 0xCocomastoras/// @custom:version 1.0/// @title SlashToken/// @notice SlashToken is a simple, yet powerful tool to airdrop tokens and NFTs.contractSlashTokenisTokenTransferer, NativeTransferer, SlashTokenEvents, SubscriptionRegistry, ReentrancyGuard{
constructor() ReentrancyGuard(){}
/**
@notice ERC-20 token airdrop with same, equal amount to all recipients
@param recipients A list of addresses of the recipients
@param amount Amount of tokens each recipient will be airdropped
@param token Address of the token
*/functionerc20AirdropEqualAmount(address[] calldata recipients, uint256 amount, address token) externalpayablenonReentrant{
require(frozen ==0, "CF");
require(denylist[msg.sender] ==0, 'UD');
uint256 value = _getBaseFeeForWallet(); //Check if wallet is whitelisted with different valueuint256 purchasedTxns = _getAvailableTxnsForWallet();
uint recipientsLength = recipients.length;
value = value ==0 ? baseFee : value;
if (purchasedTxns ==0) {
require(msg.value== value, "NVV");
} else {
_updateAvailableTxnsForWallet();
}
require(isInitialized !=0, 'NIY');
require(recipientsLength <=500, 'NVL');
uint recipientsOffset;
assembly {
recipientsOffset := recipients.offset
}
_performMultiERC20Transfer(token, recipientsOffset, recipientsLength, amount);
emit Erc20AirdropEqualAmount(msg.sender, token, recipientsLength, recipientsLength*amount);
}
/**
@notice ERC-20 token airdrop with custom amount for each recipient
@param recipients A list of addresses of the recipients
@param amount A list of amounts of the tokens each recipient will be airdropped
@param token Address of the token
@param totalAmount The sum of all tokens to be airdropped
*/functionerc20AirdropCustomAmount(address[] calldata recipients, uint256[] calldata amount, address token, uint256 totalAmount) externalpayablenonReentrant{
require(frozen ==0, "CF");
require(denylist[msg.sender] ==0, 'UD');
uint256 value = _getBaseFeeForWallet(); //Check if wallet is whitelisted with different valueuint256 purchasedTxns = _getAvailableTxnsForWallet();
uint recipientsLength = recipients.length;
value = value ==0 ? baseFee : value;
if (purchasedTxns ==0) {
require(msg.value== value, "NVV");
} else {
_updateAvailableTxnsForWallet();
}
require(isInitialized !=0, 'NIY');
require(recipientsLength <=500&& recipientsLength == amount.length, 'NVL');
uint recipientsOffset;
uint amountsOffset;
assembly {
recipientsOffset := recipients.offset
amountsOffset := amount.offset
}
_performMultiERC20TransferCustom(token, recipientsOffset, recipientsLength, amountsOffset, totalAmount);
emit Erc20AirdropCustomAmount(msg.sender, token, recipientsLength, totalAmount);
}
/**
@notice Native currency airdrop with same, equal amount to all recipients
@param recipients A list of addresses of the recipients
@param amount Amount of tokens each recipient will be airdropped
*/functionnativeAirdropEqualAmount(address[] calldata recipients, uint256 amount) externalpayablenonReentrant{
require(frozen ==0, "CF");
require(isInitialized !=0, 'NIY');
require(denylist[msg.sender] ==0, 'UD');
uint recipientsOffset;
uint recipientsLength = recipients.length;
uint256 value = _getBaseFeeForWallet(); //Check if wallet is whitelisted with different valueuint256 purchasedTxns = _getAvailableTxnsForWallet();
uint256 recipientsValue = amount * recipientsLength;
value = value ==0 ? (baseFee + recipientsValue) : (value + recipientsValue);
if (purchasedTxns ==0) {
require(msg.value== value, "NVV");
} else {
require(msg.value== recipientsValue, 'NVV');
_updateAvailableTxnsForWallet();
}
require(recipientsLength <=500, 'NVL');
assembly {
recipientsOffset := recipients.offset
}
_performMultiNativeTransfer(recipientsOffset, recipientsLength, amount);
emit NativeAirdropEqualAmount(msg.sender, recipientsLength, recipientsValue);
}
/**
@notice Native currency airdrop with custom amount for each recipient
@param recipients A list of addresses of the recipients
@param amounts A list of amounts that each recipient will be airdropped
*/functionnativeAirdropCustomAmount(address[] calldata recipients, uint256[] calldata amounts) externalpayablenonReentrant{
require(frozen ==0, "CF");
require(isInitialized !=0, 'NIY');
require(denylist[msg.sender] ==0, 'UD');
uint256 value = _getBaseFeeForWallet(); //Check if wallet is whitelisted with different valueuint256 purchasedTxns = _getAvailableTxnsForWallet();
uint recipientsOffset;
uint amountsOffset;
uint recipientsLength = recipients.length;
require(recipientsLength <=500&& recipientsLength == amounts.length, 'NVL');
assembly {
recipientsOffset := recipients.offset
amountsOffset := amounts.offset
}
uint totalAmount = _performMultiNativeTransferCustom(recipientsOffset, recipientsLength, amountsOffset);
value = value ==0 ? (baseFee + totalAmount) : (value + totalAmount);
if (purchasedTxns ==0) {
require(msg.value== value, "NVV");
} else {
require(msg.value== totalAmount, 'NVV');
_updateAvailableTxnsForWallet();
}
emit NativeAirdropCustomAmount(msg.sender, recipientsLength, totalAmount);
}
/**
@notice Basic Airdrop of Erc721 tokens without bundle
@param recipients A list of addresses of the recipients
@param ids A list of ids of the token each recipient will be airdropped
@param token The address of the token
*/functionerc721Airdrop(address[] calldata recipients, uint256[] calldata ids, address token) externalpayablenonReentrant{
require(permitErc721 !=0, 'NEY');
require(frozen ==0, "CF");
require(isInitialized !=0, 'NIY');
require(denylist[msg.sender] ==0, 'UD');
uint256 value = _getBaseFeeForWallet();
value = value ==0 ? baseFee : value;
uint256 purchasedTxns = _getAvailableTxnsForWallet();
uint recipientsLength = recipients.length;
if (purchasedTxns ==0) {
require(msg.value== value, "NVV");
} else {
_updateAvailableTxnsForWallet();
}
require(recipientsLength <=500&& recipientsLength == ids.length, 'NVL');
uint recipientsOffset;
uint idsOffset;
assembly {
recipientsOffset := recipients.offset
idsOffset := ids.offset
}
_performMultiERC721Transfer(token, msg.sender, recipientsOffset, recipientsLength, idsOffset);
emit Erc721Airdrop(msg.sender, token, recipientsLength);
}
}
// SPDX-License-Identifier: UNLICENSEDpragmasolidity ^0.8.0;import"../handshake-drop-types/interfaces/SlashTokenRegistryEvents.sol";
import"../handshake-drop-types/interfaces/PremiumSubscriptionRegistryEvents.sol";
import"./ManagerActions.sol";
contractSubscriptionRegistryisSlashTokenRegistryEvents, PremiumSubscriptionRegistryEvents, ManagerActions{
// @dev user's adddress to custom base fee for no bundle purchasesmapping (address=>uint256) baseFeeWhitelisted;
// @dev user address to total available txns to usemapping(address=>uint256) public userToTxns;
uint256[] availableTxnsBundles;
uint256[] txnsBundlesToPrice;
uint256 isInitialized;
uint256public baseFee;
usingEnumerableSetforEnumerableSet.AddressSet;
EnumerableSet.AddressSet bundleUsers;
functioninitialize(address admin_, address feeSink_, uint256 baseFeeCostInWei, uint256[] memory availableTxnsBundles_, uint256[] memory txnsBundlesToPrice_ ) external{
require(isInitialized ==0, 'AI');
require(availableTxnsBundles_.length== txnsBundlesToPrice_.length, 'NVD');
owner = admin_;
feeSink = feeSink_;
availableTxnsBundles = availableTxnsBundles_;
txnsBundlesToPrice = txnsBundlesToPrice_;
isInitialized =1;
baseFee = baseFeeCostInWei;
}
constructor(){}
/**
@notice User buys a bundle of txns
@param bundleIndex The index of the bundle array
@param quantity The number of bundles that the user wants to buy
*/functionbuyTxnsBundle(uint256 bundleIndex, uint256 quantity) externalpayable{
require(frozen ==0, "CF");
require(msg.value== txnsBundlesToPrice[bundleIndex] * quantity, 'NVV');
require(denylist[msg.sender] ==0, 'UD');
require(quantity !=0, 'NVA');
if(!bundleUsers.contains(msg.sender)) {
bundleUsers.add(msg.sender);
}
uint256 total;
unchecked {
total = availableTxnsBundles[bundleIndex] * quantity;
userToTxns[msg.sender] += total;
}
emit TxnsBundleBought(msg.sender, msg.value, total);
}
/**
@notice Admin sets promo fee for wallet instead of default base fee
@param wallet User's wallet address
@param amountInWei New cost per txns
*/functionsetBaseFeeForWallet(address wallet, uint256 amountInWei) external{
require(amountInWei < baseFee, "NVV");
require(msg.sender== owner, 'NVS');
baseFeeWhitelisted[wallet] = amountInWei;
emit WalletBaseFeeSet(wallet, amountInWei);
}
/**
@notice Admin resets promo fee for wallet. Default base fee applies
@param wallet User's wallet address
*/functionresetBaseFeeForWallet(address wallet) external{
require(msg.sender== owner, 'NVS');
delete baseFeeWhitelisted[wallet];
emit WalletBaseFeeReset(wallet);
}
/**
@notice Admin adds txns to a user
@param wallets A list of user's wallet address
@param txns A list of txns to be added
*/functionaddTxnsToWallets(address[] memory wallets, uint256[] memory txns) external{
require(msg.sender== owner, 'NVS');
require(wallets.length== txns.length, "NVL");
uint len = wallets.length;
for(uint i =0; i<len;){
unchecked {
userToTxns[wallets[i]] += txns[i];
i++;
}
}
emit TxnsAdded(wallets, txns);
}
/**
@notice Admin sets the new base fee for all txns
@param baseFee_ New base fee
*/functionsetNewBaseFee(uint256 baseFee_) external{
require(msg.sender== owner, 'NVS');
baseFee = baseFee_;
}
/**
@notice Admin sets the new available txnsBundles and prices
@param availableTxnsBundles_ New available bundles
@param txnsBundlesToPrice_ New price per bundles
*/functionupdateBundles(uint256[] memory availableTxnsBundles_, uint256[] memory txnsBundlesToPrice_ ) external{
require(msg.sender== owner, 'NVS');
require(availableTxnsBundles_.length== txnsBundlesToPrice_.length, 'NVD');
availableTxnsBundles = availableTxnsBundles_;
txnsBundlesToPrice = txnsBundlesToPrice_;
emit BundlesUpdated(msg.sender, availableTxnsBundles_, txnsBundlesToPrice_);
}
/**
@notice External view function that returns active bundle offers
*/functiongetBundles() externalviewreturns (uint256[] memory AvailableBundles, uint256[] memory BundlesPrices) {
AvailableBundles = availableTxnsBundles;
BundlesPrices = txnsBundlesToPrice;
}
/**
@notice External view function that returns the custom base fee for wallet
*/functiongetBaseFeeForWallet() externalviewreturns (uint256) {
return baseFeeWhitelisted[msg.sender];
}
/**
@notice External view function that returns the available txns for wallet
*/functiongetAvailableTxnsForWallet() externalviewreturns (uint256) {
return userToTxns[msg.sender];
}
/**
@notice External view function that returns all the users that have bought a bundle
*/functiongetUsersThatBoughtBundles() externalviewreturns (address[] memory Users) {
require(msg.sender== owner, 'NVS');
Users = bundleUsers.values();
}
/**
@notice Internal view function that returns the custom base fee for wallet
*/function_getBaseFeeForWallet() internalviewreturns (uint256) {
return baseFeeWhitelisted[msg.sender];
}
/**
@notice Internal view function that returns the available txns for wallet
*/function_updateAvailableTxnsForWallet() internal{
unchecked {
--userToTxns[msg.sender];
}
}
/**
@notice Internal view function that returns the available txns for wallet
*/function_getAvailableTxnsForWallet() internalviewreturns (uint256) {
return userToTxns[msg.sender];
}
}
Contract Source Code
File 10 of 10: TokenTransferer.sol
// SPDX-License-Identifier: MITpragmasolidity ^0.8.13;/// @notice Safe ERC20 ,ERC721 multi transfer library that gracefully handles missing return values./// @author Cocomastoras/// @author Modified from Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol)/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)////// @dev Note:/// - For ERC20s and ERC721s, this implementation won't check that a token has code,/// responsibility is delegated to the caller.contractTokenTransferer{
errorTransferFromFailed();
/**
* @dev Internal function to transfer ERC20 tokens from a given originator
* to a multiple recipients. Sufficient approvals must be set on the
* contract performing the transfer.
*
* @param token The ERC20 token to transfer.
* @param recipientsOffset Calldata offset of the recipients of the transfer.
* @param length Calldata length of the recipients of the transfer.
* @param amount The amount to transfer.
*/function_performMultiERC20Transfer(address token, uint256 recipientsOffset, uint256 length, uint256 amount) internal{
/// @solidity memory-safe-assemblyassembly {
let total :=mul(amount, length)
let m :=mload(0x40) // Cache the free memory pointer.mstore(0x60, total) // Store the `amount` argument.mstore(0x40, address()) // Store the `to` argument.mstore(0x2c, shl(96, caller())) // Store the `from` argument.mstore(0x0c, 0x23b872dd000000000000000000000000)
ifiszero(
and( // The arguments of `and` are evaluated from right to left.or(
eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
)
)
{
mstore(0x00, 0x7939f424) // `TransferFromFailed()`.revert(0x1c, 0x04)
}
mstore(0x40, amount) // Store the `amount` argument.for { let i :=0 } lt(i, length) { i :=add(i, 1) } {
let to :=calldataload(add(recipientsOffset, mul(i, 0x20)))
mstore(0x2c, shl(96, to)) // Store the `to` argument.mstore(0x0c, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.// Perform the transfer, reverting upon failure.ifiszero(
and( // The arguments of `and` are evaluated from right to left.or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.call(gas(), token, 0, 0x1c, 0x44, 0x00, 0x20)
)
) {
mstore(0x00, 0x7939f424) // `TransferFromFailed()`.revert(0x1c, 0x04)
}
}
mstore(0x60, 0) // Restore the zero slot to zero.mstore(0x40, m) // Restore the free memory pointer.
}
}
/**
* @dev Internal function to transfer ERC20 tokens from a given originator
* to multiple recipients. Sufficient approvals must be set on the
* contract performing the transfer.
* @param token The ERC20 token to transfer.
* @param recipientsOffset Offset of the recipients of the transfer.
* @param recipientsLength Length of the recipients of the transfer.
* @param amountsOffset Offset of the amounts to transfer.
* @param totalAmount The totalAmount to transfer
*/function_performMultiERC20TransferCustom(address token, uint256 recipientsOffset, uint256 recipientsLength, uint256 amountsOffset, uint256 totalAmount) internal{
/// @solidity memory-safe-assemblyassembly {
let m :=mload(0x40) // Cache the free memory pointer.mstore(0x60, totalAmount) // Store the `amount` argument.mstore(0x40, address()) // Store the `to` argument.mstore(0x2c, shl(96, caller())) // Store the `from` argument.mstore(0x0c, 0x23b872dd000000000000000000000000)
ifiszero(
and( // The arguments of `and` are evaluated from right to left.or(
eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
)
)
{
mstore(0x00, 0x7939f424) // `TransferFromFailed()`.revert(0x1c, 0x04)
}
let sumAmount :=0for { let i :=0 } lt(i, recipientsLength) { i :=add(i, 1) } {
let to :=calldataload(add(recipientsOffset, mul(i, 0x20)))
let amount :=calldataload(add(amountsOffset, mul(i, 0x20)))
sumAmount :=add(sumAmount, amount)
mstore(0x40, amount) // Store the `amount` argument.mstore(0x2c, shl(96, to)) // Store the `to` argument.mstore(0x0c, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.// Perform the transfer, reverting upon failure.ifiszero(
and( // The arguments of `and` are evaluated from right to left.or(eq(mload(0x00), 1), iszero(returndatasize())), // Returned 1 or nothing.call(gas(), token, 0, 0x1c, 0x44, 0x00, 0x20)
)
) {
mstore(0x00, 0x7939f424) // `TransferFromFailed()`.revert(0x1c, 0x04)
}
}
ifiszero(eq(totalAmount, sumAmount)) {
revert(0,0)
}
mstore(0x60, 0) // Restore the zero slot to zero.mstore(0x40, m) // Restore the free memory pointer.
}
}
/**
* @dev Internal function to transfer batch of ERC721 tokens from a given
* originator to multiple recipients. Sufficient approvals must be set on
* the contract performing the transfer. Note that this function does
* not check whether the receiver can accept the ERC721 token (i.e. it
* does not use `safeTransferFrom`).
*
* @param token The ERC721 token to transfer.
* @param from The originator of the transfer.
* @param recipientsOffset The offset of recipients of the transfer.
* @param recipientsLength The length of tokens to transfer.
* @param idsOffset The offset of tokenIds to transfer.
*/function_performMultiERC721Transfer(address token,
addressfrom,
uint256 recipientsOffset,
uint256 recipientsLength,
uint256 idsOffset
) internal{
// Utilize assembly to perform an optimized ERC721 token transfer.assembly {
let m :=mload(0x40) // Cache the free memory pointer.for { let i :=0 } lt(i, recipientsLength) { i :=add(i, 1) } {
let to :=calldataload(add(recipientsOffset, mul(i, 0x20)))
let identifier :=calldataload(add(idsOffset, mul(i, 0x20)))
mstore(0x60, identifier) // Store the `identifier` argument.mstore(0x40, to) // Store the `to` argument.mstore(0x2c, shl(96, from)) // Store the `from` argument.mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.// Perform the transfer, reverting upon failure.ifiszero(
and( // The arguments of `and` are evaluated from right to left.iszero(returndatasize()), // Returned error.call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x00)
)
) {
mstore(0x00, 0x7939f424) // `TransferFromFailed()`.revert(0x1c, 0x04)
}
}
mstore(0x60, 0) // Restore the zero slot to zero.mstore(0x40, m) // Restore the free memory pointer.
}
}
}