-
Notifications
You must be signed in to change notification settings - Fork 37
Home
Version 1.1.0 - Last updated: Jul 6th 2020
The goal of this wiki is to provide a reference specification for the smart-contract(s) implementing the continuous financing model described in the continuous organizations whitepaper. The continuous financing model enables organizations to finance themselves in a permission-less and non-dilutive way by continuously issuing tokens called FAIR while aligning stakeholders to their financial success.
On a high-level, the contract acts as a state machine with 3 states:
-
initstate. The default state when the c-org contract is instantiated. In this state, the c-org is initializing and needs to sell a minimum amount of FAIR (init_goal) to switch to therunstate. Onlybeneficiaryis allowed to transfer tokens during this state. All other participants can onlybuy()orsell(). -
runstate. The c-org is running and accepting investments using the bonding curve contract model described in the whitepaper. -
closestate. The c-org closing, paying out every FAIR holder and not accepting investments anymore. To close the c-org, thebeneficiaryneeds to escrow theexit_feeand call theclose()function. -
cancelstate. The c-org got cancelled (by callingclose()) while still ininitstate.
-
init_investors. A map with all investors ininitstate usingaddressas a key andamount(in FAIR) as value. This structure's purpose is to make sure that only investors can withdraw their money ifinit_goalis not reached.
These constants are preset in the contract.
-
currency. The address of the token used as reserve in the bonding curve (i.e. the DAI contract). UseETHif0. -
init_reserve. The initial number of FAIR created at initialization for thebeneficiary. Technically however, this variable is not a constant as we must always haveinit_reserve<=total_supply+burnt_supplywhich means thatinit_reservewill be automatically decreased to equaltotal_supply+burnt_supplyin caseinit_reserve>total_supply+burnt_supplyafter an investor sells his FAIRs. -
init_goal. The initial fundraising goal (expressed in FAIR) to start the c-org.0means that there is no initial fundraising and the c-org immediately moves torunstate. -
buy_slope. The buy slope of the bonding curve. Does not affect the financial model, only the granularity of FAIR. -
investment_reserve. The investment reserve of the c-org. Defines the percentage of the value invested that is automatically funneled and held into thebuyback_reserve. -
setup_fee. The success fee (expressed incurrency) that will be earned bysetup_fee_recipientas soon asinit_goalis reached. We must havesetup_fee <= buy_slope*init_goal^(2)/2. -
setup_fee_recipient. The recipient of thesetup_feeonceinit_goalis reached.
These variables are preset in the contract but can be altered under certain conditions once the contract is deployed. The variables can be updated using the control address. We highly recommend that this control address be a multisig to prevent unilateral modification of these variables.
-
control. The address from which the updatable variables (see below) can be updated. Defaults to the contract deployer. -
beneficiary. The address of the beneficiary organization which receives the investments. Points to the wallet of the organization. Defaults to the contract deployer. -
fee. The fee collected each time new FAIR are issued. Defaults to0%. -
fee_collector. The address where fees are sent. Defaults to the contract deployer. -
min_investment. The minimum investment accepted. Defaults to100. -
minimum_duration. The minimum time before which the c-org contract cannot be closed once the contract has reached therunstate. When updated, the new value ofminimum_durationcannot be earlier than the previousminimum_duration. To set infinite duration, setminimum_duration=MAX_UINT. -
whitelistrefers to the contracts in charge of enforcing the legal restrictions related to the c-org (lock-up periods, no flow-back, transfer restrictions etc...). The contract referred bywhitelistis modeled after the ERC-1404 (with one addition). Set whitelist to0if you don't want to enforce on-chain legal restrictions, we advise you to seek for legal advise before doing so. Just make sure you know what you're doing. -
revenue_commitment. The "on-chain" revenue commitment of the organization. If the organization has its revenues off-chain,revenue_commitmentis set to0. To protect investors, it is important to note that the revenue commitment can be increased but can never be decreased.
These variables are the result of a calculation based on other variables. A key variable in the c-org model is the sell_slope, the sell slope of the bonding curve. It is actually not coded as a variable in this contract but is being calculated on demand (with sell_slope=(2*buyback_reserve)/((total_supply+burnt_supply)^2)) to avoid rounding issues. Other key variables non-coded are issuance_price, the current issuance price for FAIR which equals (total_supply+burnt_supply-init_reserve)*buy_slope and buyback_price, the current minimum buy-back price which equals (total_supply+burnt_supply)*sell_slope + (sell_slope*burnt_supply^2)/(2*total_supply).
-
state. The current state of the contract:0=init,1=run,2=close. Unlessinit_goalequals0, default isinitotherwise default isrun. Onceinit_goalis reached,statechanges torun. Finallystateswitches toclosewhenexit_feeis paid. -
buyback_reserve. The total amount of value currently locked in the buyback reserve. Thebuyback_reserveshould be implemented as the current contract balance of thecurrency(instead of a separate variable). -
total_supply. The total outstanding supply of FAIR issued, including the pre-minted FAIRs (seeinit_reserve) but excluding burnt FAIRs (seeburnt_supply). -
burnt_supply. The total number of FAIR burnt. -
run_started_on. Initialized at0and updated when the contract switches frominitstate torunstate with the current timestamp.
Method called to buy FAIR. When buy() is called:
When in init state, every investor receives tokens for the same price until init_goal is reached. beneficiary is the only one allowed to transfer() FAIRs from init_reserve if any (ideally using vesting schedules). The investor is the caller or to if specified. Note that minimum is discarded in init state.
- If investor is not allowed to buy FAIR (see compliance below), then the function exits.
- If
amount < min_investment, then the function exits. - If
amount > (buy_slope*init_goal)*(init_goal-total_supply+init_reserve)thennext_amount=amount - (buy_slope*init_goal)*(init_goal-total_supply+init_reserve)amount=amount - next_amount
- if
next_amount>0thenadditional_tokens=((2*next_amount/buy_slope)+init_goal^2)^(1/2)-init_goalelseadditional_tokens=0 - Add
xto the investor's balance withx=amount/(buy_slope*init_goal)+additional_tokens. - Increase
total_supplywithxnew FAIRs. - Add
amountto thebuyback_reserve. - Save investor's total investment in
init_investors[address]+=x. - If
total_supply - init_reserve >= init_goal, then:-
state=run. - calculate the amount
yinvested by the beneficiary during init withy=init_investors[beneficiary]*buy_slope*init_goal - if
setup_fee>0then- send
setup_feefrombuyback_reservetosetup_fee_recipient - update
buyback_reserve=buyback_reserve-setup_fee - if
y>0 && y>setup_feetheny=y-setup_fee - else if
y>0theny=0
- send
- send
(buyback_reserve-y)*(1-investment_reserve)*(1-fee)to thebeneficiary - send
(buyback_reserve-y)*(1-investment_reserve)*feeto thefee_collector - update
buyback_reserve = investment_reserve * (buyback_reserve-y) + y -
run_started_on=<current_timestamp>.
-
- If the investor is not allowed to buy FAIR (see compliance), then the function exits.
- If
amount < min_investment, then the function exits. - Calculate the number of FAIR
xthat the investor should receive for his investment withx=sqrt((2*amount/buy_slope)+(total_supply-init_reserve+burnt_supply)^2)-(total_supply-init_reserve+burnt_supply). - If
x < minimumthen the call fails. This is a protection against large price movements and front-running attacks. - Add
xFAIRs to the investor's balance. - Increase
total_supplywithxnew FAIRs. - If the investor is the
beneficiary, then the fullamountis added to thebuyback_reserve. - If the investor is not the
beneficiary, then:-
investment_reserve*amountis being added to thebuyback_reserve -
(1-investment_reserve)*amount*(1-fee)is being transfered tobeneficiary. -
(1-investment_reserve)*amount*feeis being sent tofee_collector
-
The buy() functions fails in close state.
Method called to sell FAIR. It is important to note that beneficiary is only allowed to sell in close state or cancel state, beneficiary cannot sell in any other state. When sell() is called:
In init state, the minimum parameter is ignored.
- If
address == beneficiary, then the function exits. - If
init_investors[address]does not exists, then the function exits. Prevents the receivers of free FAIR frominit_reserveto sell them at this time. - If
init_investors[address]<amountthen the call fails. Prevents the receivers of free FAIR frominit_reserveto sell them at this time. -
amountis being substracted from the investor's balance. - The investor receives
xcollateral value from thebuyback_reservewithx=amount*buyback_reserve/(total_supply-init_reserve). - Save investor's total withdrawal in
init_investors[address]-=amount. - The
total_supplyis decreased ofamountFAIRs.
- If
address == beneficiary, then the function exits. - If
init_goal=0 && buyback_reserve=0, then the function exits. - The collateral value
xthat the investor should receive from the buyback reserve is calculated withx=(total_supply+burnt_supply)*amount*sell_slope-((sell_slope*amount^2)/2)+(sell_slope*amount*burnt_supply^2)/(2*(total_supply))withsell_slope=(2*buyback_reserve)/((total_supply+burnt_supply)^2). - If
x < minimumthen the call fails. -
amountis being substracted from the investor's balance if it is superior or equal toamount. Otherwise the call fails. - The investor receives
xcollateral value from the buyback reserve - Substract
amountFAIRs fromtotal_supplyto remove the sold FAIRs from the outstanding supply. - If
init_reserve>total_supply+burnt_supplythen setinit_reserve=total_supply+burnt_supply
In close state, the minimum parameter is ignored.
-
amountis being substracted from the investor's balance if their balance is superior or equal toamount. Otherwise the call fails. - The investor receives
xcollateral value from the buyback reserve withx=buyback_reserve*amount/total_supply. - Substract
amountFAIRs fromtotal_supplyto remove the sold FAIRs from the outstanding supply.
In cancel state, the minimum parameter is ignored.
- If
init_investors[address]does not exists, then the function exits. Prevents the receivers of free FAIR frominit_reserveto sell them at this time. - If
init_investors[address]<amountthen the call fails. Prevents the receivers of free FAIR frominit_reserveto sell them at this time. -
amountis being substracted from the investor's balance. - The investor receives
xcollateral value from thebuyback_reservewithx=amount*buyback_reserve/(total_supply-init_reserve). - Save investor's total withdrawal in
init_investors[address]-=amount. - The
total_supplyis decreased ofamountFAIRs.
Method called to burn FAIR. When burn() is called:
- If
state != 'run'then the function exits. - Burn
amountFAIRs by addingamounttoburnt_supply. - Substract
amountfromtotal_supply
The burn() method fails during init, close and cancel states.
Method called to pay the organization on-chain. This is the payable method call when a transaction is sent to the c-org contract. If to is specified and to is allowed to receive FAIRs, then to should receive the newly minted FAIRs. In the case where to is not specified, the new FAIRs go to beneficiary. When pay() is called:
- If
state != 'run'then the function exits. -
revenue_commitment*amountis being added to thebuyback_reserveand(1-revenue_commitment)*amountis being transferred to thebeneficiary.
The pay() method fails during init, close and cancel states.
Method called to close the c-org contract. To close the c-org contract, the beneficiary needs to pay an exit_fee = total_supply*(total_supply+burnt_supply)*buy_slope - buyback_reserve.
- If
address != beneficiarythen the function exits. - If
state == 'close' OR state == 'cancel'then the function exits. - If
state == 'init'thenstate = 'cancel' - If
state == 'run'andnow > run_started_on + minimum_durationthen- if
balanceOf(beneficiary) < (total_supply^2 * buy_slope)/2 + burnt_supply*buy_slope*total_supply - buyback_reservethen the function exits. -
state = 'close'. - substract
(total_supply^2 * buy_slope)/2 + burnt_supply*buy_slope*total_supply - buyback_reservefrom the balance ofbeneficiary. -
buyback_reserve = (total_supply^2 * buy_slope)/2 + burnt_supply*buy_slope*total_supply.
- if
The c-org contract is highly sensitive due to the funds it holds in its reserve and due to the potential number of investors it coordinates. Fairmint is committed to provide the community with c-org contracts of the highest quality and providing the highest security. It is expected that other contracts respecting the below specification will be developed by third-parties. If you are a developer developing a c-org contract on any blockchain, please get in touch with us to make sure we DO NOT release buggy or deceptive contracts on the market. Likewise, if you are a user of a contract not developed or not audited techically, economically and legally by Fairmint, please be very cautious as you might put your money and the money of your investors at risk. Obviously, Fairmint offers no warranty and is not responsible nor liable for any of the contracts implementing this specification. Use them at your own risk.