Skip to content
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
Binary file modified .DS_Store
Binary file not shown.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
node_modules
.env
cache
artifacts

Expand Down
5 changes: 5 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions .idea/airdrop-template.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions AirdropManagerArguments.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = [
["0x6927ABD63Da2Da250E6676c64cF14586E1E1fA10"],
"0xda0c531F4dAFED4E6bc6EfBe2D281C49BA5eE049",
"0x6465331bBf430f53504cb94BF2d2AF32E5740F68"
]
64 changes: 64 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,70 @@
# ERC1155 Airdrop Smart Contracts Template
This project is an open-source template for creating an ERC1155 airdrop smart contract on the RSK network. The template is designed to be easy to use and customize, and it includes a simple example of how to create an airdrop campaign and distribute tokens to multiple recipients.

## Deployment
The smart contracts in this template can be deployed to the RSK network using the next command:
```bash
npx hardhat ignition deploy ignition/modules/AirdropManager.ts --network rskTestnet
```

It will deploy the `AirdropManager`, `AirdropDeployerERC20Module` & `AirdropDeployerERC1155Module` contracts and its dependencies to the RSK Testnet network. You should see a response like:
```bash
Hardhat Ignition 🚀

Deploying [ AirdropManagerModule ]

Batch #1
Executed AirdropDeployerERC1155Module#AirdropDeployerERC1155
Executed AirdropDeployerERC20Module#AirdropDeployerERC20

Batch #2
Executed AirdropManagerModule#AirdropManager

[ AirdropManagerModule ] successfully deployed 🚀

Deployed Addresses

AirdropDeployerERC1155Module#AirdropDeployerERC1155 - 0x6465331bBf430f53504cb94BF2d2AF32E5740F68
AirdropDeployerERC20Module#AirdropDeployerERC20 - 0xda0c531F4dAFED4E6bc6EfBe2D281C49BA5eE049
AirdropManagerModule#AirdropManager - 0x19Fa15E7084D802335cfC1B7d5AC22a6b80Bf6Ef
```
> Also, you can see the deployed contracts in the `ignition/deployments/chain-31/deployed_addresses` folder.

## Verify Contracts
To verify the contracts on the RSK network, you can use the next command:
1. AirdropDeployerERC1155
```bash
npx hardhat verify --network rskTestnet 0x49dbbA265c0f4a7Ca8C277F57E189f6B90998aEE
```
***Note: Replace the address `0x49dbbA265c0f4a7Ca8C277F57E189f6B90998aEE` with the address of the contract you want to verify.***

2. AirdropDeployerERC20
```bash
npx hardhat verify --network rskTestnet 0xe68B923822E0b9067413be380dBED46f295F2372
```
***Note: Replace the address `0xe68B923822E0b9067413be380dBED46f295F2372` with the address of the contract you want to verify.***

3. AirdropManager, for this contract verification, you need to pass the constructor arguments in the file `AirdropManagerArguments.js`, so make sure you replace them with your own args:
```bash
npx hardhat verify --constructor-args AirdropManagerArguments.js --network rskTestnet 0xFdEdc1427b745D9876B5BBF21e2F57922CF78117
```
You should see a response like this in each verification:
```bash
Successfully verified contract AirdropDeployerERC20 on the block explorer.
https://rootstock-testnet.blockscout.com/address/0xe68B923822E0b9067413be380dBED46f295F2372#code
```

## Deploy ERC1155
We have included an ERC1155 contract in the `contracts/ERC1155/Erc1155.sol` file. You can modify it as needed and deploy it to the RSK network.

To deploy your ERC1155 contract, you can use the next command:
```bash
npx hardhat ignition deploy ignition/modules/ERC1155.ts --network rskTestnet
```
And then you can use the next command to verify the contract:
```bash
npx hardhat verify --network rskTestnet 0xe68B923822E0b9067413be380dBED46f295F2372
```
## Smart Contracts Reference

### 1. **Administrable.sol**
Expand Down
197 changes: 127 additions & 70 deletions contracts/AirdropManager.sol
Original file line number Diff line number Diff line change
@@ -1,115 +1,160 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import "./Administrable.sol";

enum AirdropType {
CUSTOM,
MERKLE
}
struct AirdropInfo {
string airdropName;
address airdropAddress;
uint256 totalAirdropAmount;
uint256 airdropAmountLeft;
uint256 claimAmount;
uint256 expirationDate;
AirdropType airdropType;
}

