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

Combine airdrop + metal fun with price calc #8

Open
wants to merge 16 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
28 changes: 24 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@

Foundry consists of:

- **Forge**: Ethereum testing framework (like Truffle, Hardhat and DappTools).
- **Cast**: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data.
- **Anvil**: Local Ethereum node, akin to Ganache, Hardhat Network.
- **Chisel**: Fast, utilitarian, and verbose solidity REPL.
- **Forge**: Ethereum testing framework (like Truffle, Hardhat and DappTools).
- **Cast**: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data.
- **Anvil**: Local Ethereum node, akin to Ganache, Hardhat Network.
- **Chisel**: Fast, utilitarian, and verbose solidity REPL.

## Documentation

Expand All @@ -27,6 +27,12 @@ $ forge build
$ forge test
```

example:

```shell
forge test --match-contract TestEndToEndAirdrop -vv --via-ir --chain 11155111 --fork-url https://eth-sepolia.g.alchemy.com/v2/INSERT_ALCHEMY_SEPOLIA_KEY
```

### Format

```shell
Expand All @@ -51,6 +57,20 @@ $ anvil
$ forge script script/Counter.s.sol:CounterScript --rpc-url <your_rpc_url> --private-key <your_private_key>
```

Example:

```shell
forge script script/DeployMetalFunFactoryV2.s.sol --rpc-url https://eth-sepolia.g.alchemy.com/v2/ALCHEMY_SEPOLIA_EY --sender 0x123 --private-key PRIVATE_KEY --optimize --optimizer-runs 200 --verify --verifier-url https://api-sepolia.etherscan.io/api --etherscan-api-key ETHERSCAN_KEY --broadcast --chain-id 11155111 --constructor-args 0x0
```

### Verify

If the verification fails on deploy:

```shell
forge verify-contract --verifier-url https://api-sepolia.etherscan.io/api --etherscan-api-key ETHERSCAN_KEY 0x123contractAddress... "PATH:src/FundMe.sol:FundMe"
```

### Cast

```shell
Expand Down
70 changes: 70 additions & 0 deletions broadcast/DeployAirdropFactory.s.sol/11155111/run-latest.json

Large diffs are not rendered by default.

73 changes: 73 additions & 0 deletions broadcast/DeployAirdropFactory.s.sol/8453/run-latest.json

Large diffs are not rendered by default.

307 changes: 307 additions & 0 deletions broadcast/DeployAirdropToken.s.sol/11155111/run-latest.json

Large diffs are not rendered by default.

307 changes: 307 additions & 0 deletions broadcast/DeployAirdropToken.s.sol/8453/run-latest.json

Large diffs are not rendered by default.

This file was deleted.

72 changes: 0 additions & 72 deletions broadcast/DeployMetalFunFactoryV2.s.sol/11155111/run-latest.json

This file was deleted.

75 changes: 0 additions & 75 deletions broadcast/DeployMetalFunFactoryV2.s.sol/8453/run-1714608651.json

This file was deleted.

75 changes: 0 additions & 75 deletions broadcast/DeployMetalFunFactoryV2.s.sol/8453/run-latest.json

This file was deleted.

22 changes: 22 additions & 0 deletions script/DeployAirdropFactory.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;

import {Script, console} from "forge-std/Script.sol";
import {AIRDROP_FACTORY_SALT} from "../src/Constants.sol";
import {InstantLiquidityToken} from "../src/InstantLiquidityToken.sol";
import {AirdropFactory} from "../src/AirdropFactory.sol";

contract DeployAirdropFactory is Script {
function run() public returns (AirdropFactory) {
return _run(0x71e1BB6EA5B84E9Aa55691a1E86223d250a18F8F);
}

function _run(address _owner) public returns (AirdropFactory) {
vm.broadcast();
AirdropFactory tokenFactory = new AirdropFactory{salt: AIRDROP_FACTORY_SALT}(_owner);

console.log("Airdrop Factory: ", address(tokenFactory));

return tokenFactory;
}
}
52 changes: 52 additions & 0 deletions script/DeployAirdropToken.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.20;

import {Script, console} from "forge-std/Script.sol";
import {AirdropFactory, InstantLiquidityToken} from "../src/AirdropFactory.sol";

contract DeployAirdropToken is Script {
struct RunParams {
address factory;
string name;
string symbol;
uint256 initialPricePerEth;
uint256 totalSupply;
uint256 minterSupply;
uint256 airdropSupply;
address minterAddress;
address[] airdropAddresses;
}

function run() public {
address[] memory airdropAddresses = new address[](2);
airdropAddresses[0] = address(0xc0ffee);
airdropAddresses[1] = address(0x123);

vm.broadcast();
RunParams memory params = RunParams({
factory: 0x13a0dFb64FFaE6BB58bbAB81cA8d17cb259C183f,
name: "",
symbol: "",
initialPricePerEth: 0.01 ether,
totalSupply: 1_000_000_000,
minterSupply: 5_000,
airdropSupply: 253_000,
minterAddress: airdropAddresses[0],
airdropAddresses: airdropAddresses
});
_run(params);
}

function _run(RunParams memory params)
public returns (InstantLiquidityToken, uint256) {
AirdropFactory factory = AirdropFactory(params.factory);

(InstantLiquidityToken token, uint256 lpTokenId) =
factory.deployAndAirdrop(params.name, params.symbol, params.initialPricePerEth, params.totalSupply, params.minterSupply, params.airdropSupply, params.minterAddress, params.airdropAddresses);

console.log("token", address(token));

return (token, lpTokenId);
}

}
2 changes: 1 addition & 1 deletion script/DeployMetalFunFactoryV2.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {MetalFunFactoryV2} from "../src/MetalFunFactoryV2.sol";

