Skip to content

refcell/twam

Repository files navigation

TWAM • tests lints GitHub GitHub package.json version

Time Weighted Asset Mints

A minting harness enabling time-weighted assets to determine minting prices.

How it works

TwamFactory manages creating TWAM Sessions.

A given TWAM Session can be created permissionlessly. With two requirements:

  • The session creator sets the TwamFactory ERC721 token balance to at least maxMiningAmount.
  • The session creator then transfers 1 ERC721 token to the TwamFactory to verify they are the owner of the ERC721 Tokens.

The singular ERC721 Token transfer is required to trigger the TwamFactory's onERC721Received hook that sets the approved session creator.

This comes with assumptions:

  • The creator owns all ERC721 Tokens to start with before doing a sale (or they risk another owner frontrunning the session creation).
  • ERC721 Tokens [0-maxMintingAmount] are owned by the TwamFactory since sales are done sequentially.

When a TWAM Session is created using the TwamFactory's createTwam function, a minimal proxy contract is created using the arguments as immutables (h/t ZeframLou).

TWAM Session Parameters

token - The address of the ERC721 Contract. coordinator - The sale profit receiver. allocationStart - The timestamp when the allocation period begins. allocationEnd - The timestamp when the allocation period ends. mintingStart - The timestamp when the minting period begins. mintingEnd - The timestamp when the minting period ends. minPrice - The minimum price per ERC721 token. depositToken - The address of the ERC20 token that is paid by users. maxMintingAmount - The maximum number of ERC721 Tokens available for sale. rolloverOption - Option in {1, 2, 3} indicating what happens when a Session ends.

TWAM Session Lifecycle

For a given mint's allocationPeriod (let's use 24 hours), a given type of asset can be deposited into the twam contract. Note: during the allocationPeriod, the deposit token cannot be withdrawn.

Additionally, a loss penalty is calculated with respect to when you deposit in the allocation period. The later you deposit, the more of a penalty you will occur if you choose to forgo minting. This prevents spoofing allocations, helping those who are genuinely interested in minting the ERC721 token.

NOTE: if someones total deposits in a session aren't enough to mint at least one ERC721 token based on price, withdrawals are allowed without a penalty.

Once the allocationPeriod ends, a cooldown period begins with a length of mintingStart - allocationEnd. At this time, no more deposits are permitted.

Note: there may be no cooldown if mintingStart = allocationEnd.

At the beginning of the minting period mintingStart, each ERC721 can be minted at the price equal to (total allocated assets) / (maximum supply ERC721 tokens) as long as it exceeds the minPrice TWAM session parameter.

If the minPrice is not reached, minting is prohibited, and nothing happens during the minting period.

If all tokens are minted at the end of the minting period, the session is completed.

Otherwise (when the minimumPrice isn't met or not all tokens are minted), one of three options are available based on the Session's rolloverOption:

  1. The TWAM Session starts over again.
  2. Minting is enabled at the max{resultPrice, minimumPrice}.
  3. The session is ended.

The Session's rolloverOption may only be one of these three.

Minter Functions

deposit(uint256) - Deposits a uint256 amount into the Session during the allocation period. withdraw(uint256) - Allows a user to withdraw after the Session ends (mintingEnd is passed) and the rolloverOption is 3. mint(uint256) - Mints a number of ERC721 tokens to a user during the minting period as calculated by uint256 / resultPrice where resultPrice is the final price per ERC721 token. forgo(uint256) - Allows a user to withdraw their deposited token, giving up their minting allocation. This may incur a loss penalty as a function of when the deposits are made.

Coordinator Functions

rollover() - Allows the coordinator to rollover the Session if the minting is over - only sets the rolloverOffset if the rolloverOption is one of {1,2}. withdrawRewards() - Withdraws the deposit tokens earned by the coordinator in exchange for the minted ERC721 Tokens.

Blueprint

lib
├─ clones-with-immutable-args — https://github.com/ZeframLou/clones-with-immutable-args
├─ ds-test — https://github.com/dapphub/ds-test
├─ forge-std — https://github.com/brockelmore/forge-std
├─ solmate — https://github.com/Rari-Capital/solmate
src
├─ tests
│  ├─ TwamBase.t — "Primary TWAM Functionality Tests"
│  └─ TwamFactory.t — "Proxy and TwamBase Deployment Tests"
├─ TwamBase"Time Weighted Asset Mint Logic Contract"
└─ TwamFactory"Minimal Proxy Deployer"

Development

Install DappTools

Install DappTools using their installation guide.

First time with Forge/Foundry?

Don't have rust installed? Run

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

Then, install foundry with:

cargo install --git https://github.com/gakonst/foundry --bin forge --locked

Setup and Build

make

Run Tests

make test

License

AGPL-3.0-only

Acknowledgements

Disclaimer

These smart contracts are being provided as is. No guarantee, representation or warranty is being made, express or implied, as to the safety or correctness of the user interface or the smart contracts. They have not been audited and as such there can be no assurance they will work as intended, and users may experience delays, failures, errors, omissions, loss of transmitted information or loss of funds. The creators are not liable for any of the foregoing. Users should proceed with caution and use at their own risk.