interface IAirdrop1155 {
function claim(address user, uint256 amount_, bytes32[] calldata proof_) external;
function hasClaimed(address _address) external view returns(bool);
function hasExpired() external view returns(bool);
function allowAddress(address _address) external;
function allowAddresses(address[] memory addresses) external;
function disallowAddresses(address[] memory addresses) external;
function disallowAddress(address _address) external;
function isAllowed(address _address) external view returns(bool);
function getExpirationDate() external view returns(uint256);
function getClaimAmount() external view returns(uint256);
function getTotalAirdropAmount() external view returns(uint256);
function getAirdropAmountLeft() external view returns(uint256);
function getBalance() external view returns(uint256);
function getAirdropInfo() external view returns(AirdropInfo memory info);
function setRoot(bytes32 _root) external;
}
import "./Lib/Administrable.sol";
import "./Tools/Types.sol";

contract AirdropManager is Administrable {
address _airdropDeployerERC20Address;
address _airdropDeployerERC1155Address;
address[] _airdrops;

constructor (address[] memory initialAdmins) Administrable(initialAdmins) {}

event AirdropAdded(address airdropAddress);
event AirdropRemoved(address airdropAddress);

function claim(address airdropAddress, address user, uint256 amount, bytes32[] calldata proof) public {
IAirdrop1155 airdrop = IAirdrop1155(airdropAddress);
event AirdropERC20Deployed(address airdropAddress);
event AirdropERC1155Deployed(address airdropAddress);

constructor(
address[] memory initialAdmins,
address airdropDeployerERC20Address,
address airdropDeployerERC1155Address
) Administrable(initialAdmins) {
_airdropDeployerERC20Address = airdropDeployerERC20Address;
_airdropDeployerERC1155Address = airdropDeployerERC1155Address;
}

function claim(
address airdropAddress,
address user,
uint256 amount,
bytes32[] calldata proof
) public {
IAirdrop airdrop = IAirdrop(airdropAddress);
airdrop.claim(user, amount, proof);
}

function hasClaimed(address airdropAddress, address user) public view returns(bool) {
IAirdrop1155 airdrop = IAirdrop1155(airdropAddress);
function hasClaimed(
address airdropAddress,
address user
) public view returns (bool) {
IAirdrop airdrop = IAirdrop(airdropAddress);
return airdrop.hasClaimed(user);
}

function hasExpired(address airdropAddress) public view returns(bool) {
IAirdrop1155 airdrop = IAirdrop1155(airdropAddress);
function hasExpired(address airdropAddress) public view returns (bool) {
IAirdrop airdrop = IAirdrop(airdropAddress);
return airdrop.hasExpired();
}

function isAllowed(address airdropAddress, address user) public view returns(bool) {
IAirdrop1155 airdrop = IAirdrop1155(airdropAddress);
function isAllowed(
address airdropAddress,
address user
) public view returns (bool) {
IAirdrop airdrop = IAirdrop(airdropAddress);
return airdrop.isAllowed(user);
}

function getExpirationDate(address airdropAddress) public view returns(uint256) {
IAirdrop1155 airdrop = IAirdrop1155(airdropAddress);
function getExpirationDate(
address airdropAddress
) public view returns (uint256) {
IAirdrop airdrop = IAirdrop(airdropAddress);
return airdrop.getExpirationDate();
}

function getClaimAmount(address airdropAddress) public view returns(uint256) {
IAirdrop1155 airdrop = IAirdrop1155(airdropAddress);
function getClaimAmount(
address airdropAddress
) public view returns (uint256) {
IAirdrop airdrop = IAirdrop(airdropAddress);
return airdrop.getClaimAmount();
}

function getAirdropInfo(address airdropAddress) public view returns(AirdropInfo memory) {
IAirdrop1155 airdrop = IAirdrop1155(airdropAddress);
function getAirdropInfo(
address airdropAddress
) public view returns (AirdropInfo memory) {
IAirdrop airdrop = IAirdrop(airdropAddress);
return airdrop.getAirdropInfo();
}

function getTotalAirdropAmount(address airdropAddress) public view returns(uint256) {
IAirdrop1155 airdrop = IAirdrop1155(airdropAddress);
function getTotalAirdropAmount(
address airdropAddress
) public view returns (uint256) {
IAirdrop airdrop = IAirdrop(airdropAddress);
return airdrop.getTotalAirdropAmount();
}

function getAirdropAmountLeft(address airdropAddress) public view returns(uint256) {
IAirdrop1155 airdrop = IAirdrop1155(airdropAddress);
function getAirdropAmountLeft(
address airdropAddress
) public view returns (uint256) {
IAirdrop airdrop = IAirdrop(airdropAddress);
return airdrop.getAirdropAmountLeft();
}

function getBalance(address airdropAddress) public view returns(uint256) {
IAirdrop1155 airdrop = IAirdrop1155(airdropAddress);
function getBalance(address airdropAddress) public view returns (uint256) {
IAirdrop airdrop = IAirdrop(airdropAddress);
return airdrop.getBalance();
}

function getAirdrops() public view returns(address[] memory) {
function getAirdrops() public view returns (address[] memory) {
return _airdrops;
}

function addAirdrop(address newAirdropAddress) public onlyAdmins {
function deployAndAddAirdropERC20(
string memory airdropName,
address tokenAddress,
uint256 totalAirdropAmount,
uint256 claimAmount,
uint256 expirationDate
) public returns(address) {
IDeployerERC20 deployerERC20 = IDeployerERC20(_airdropDeployerERC20Address);
address deployedAddress = deployerERC20.deployAndAddAirdrop(
airdropName,
tokenAddress,
totalAirdropAmount,
claimAmount,
expirationDate
);
addAirdrop(deployedAddress);
emit AirdropERC20Deployed(deployedAddress);
return deployedAddress;
}

function deployAndAddAirdropERC1155(
string memory airdropName,
address tokenAddress,
uint256 tokenId,
uint256 totalAirdropAmount,
uint256 claimAmount,
uint256 expirationDate,
uint256 mode
) public returns(address) {
IDeployer1155 deployer1155 = IDeployer1155(_airdropDeployerERC1155Address);
address deployedAddress = deployer1155.deployAndAddAirdrop(
airdropName,
tokenAddress,
tokenId,
totalAirdropAmount,
claimAmount,
expirationDate,
mode
);
require(deployedAddress != address(0), "Error, wrong mode selected");
addAirdrop(deployedAddress);
emit AirdropERC1155Deployed(deployedAddress);
return deployedAddress;
}

function addAirdrop(address newAirdropAddress) internal {
bool exists = false;
for (uint i = 0; i < _airdrops.length && !exists; i++) {
exists = _airdrops[i] == newAirdropAddress;
}

require(!exists, "Airdrop already added");
_airdrops.push(newAirdropAddress);
emit AirdropAdded(newAirdropAddress);
}

function setRoot(address airdropAddress, bytes32 _root) public onlyAdmins {
IAirdrop1155 airdrop = IAirdrop1155(airdropAddress);
IAirdrop airdrop = IAirdrop(airdropAddress);
airdrop.setRoot(_root);
}

Expand All @@ -118,31 +163,43 @@ contract AirdropManager is Administrable {
for (uint i = 0; i < _airdrops.length && !exists; i++) {
if (_airdrops[i] == airdropAddress) {
exists = true;
_airdrops[i] = _airdrops[_airdrops.length -1];
_airdrops[i] = _airdrops[_airdrops.length - 1];
_airdrops.pop();
}
}

if (exists) emit AirdropRemoved(airdropAddress);
}

function allowAddress(address airdropAddress, address user) public onlyAdmins {
IAirdrop1155 airdrop = IAirdrop1155(airdropAddress);
function allowAddress(
address airdropAddress,
address user
) public onlyAdmins {
IAirdrop airdrop = IAirdrop(airdropAddress);
airdrop.allowAddress(user);
}

function allowAddresses(address airdropAddress, address[] memory users) public onlyAdmins {
IAirdrop1155 airdrop = IAirdrop1155(airdropAddress);
function allowAddresses(
address airdropAddress,
address[] memory users
) public onlyAdmins {
IAirdrop airdrop = IAirdrop(airdropAddress);
airdrop.allowAddresses(users);
}

function disallowAddress(address airdropAddress, address user) public onlyAdmins {
IAirdrop1155 airdrop = IAirdrop1155(airdropAddress);
function disallowAddress(
address airdropAddress,
address user
) public onlyAdmins {
IAirdrop airdrop = IAirdrop(airdropAddress);
airdrop.disallowAddress(user);
}

function disallowAddresses(address airdropAddress, address[] memory users) public onlyAdmins {
IAirdrop1155 airdrop = IAirdrop1155(airdropAddress);
function disallowAddresses(
address airdropAddress,
address[] memory users
) public onlyAdmins {
IAirdrop airdrop = IAirdrop(airdropAddress);
airdrop.disallowAddresses(users);
}
}
}
Loading