IFAllocationSale.sol
Launchpad allocation sale contract
This contract is responsible for conducting a token sale based on allocation that is obtained through staking over time via IFAllocationMaster.

Events

1
event Fund(address indexed sender, uint256 amount);
2
event SetMinTotalPayment(uint256 indexed minTotalPayment);
3
event SetSaleTokenAllocationOverride(
4
uint256 indexed saleTokenAllocationOverride
5
);
6
event SetCasher(address indexed casher);
7
event SetWhitelistSetter(address indexed whitelistSetter);
8
event SetWhitelist(bytes32 indexed whitelistRootHash);
9
event SetWithdrawDelay(uint24 indexed withdrawDelay);
10
event Purchase(address indexed sender, uint256 indexed paymentAmount);
11
event Withdraw(address indexed sender, uint256 indexed amount);
12
event Cash(
13
address indexed sender,
14
uint256 paymentTokenBalance,
15
uint256 saleTokenBalance
16
);
17
event EmergencyTokenRetrieve(address indexed sender, uint256 amount);
Copied!

Public variables

saleAmount

1
uint256 public saleAmount;
Copied!
Amount of sale tokens to sell.
This is updated only by depositing sale tokens into this contract via fund.

paymentReceived

1
mapping(address => uint256) public paymentReceived;
Copied!
Tracks amount of payment received by each address.
The amount of tokens a user has purchased can be determined with the following calculation:
paymentReceived[user] / salePrice

hasWithdrawn

1
mapping(address => bool) public hasWithdrawn;
Copied!
Tracks whether user has already successfully withdrawn.

purchaserCount

1
uint32 public purchaserCount;
Copied!
Counter of unique purchasers.

withdrawerCount

