Skip to content

Commit

Permalink
Add Airdrop Factory
Browse files Browse the repository at this point in the history
  • Loading branch information
ben-kaufman committed Jan 2, 2024
1 parent 805573a commit 5bec34a
Show file tree
Hide file tree
Showing 6 changed files with 385 additions and 41 deletions.
80 changes: 48 additions & 32 deletions contracts/tge/HATAirdrop.sol
Original file line number Diff line number Diff line change
@@ -1,49 +1,58 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.16;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
import "../tokenlock/TokenLockFactory.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/cryptography/MerkleProofUpgradeable.sol";
import "../tokenlock/ITokenLockFactory.sol";

/*
An airdrop contract that transfers tokens based on a merkle tree.
*/
contract HATAirdrop is Ownable {
contract HATAirdrop is OwnableUpgradeable {
error CannotRedeemBeforeStartTime();
error CannotRedeemAfterDeadline();
error LeafAlreadyRedeemed();
error InvalidMerkleProof();
error CannotRecoverBeforeDeadline();

using SafeERC20 for IERC20;
using SafeERC20Upgradeable for IERC20Upgradeable;

bytes32 public immutable root;
uint256 public immutable startTime;
uint256 public immutable deadline;
uint256 public immutable periods;
IERC20 public immutable token;
TokenLockFactory public immutable tokenLockFactory;
bytes32 public root;
uint256 public startTime;
uint256 public deadline;
uint256 public lockEndTime;
uint256 public periods;
IERC20Upgradeable public token;
ITokenLockFactory public tokenLockFactory;

mapping (bytes32 => bool) public leafRedeemed;

event MerkleTreeSet(string _merkleTreeIPFSRef, bytes32 _root, uint256 _startTime, uint256 _deadline);
event TokensRedeemed(address indexed _account, address indexed _tokenLock, uint256 _amount);
event TokensRecovered(address indexed _owner, uint256 _amount);

constructor(
constructor () {
_disableInitializers();
}

function initialize(
address _owner,
string memory _merkleTreeIPFSRef,
bytes32 _root,
uint256 _startTime,
uint256 _deadline,
uint256 _lockEndTime,
uint256 _periods,
IERC20 _token,
TokenLockFactory _tokenLockFactory
) {
IERC20Upgradeable _token,
ITokenLockFactory _tokenLockFactory
) external initializer {
_transferOwnership(_owner);
root = _root;
startTime = _startTime;
deadline = _deadline;
lockEndTime = _lockEndTime;
periods = _periods;
token = _token;
tokenLockFactory = _tokenLockFactory;
Expand All @@ -59,20 +68,27 @@ contract HATAirdrop is Ownable {
if (leafRedeemed[leaf]) revert LeafAlreadyRedeemed();
if(!_verify(_proof, leaf)) revert InvalidMerkleProof();
leafRedeemed[leaf] = true;
address _tokenLock = tokenLockFactory.createTokenLock(
address(token),
0x0000000000000000000000000000000000000000,
_account,
_amount,
startTime,
deadline,
periods,
0,
0,
false,
true
);
token.safeTransfer(_tokenLock, _amount);

address _tokenLock = address(0);
if (lockEndTime != 0) {
_tokenLock = tokenLockFactory.createTokenLock(
address(token),
0x0000000000000000000000000000000000000000,
_account,
_amount,
startTime,
lockEndTime,
periods,
0,
0,
false,
true
);
token.safeTransfer(_tokenLock, _amount);
} else {
token.safeTransfer(_account, _amount);
}

emit TokensRedeemed(_account, _tokenLock, _amount);
}

Expand All @@ -86,7 +102,7 @@ contract HATAirdrop is Ownable {
}

function _verify(bytes32[] calldata proof, bytes32 leaf) internal view returns (bool) {
return MerkleProof.verifyCalldata(proof, root, leaf);
return MerkleProofUpgradeable.verifyCalldata(proof, root, leaf);
}

function _leaf(address _account, uint256 _amount) internal pure returns (bytes32) {
Expand Down
78 changes: 78 additions & 0 deletions contracts/tge/HATAirdropFactory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// SPDX-License-Identifier: MIT
// Disclaimer https://github.com/hats-finance/hats-contracts/blob/main/DISCLAIMER.md

pragma solidity 0.8.16;

import "@openzeppelin/contracts/proxy/Clones.sol";
import "./HATAirdrop.sol";

contract HATAirdropFactory {
address public immutable implementation;
event HATAirdropCreated(address indexed _hatAirdrop);

constructor (address _implementation) {
implementation = _implementation;
}

function createHATAirdrop(
address _owner,
string memory _merkleTreeIPFSRef,
bytes32 _root,
uint256 _startTime,
uint256 _deadline,
uint256 _lockEndTime,
uint256 _periods,
IERC20Upgradeable _token,
ITokenLockFactory _tokenLockFactory
) external returns (address result) {
result = Clones.cloneDeterministic(implementation, keccak256(abi.encodePacked(
_owner,
_merkleTreeIPFSRef,
_root,
_startTime,
_deadline,
_lockEndTime,
_periods,
_token,
_tokenLockFactory
)));

HATAirdrop(payable(result)).initialize(
_owner,
_merkleTreeIPFSRef,
_root,
_startTime,
_deadline,
_lockEndTime,
_periods,
_token,
_tokenLockFactory
);

emit HATAirdropCreated(result);
}

function predictHATAirdropAddress(
address _owner,
string memory _merkleTreeIPFSRef,
bytes32 _root,
uint256 _startTime,
uint256 _deadline,
uint256 _lockEndTime,
uint256 _periods,
IERC20 _token,
ITokenLockFactory _tokenLockFactory
) public view returns (address) {
return Clones.predictDeterministicAddress(implementation, keccak256(abi.encodePacked(
_owner,
_merkleTreeIPFSRef,
_root,
_startTime,
_deadline,
_lockEndTime,
_periods,
_token,
_tokenLockFactory
)));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# MerkleProofUpgradeable







*These functions deal with verification of Merkle Tree proofs. The tree and the proofs can be generated using our https://github.com/OpenZeppelin/merkle-tree[JavaScript library]. You will find a quickstart guide in the readme. WARNING: You should avoid using leaf values that are 64 bytes long prior to hashing, or use a hash function other than keccak256 for hashing leaves. This is because the concatenation of a sorted pair of internal nodes in the merkle tree could be reinterpreted as a leaf value. OpenZeppelin's JavaScript library generates merkle trees that are safe against this attack out of the box.*



65 changes: 61 additions & 4 deletions docs/dodoc/tge/HATAirdrop.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,30 @@ function deadline() external view returns (uint256)
|---|---|---|
| _0 | uint256 | undefined |

### initialize

```solidity
function initialize(address _owner, string _merkleTreeIPFSRef, bytes32 _root, uint256 _startTime, uint256 _deadline, uint256 _lockEndTime, uint256 _periods, contract IERC20Upgradeable _token, contract ITokenLockFactory _tokenLockFactory) external nonpayable
```





#### Parameters

| Name | Type | Description |
|---|---|---|
| _owner | address | undefined |
| _merkleTreeIPFSRef | string | undefined |
| _root | bytes32 | undefined |
| _startTime | uint256 | undefined |
| _deadline | uint256 | undefined |
| _lockEndTime | uint256 | undefined |
| _periods | uint256 | undefined |
| _token | contract IERC20Upgradeable | undefined |
| _tokenLockFactory | contract ITokenLockFactory | undefined |

### leafRedeemed

```solidity
Expand All @@ -49,6 +73,23 @@ function leafRedeemed(bytes32) external view returns (bool)
|---|---|---|
| _0 | bool | undefined |

### lockEndTime

```solidity
function lockEndTime() external view returns (uint256)
```






#### Returns

| Name | Type | Description |
|---|---|---|
| _0 | uint256 | undefined |

### owner

```solidity
Expand Down Expand Up @@ -160,7 +201,7 @@ function startTime() external view returns (uint256)
### token

```solidity
function token() external view returns (contract IERC20)
function token() external view returns (contract IERC20Upgradeable)
```


Expand All @@ -172,12 +213,12 @@ function token() external view returns (contract IERC20)

| Name | Type | Description |
|---|---|---|
| _0 | contract IERC20 | undefined |
| _0 | contract IERC20Upgradeable | undefined |

### tokenLockFactory

```solidity
function tokenLockFactory() external view returns (contract TokenLockFactory)
function tokenLockFactory() external view returns (contract ITokenLockFactory)
```


Expand All @@ -189,7 +230,7 @@ function tokenLockFactory() external view returns (contract TokenLockFactory)

| Name | Type | Description |
|---|---|---|
| _0 | contract TokenLockFactory | undefined |
| _0 | contract ITokenLockFactory | undefined |

### transferOwnership

Expand All @@ -211,6 +252,22 @@ function transferOwnership(address newOwner) external nonpayable

## Events

### Initialized

```solidity
event Initialized(uint8 version)
```





#### Parameters

| Name | Type | Description |
|---|---|---|
| version | uint8 | undefined |

### MerkleTreeSet

```solidity
Expand Down
Loading

0 comments on commit 5bec34a

Please sign in to comment.