contract DeployMetalFunFactory is Script {
function run() public returns (MetalFunFactoryV2) {
return _run(vm.envAddress("OWNER"));
return _run(0x71e1BB6EA5B84E9Aa55691a1E86223d250a18F8F);
}

function _run(address _owner) public returns (MetalFunFactoryV2) {
Expand Down
2 changes: 1 addition & 1 deletion script/DeployMetalFunTokenV2.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ contract DeployMetalFunTokenV2 is Script {
function _run(address _factory) public returns (InstantLiquidityToken, uint256) {
MetalFunFactoryV2 factory = MetalFunFactoryV2(_factory);
(InstantLiquidityToken token, uint256 lpTokenId) =
factory.deploy("", "", 0.01 ether, 1000_000_000, address(0), 0);
factory.deploy("", "", 0.01 ether, 1_000_000_000, address(0), 0);

console.log("token", address(token));

Expand Down
108 changes: 108 additions & 0 deletions src/AirdropFactory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "./MetalAirdropFactory.sol";

interface IGasliteDrop {
function airdropERC20(
address _token,
address[] calldata _addresses,
uint256[] calldata _amounts,
uint256 _totalAmount
) external payable;

function airdropERC721(
address _nft,
address[] calldata _addresses,
uint256[] calldata _tokenIds
) external payable;

function airdropETH(address[] calldata _addresses, uint256[] calldata _amounts)
external
payable;
}

IGasliteDrop constant gasliteDrop = IGasliteDrop(0x09350F89e2D7B6e96bA730783c2d76137B045FEF);

contract AirdropFactory is MetalAirdropFactory {

event DeploymentWithAirdrop(
address indexed token,
uint256 indexed lpTokenId,
address[] recipients,
string name,
string symbol
);

constructor(address _owner) MetalAirdropFactory(_owner) {}

function _getAirdropAmounts(address[] calldata _addresses, uint256 _airdropSupply)
internal
pure
returns (uint256[] memory) {

// initialize the amounts array
uint256[] memory amounts = new uint256[](_addresses.length);

// figure how much should go to each owner
uint256 fractionalAmount = _airdropSupply / _addresses.length;

// load up the amounts
for (uint256 i; i < _addresses.length; ++i) {
amounts[i] = fractionalAmount;
}

return amounts;
}

function deployAndAirdrop(
string calldata _name,
string calldata _symbol,
uint256 _initialPricePerEth,
uint256 _totalSupply,
uint256 _minterSupply,
uint256 _airdropSupply,
address _minterAddress,
address[] calldata _airdropAddresses
) public returns (InstantLiquidityToken, uint256) {
// airdrop array needs at least one recipient
if (_airdropAddresses.length == 0) revert("must specify recipient addresses");

// determine pool amount
uint256 poolSupply = _totalSupply - _minterSupply - _airdropSupply;

//
(InstantLiquidityToken token, uint256 lpTokenId) =
deploy({_name: _name, _symbol: _symbol, _initialPricePerEth: _initialPricePerEth, _totalSupply: _totalSupply, _poolSupply: poolSupply});


// After token initialization and pool creation, transfer to the optional minter address
if (_minterSupply > 0) {
InstantLiquidityToken(token).transfer(_minterAddress, _minterSupply);
}

// approve the airdrop amount
token.approve({spender: address(gasliteDrop), value: _airdropSupply});

uint256[] memory amounts =
_getAirdropAmounts({_addresses: _airdropAddresses, _airdropSupply: _airdropSupply});

// transfer the airdropSupply to airdropAddresses
gasliteDrop.airdropERC20({
_token: address(token),
_addresses: _airdropAddresses,
_amounts: amounts,
_totalAmount: _airdropSupply
});

emit DeploymentWithAirdrop({
token: address(token),
lpTokenId: lpTokenId,
recipients: _airdropAddresses,
name: _name,
symbol: _symbol
});

return (token, lpTokenId);
}
}
1 change: 1 addition & 0 deletions src/Constants.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ bytes32 constant TOKEN_FACTORY_SALT = keccak256("TOKEN_FACTORY_V3");
bytes32 constant TOKEN_FACTORYV2_SALT = keccak256("TOKEN_FACTORY_AIRDROP_VARIANT");
bytes32 constant METAL_FUN_FACTORY_SALT = keccak256("METAL_FUN_FACTORY");
bytes32 constant METAL_FUN_FACTORY_V2_SALT = keccak256("METAL_FUN_FACTORY_V2");
bytes32 constant AIRDROP_FACTORY_SALT = keccak256("METAL_AIRDROP_FACTORY");
Loading
Loading