1
uint32 public withdrawerCount;
Copied!
Counter of unique withdrawers (doesn't count casher).

salePrice

1
uint256 public salePrice;
Copied!
Sale price is in units of paymentToken/saleToken with 10^18 decimals (we define this constant as SALE_PRICE_DECIMALS = 10^18).
For example, if selling ABC token for 10 IFUSD each, then sale price will be 10 * 10^18 = 10_000_000_000_000_000_000.
Note: this example assumes that ABC token and IFUSD have the same number of decimals.
If decimals differ, then salePrice must accommodate any differences in decimals between sale and payment tokens. In other words, if payment token has A decimals and sale token has B decimals, then the price must be adjusted by multiplying by 10**(A-B). The following examples illustrates this:
If A was 18 but B was only 12, then the salePrice should be adjusted by multiplying by 1,000,000. If A was 12 and B was 18, then salePrice should be adjusted by dividing by 1,000,000.

funder

1
address public funder;
Copied!
The contract funder which adds sale tokens to be sold.

casher (optional)

1
address public casher;
Copied!
Optional casher settable by owner.
The owner can cash the sale contract, and if an optional casher is specified, then both owner and casher can cash the sale contract.

whitelistSetter (optional)

1
address public whitelistSetter;
Copied!
Optional whitelist setter settable by owner.
The owner can set the whitelist, and if an optional whitelistSetter is specified, then both owner and whitelistSetter can set the whitelist.

paymentToken

1
ERC20 public paymentToken;
Copied!
The payment token.

saleToken

1
ERC20 public saleToken;
Copied!
The sale token.

allocationMaster

1
IFAllocationMaster public allocationMaster;
Copied!
The allocation master.

trackId

1
uint24 public trackId;
Copied!
The track on which this sale is conducted.

allocSnapshotBlock

1
uint80 public allocSnapshotBlock;
Copied!
The snapshot block to read stake weights from for determining allocations.

startBlock

1
uint256 public startBlock;
Copied!
Start block is when sale is active (inclusive).

endBlock

1
uint256 public endBlock;
Copied!
End block is when sale is active (inclusive).

minTotalPayment (optional)

1
uint256 public minTotalPayment;
Copied!
Min payment for token amount.

maxTotalPayment

1
uint256 public maxTotalPayment;
Copied!
Max payment for token amount.
This is an independent constraint from allocation. If a user's allocation determines that they can buy a maximum amount of sale tokens for X payment tokens, then the user's maximum is whichever is smaller, X or maxTotalPayment.

saleTokenAllocationOverride (optional)

1
uint256 public saleTokenAllocationOverride;
Copied!
Flat allocation override for all participants.

Non Internal Functions

constructor

1
constructor(
2
uint256 _salePrice,
3
address _funder,
4
ERC20 _paymentToken,
5
ERC20 _saleToken,
6
IFAllocationMaster _allocationMaster,
7
uint24 _trackId,
8
uint80 _allocSnapshotBlock,
9
uint256 _startBlock,
10
uint256 _endBlock,
11
uint256 _maxTotalPayment
12
) {
13
salePrice = _salePrice;
14
funder = _funder;
15
paymentToken = _paymentToken;
16
saleToken = _saleToken;
17
allocationMaster = _allocationMaster;
18
trackId = _trackId;
19
allocSnapshotBlock = _allocSnapshotBlock;
20
startBlock = _startBlock;
21
endBlock = _endBlock;
22
maxTotalPayment = _maxTotalPayment;
23
}
Copied!

fund

1
function fund(uint256 amount) external onlyFunder
Copied!
Function for funding sale with sale token (called by project team).
Note that if sale tokens are sent to this contract outside of calling fund, they will not be used in the sale. The variable saleAmount tracks how many sale tokens to sell, and it only increases by calling fund. The purchase / withdraw functions use saleAmount in the denominator when computing the appropriate fractions of tokens purchased / withdrawn to participants.
However, if sale tokens are accidentally sent directly to the contract, the project team can withdraw those tokens using cash at the end of the sale.
Can only be called before sale begins.

setMinTotalPayment

1
function setMinTotalPayment(uint256 _minTotalPayment) external onlyOwner
Copied!
Function for owner to set an optional, minimum total payment.
Can only be called before sale begins.

setSaleTokenAllocationOverride

1
function setSaleTokenAllocationOverride(
2
uint256 _saleTokenAllocationOverride
3
) external onlyOwner
Copied!
Function for owner to set an optional, sale token allocation override.
Can only be called before sale begins.

setCasher

1
function setCasher(address _casher) external onlyOwner
Copied!
Function for owner to set an optional, separate casher.
Can only be called before sale begins.

setWhitelistSetter

1
function setWhitelistSetter(address _whitelistSetter) external onlyOwner
Copied!
Function for owner to set an optional, separate whitelist setter.
Can only be called before sale begins.

setWhitelist

1
function setWhitelist(bytes32 _whitelistRootHash)
2
external
3
onlyWhitelistSetterOrOwner
Copied!
Function for owner or whitelist setter to set the whitelist.
Can be called any time, even during sale.

setWithdrawDelay

1
function setWithdrawDelay(uint24 _withdrawDelay) external onlyOwner
Copied!
Function for owner to set a withdraw delay.
Can be called at any time, even during sale.

checkWhitelist

1
function checkWhitelist(address user, bytes32[] calldata merkleProof)
2
public
3
view
4
returns (bool)
Copied!
Function for checking merkle proof against provided user address.

getTotalPaymentAllocation

1
function getTotalPaymentAllocation(address user)
2
public
3
view
4
returns (uint256)
Copied!
Function to get the total allocation of a user in allocation sale.
Allocation is calculated via the override if set, and otherwise allocation is calculated by the allocation master data.

getMaxPayment

1
function getMaxPayment(address user) public view returns (uint256)
Copied!
Function to get the max remaining amount of allocation for a user (in terms of payment token).
It is whichever is smaller:
    1.
    user's payment allocation, which is determined by:
      1.
      the allocation master
      2.
      the allocation override
    2.
    maxTotalPayment

purchase

1
function purchase(uint256 paymentAmount) external
Copied!
Function for making purchase in allocation sale when there is no whitelist set.
Can only be called during sale period.

whitelistedPurchase

1
function whitelistedPurchase(
2
uint256 paymentAmount,
3
bytes32[] calldata merkleProof
4
) external
Copied!
Function for making purchase in allocation sale when there is a whitelist set.
Can only be called during sale period.

withdraw

1
function withdraw() external
Copied!
Function for withdrawing purchased sale token.
Can be called only once and only after sale end.

withdrawGiveaway

1
function withdrawGiveaway(bytes32[] calldata merkleProof)
2
external
Copied!
Function for withdrawing (redeeming) sale tokens from a zero cost "giveaway" sale.
Can be called only once and only after sale end.

cash

1
function cash() external onlyCasherOrOwner
Copied!
Function for funder to cash in payment token and unpurchased sale token.
Can be called only once and only after sale end.

emergencyTokenRetrieve

1
function emergencyTokenRetrieve(address token) external onlyOwner
Copied!
Retrieve tokens erroneously sent in to this address.
Can withdraw any token EXCEPT for sale or payment token.

Other useful notes

Computing remaining

There isn't a view function that returns the remaining sale amount, but this can be easily calculated:
    1.
    Get public variable totalPaymentReceived.
    2.
    Get public variable salePrice.
    3.
    Calculate the current amount of sale tokens purchased (say saleTokensPurchased) with paymentReceived*SALE_PRICE_DECIMALS/salePrice.
      1.
      Keep in mind that salePrice is in units of paymentToken/saleToken with SALE_PRICE_DECIMALS decimals.
    4.
    Finally, get the amount of remaining sale tokens with saleAmount-saleTokensPurchased.
Last modified 1mo ago