From bcf77eccc9612b4c99e88c8db22bd59edc5f81c9 Mon Sep 17 00:00:00 2001 From: marcusnewton Date: Sun, 3 Oct 2021 02:27:50 +0000 Subject: [PATCH] update versioned docs folder (automated) --- .../version-v0.0.11/Glossary.md | 51 ++++ .../version-v0.0.11/Introduction.md | 84 ++++++ .../version-v0.0.11/RiskMitigation.md | 262 ++++++++++++++++++ .../api/claim/TierByConstructionClaim.md | 106 +++++++ .../version-v0.0.11/api/cooldown/Cooldown.md | 65 +++++ .../version-v0.0.11/api/factory/Factory.md | 46 +++ .../version-v0.0.11/api/factory/IFactory.md | 35 +++ .../version-v0.0.11/api/libraries/TierUtil.md | 88 ++++++ .../version-v0.0.11/api/phased/Phased.md | 135 +++++++++ .../api/pool/IBalancerConstants.md | 39 +++ .../version-v0.0.11/api/pool/ICRPFactory.md | 13 + .../api/pool/IConfigurableRightsPool.md | 37 +++ .../api/pool/RedeemableERC20Pool.md | 101 +++++++ .../api/pool/RedeemableERC20PoolFactory.md | 47 ++++ .../api/redeemableERC20/RedeemableERC20.md | 206 ++++++++++++++ .../redeemableERC20/RedeemableERC20Factory.md | 34 +++ .../version-v0.0.11/api/seed/SeedERC20.md | 145 ++++++++++ .../api/seed/SeedERC20Factory.md | 34 +++ .../version-v0.0.11/api/tier/AlwaysTier.md | 33 +++ .../api/tier/ERC20BalanceTier.md | 58 ++++ .../api/tier/ERC20TransferTier.md | 69 +++++ .../version-v0.0.11/api/tier/ITier.md | 168 +++++++++++ .../version-v0.0.11/api/tier/NeverTier.md | 33 +++ .../version-v0.0.11/api/tier/ReadOnlyTier.md | 36 +++ .../version-v0.0.11/api/tier/ReadWriteTier.md | 73 +++++ .../api/tier/TierByConstruction.md | 80 ++++++ .../version-v0.0.11/api/tier/ValueTier.md | 44 +++ .../version-v0.0.11/api/tier/VerifyTier.md | 37 +++ .../version-v0.0.11/api/trust/Trust.md | 183 ++++++++++++ .../version-v0.0.11/api/trust/TrustFactory.md | 56 ++++ .../version-v0.0.11/api/verify/Verify.md | 91 ++++++ .../api/verify/VerifyFactory.md | 34 +++ .../version-v0.0.11-sidebars.json | 28 ++ docusaurus/versions.json | 1 + 34 files changed, 2552 insertions(+) create mode 100644 docusaurus/versioned_docs/version-v0.0.11/Glossary.md create mode 100644 docusaurus/versioned_docs/version-v0.0.11/Introduction.md create mode 100644 docusaurus/versioned_docs/version-v0.0.11/RiskMitigation.md create mode 100644 docusaurus/versioned_docs/version-v0.0.11/api/claim/TierByConstructionClaim.md create mode 100644 docusaurus/versioned_docs/version-v0.0.11/api/cooldown/Cooldown.md create mode 100644 docusaurus/versioned_docs/version-v0.0.11/api/factory/Factory.md create mode 100644 docusaurus/versioned_docs/version-v0.0.11/api/factory/IFactory.md create mode 100644 docusaurus/versioned_docs/version-v0.0.11/api/libraries/TierUtil.md create mode 100644 docusaurus/versioned_docs/version-v0.0.11/api/phased/Phased.md create mode 100644 docusaurus/versioned_docs/version-v0.0.11/api/pool/IBalancerConstants.md create mode 100644 docusaurus/versioned_docs/version-v0.0.11/api/pool/ICRPFactory.md create mode 100644 docusaurus/versioned_docs/version-v0.0.11/api/pool/IConfigurableRightsPool.md create mode 100644 docusaurus/versioned_docs/version-v0.0.11/api/pool/RedeemableERC20Pool.md create mode 100644 docusaurus/versioned_docs/version-v0.0.11/api/pool/RedeemableERC20PoolFactory.md create mode 100644 docusaurus/versioned_docs/version-v0.0.11/api/redeemableERC20/RedeemableERC20.md create mode 100644 docusaurus/versioned_docs/version-v0.0.11/api/redeemableERC20/RedeemableERC20Factory.md create mode 100644 docusaurus/versioned_docs/version-v0.0.11/api/seed/SeedERC20.md create mode 100644 docusaurus/versioned_docs/version-v0.0.11/api/seed/SeedERC20Factory.md create mode 100644 docusaurus/versioned_docs/version-v0.0.11/api/tier/AlwaysTier.md create mode 100644 docusaurus/versioned_docs/version-v0.0.11/api/tier/ERC20BalanceTier.md create mode 100644 docusaurus/versioned_docs/version-v0.0.11/api/tier/ERC20TransferTier.md create mode 100644 docusaurus/versioned_docs/version-v0.0.11/api/tier/ITier.md create mode 100644 docusaurus/versioned_docs/version-v0.0.11/api/tier/NeverTier.md create mode 100644 docusaurus/versioned_docs/version-v0.0.11/api/tier/ReadOnlyTier.md create mode 100644 docusaurus/versioned_docs/version-v0.0.11/api/tier/ReadWriteTier.md create mode 100644 docusaurus/versioned_docs/version-v0.0.11/api/tier/TierByConstruction.md create mode 100644 docusaurus/versioned_docs/version-v0.0.11/api/tier/ValueTier.md create mode 100644 docusaurus/versioned_docs/version-v0.0.11/api/tier/VerifyTier.md create mode 100644 docusaurus/versioned_docs/version-v0.0.11/api/trust/Trust.md create mode 100644 docusaurus/versioned_docs/version-v0.0.11/api/trust/TrustFactory.md create mode 100644 docusaurus/versioned_docs/version-v0.0.11/api/verify/Verify.md create mode 100644 docusaurus/versioned_docs/version-v0.0.11/api/verify/VerifyFactory.md create mode 100644 docusaurus/versioned_sidebars/version-v0.0.11-sidebars.json diff --git a/docusaurus/versioned_docs/version-v0.0.11/Glossary.md b/docusaurus/versioned_docs/version-v0.0.11/Glossary.md new file mode 100644 index 000000000..d687394fe --- /dev/null +++ b/docusaurus/versioned_docs/version-v0.0.11/Glossary.md @@ -0,0 +1,51 @@ +--- +id: glossary +slug: /glossary +title: Glossary +--- + +### Seeder + +A contract or address that sends reserve token to the `Trust` before distribution starts to bootstrap the ability to trade. + +After the distribution completes the seeder is refunded their reserve tokens plus an optional seeder fee. + +### Reserve token + +The token that exists before the distribution starts and is provided by the seeder to be the other side of the pair in the Balancer pool. + +This token is expected to be valuable and liquid so that the creator can fund their creation process with it. + +### Redeemable token + +The token that is minted by the `Trust` and distributed by trading during the distribution phase. + +The redeemable token is frozen (impossible to transfer) after the distribution phase ends. + +The redeemable token can be burned for a pro-rata redemption of any erc20 tokens the redeemable token contract itself owns. + +### Liquidity Bootstrapping Pool + +The 'Liquidity Bootstrapping Pool' (LBP) is a style of AMM developed by Balancer. + +It simulates a Dutch Auction through Balancer's spot price mechanism as a combination of weight and relative token amounts. + +Empirical evidence from the [PERP token distribution](https://medium.com/balancer-protocol/a-new-paradigm-for-token-distribution-c82de13626bb) indicates this is a decent mechanism to achieve a wider and 'fairer' distribution of tokens than a simple AMM listing. + +Fairness is hard to define objectively, but for our purposes we want to: + +- Minimise scalping, i.e. users buying early with the intent to sell at a higher price to users who want the token utility +- Maximise the value unlocked by the distribution in terms of the reserve token +- Mimimise whales, i.e. users who buy a significant percentage of the total token supply with the intent to manipulate the price paid by users who want the token utility +- Allow for subjective valuation by users who want the token utility +- Protect the interests of users who want to hodl the token for its utility +- Avoid economic exploits that allow users to leverage mechanisms provided by other smart contracts to extract value from the pool for themselves (e.g. flash loan style attacks) +- Allow for efficient price discovery +- Mitigate 'front running' where a user (bot) sends orders in advance of (with higher gas than) another trade when it is visible in the mempool but not yet included in a block, in order to force the other user to pay a higher spot price and then immediately dump on this (almost) guaranteed higher price + +The [Balancer Whitepaper](https://balancer.finance/whitepaper/) outlines the formulas and proofs (relevant extracts in the comments in this codebase) used to define spot price in terms of amount and weight of each token in the pool. + +The target/final weights of the distribution phase give a spot price equal to the book value of the token _assuming no trades_. +This means the maximum possible dump of the pool at the lowest possible weight (i.e. 100% of all tokens are dumped) is equal to the configured final valuation. + +The [Balancer documentation](https://docs.balancer.finance/) is the best reference for more details on how this works. diff --git a/docusaurus/versioned_docs/version-v0.0.11/Introduction.md b/docusaurus/versioned_docs/version-v0.0.11/Introduction.md new file mode 100644 index 000000000..eb83de1f0 --- /dev/null +++ b/docusaurus/versioned_docs/version-v0.0.11/Introduction.md @@ -0,0 +1,84 @@ +--- +id: introduction +slug: / +title: Introduction +--- + +Rain Protocol supports fair value capture for intangible or physical assets in a permissionless way in any decentralised environment. + +We use Balancer's [Liquidity Bootstrapping Pool](https://docs.balancer.finance/smart-contracts/smart-pools/liquidity-bootstrapping-faq) to distribute the tokens. + +The goal is to achieve something analogous to KickStarter where specific projects and events are made possible through a one-time fundraising. + +## Overview + +The basic process is: + +- The trust and pools are established with a freshly minted project/event token and some starting capital for trading +- The liquidity bootstrapping pool is used to distribute the freshly minted tokens +- The pool is closed + - Some of the raised funds are forwarded to the minted token contract + - The creator receives the bulk of the raised funds + - Some fees are distributed to other stakeholders +- Any undistributed tokens are burned and all distributed tokens are frozen +- The creator creates and distributes rewards over time in many ways: + - Creating claimable NFTs and other perks that require claimants to hold a minimum balance of the distributed token + - Sending erc20 tokens to the distributed token contract that require claimants to burn their tokens to redeem + - Hosting real world exclusive events etc. that require claimants to hold a minimum balance of the distributed token to participate + +The process requires a high degree of trust between the creator and their fans as there is no on-chain mechanism to enforce delivery of any perks. + +The token minting, distribution, burning is all trustless as the deployed `Trust` contract handles construction and ownership of the other contracts. + +As each `Trust` is dedicated to a specific project or event there are no admin or upgrade functions. Future versions of `Trust` will simply be picked up by new projects and events as they arise. + +The `Trust` has native integration with the `Tier` membership system included as a git submodule. Any account that does not have a minimum membership status cannot receive the distributed token and so cannot participate. This allows additional requirements to be placed on the participants by the deployer of the trust. + +## A note on regulatory compliance + +Any legal or regulatory requirements such as KYC/AML or securities law are the responsibility of the stakeholders. + +The stakeholders are: + +- The deployer of the `Trust` contract who provides all the initial configuration parameters and pays the gas for deployment +- The creator who is raising money to create some new value in the world +- The token holders who trade tokens during the distribution phase on the Balancer pool and then hold frozen tokens after the distribution finishes +- The seeder who provides the initial tokens on the other side of the Balancer trading pool to bootstrap trading + +Without offering legal advice, one hypothetical way this could look (something like KickStarter): + +- The creator and deployer of the `Trust` creates a `Tier` contract that allows only close friends and family to hold a membership status +- The creator, who is a crypto-enthusiast and musician, decides to hold an intimate "fans only" event, using signatures from the accounts holding a frozen token balance as tickets to her event + +As the creator knows all her fans, and the token balances are frozen (cannot be traded on a secondary market), and the reward for holding the tokens is a one-time in person event, it's unlikely to be considered a public sale of an investment contract (for example) or cause KYC issues. + +Another situation could be (along the lines of Kiva): + +- The creator of the `Trust` lives in a remote village in a poor country and needs a new roof for her house +- She creates a small social media campaign for her own and surrounding villages to raise the money she needs, and airdrops a cute NFT to everyone who helped + +As none of the participants in the system are American, the SEC has no jurisdiction, and the raised money is being used directly to fix a private individual's home so it is not an investment. The NFT has only sentimental value as a "thank you" note between neighbours. + +Of course, the same system could be used to facilitate something that is probably regulated by the SEC: + +- An American creator and deployer of the `Trust` actively promotes sale of the minted tokens to a global audience +- The creator uses the raised capital to purchase real estate and regularly airdrops the rent received to all token holders + +In this case it is hard to see how the fundraise is not simply a public sale of an investment contract, by an American, for Americans, but with weird extra steps by using `Trust`. The creator, as an American, would need to ensure (presumably offchain somehow) that they are meeting their local regulatory requirements. + +The nature of data in a public blockchain is no different to a public Google spreadsheet. That is to say, it has no knowledge of or control over what the numbers and balances it calculates represent in the real world. This can only be made visible and accountable through curation by humans. The `Trust` contract is simply tracking the flow of existing tokens towards the creator and newly minted tokens distributed away from the creator, then frozen so the creator can reference them later. + +## Roadmap + +Our goal is to build a free and open source system that makes it as easy and affordable as possible for creators to deploy `Trust` contracts that are secure and can meet local laws and regulations, without positioning ourselves as the gatekeeper of every possible use-case. + +The current roadmap towards this goal: + +- [x] Create the basic contracts needed to facilitate each phase +- [x] Audit and open source everything in a combined public repository +- [x] Create factory contracts that register deployed contracts and allow for automatic verification of the authenticity of a `Trust` +- [ ] Create SDKs and incentives to foster global permissionless CURATION of raises across many independent GUIs, platforms and blockchains +- [ ] Facilitate Token Lists and Kleros style layers of additional CURATION to protect users and platforms from illicit activities +- [ ] More KYC/AML tools for creators +- [ ] More distribution mechanisms +- [ ] Data analytics and tools for better CURATION diff --git a/docusaurus/versioned_docs/version-v0.0.11/RiskMitigation.md b/docusaurus/versioned_docs/version-v0.0.11/RiskMitigation.md new file mode 100644 index 000000000..2aefc1102 --- /dev/null +++ b/docusaurus/versioned_docs/version-v0.0.11/RiskMitigation.md @@ -0,0 +1,262 @@ +--- +id: risk-mitigation +slug: /risk-mitigation +title: Risk Mitigation +--- + +### Minimum raise threshold + +The `Trust` contract has minimum redeem init, creator raise and seeder fee parameters (can both be zero). + +The distribution is considered successful if the total reserve deposited in the Balancer pool during the distribution phase (in addition to the initial seed) covers all three. + +In the case of a successful raise: + +- The creator raise will be forwarded to the creator +- The seeder will receive their original seed plus the seed fee minus pool dust +- The redeem init will be forwarded to the `RedeemableERC20` contract (can be redeemed via. burns) + +In the case of a failed raise: + +- The creator gets nothing +- The seeder receives their original seed minus pool dust +- All remaining reserve assets are forwarded to the `RedeemableERC20` contract (can be redeemed via. burns) + +Note that reserve assets forwarded to the `RedeemableERC20` contract are redeemed pro-rata in both cases. This means that in the case of a failed raise a token holder could redeem their tokens for more or less reserve than they swapped originally, as they will be redeeming for the _average_ swap value, not _their_ swap value. + +This mechanism: + +- Protects everyone in the case that the raised reserve is too low for the creator to do what they wanted +- Incentivises token purchases when the price is lower than average if a raise is close to failing, thus making it more likely to succeed + +### Maximum raise + +The creator starts the price of tokens high in their own estimation, with the price gradually declining over the distribution. + +This protects the creator from over-raising and being unable to deliver. + +For example, an indie painter can only produce a few thousand $ worth of value in a single painting, if they raise a million $ they aren't suddenly going to paint the Mona Lisa. + +Raising too much can be just as problematic as raising too little, so we do our best to help creators raise "a lot" while still appropriately sizing all the parameters. + +### Stuck AMM + +The traditional approach of simply adding tokens to a pool on Uniswap results in a situation where the price can get 'stuck'. + +This means that early FOMO causes the first buyers pump the price very high on a single exchange, then nobody else can buy until some of these early buyers then sell tokens back to the AMM (direct spot price drop) or the market (arbitrage opportunity to recover price). + +Given that the whole point of distributing tokens is to get them in the hands of fans who should want to hodl them up to and beyond the start of the redemption period, we do NOT want to rely on secondary market selling just to allow more buyers to join. + +Put another way, the traditional approach _relies on scalpers_ to acheive smooth price discovery rather than a single pump then price stagnation. + +The mitigation is to use a combination of weights and amounts to define the spot price. This allows the weights to be adjusted downwards, lowering the spot price _without_ trades occuring, rewarding _later_ participants who are patient enough to allow the weights to give a better price for the same token supply in the AMM. + +Rewarding later participants rewards patience. + +Patient token buyers are more likely to be patient token hodlers. + +Patient token hodlers are more likely to enjoy and maximise the redemption phase. + +For example, Uniswap has a fixed weight of 1:1 and relies on arbitrage with external systems to maintain a fair spot price (i.e. Uniswap by definition assumes whatever token quantities are in any given pool are always of equivalent value). +Balancer does NOT assume the tokens in a given pool are of equal value, it allows any weighting of either token up to a 50:1 ratio (i.e. the total value of one token is up to 50x more than the other token). +When we can change the weighting of the tokens we can change the spot price without changing the token amounts. + +The weight curve is defined during the `Trust` deployment and kicked off during `anonStartDistribution`. + +Anyone can call the "update weights gradually" function on the pool, it is a public method, which brings the pool _weights_ back to the predefined curve according to the current block, which brings the spot price down. This means an arbitrage opportunity _against the weights_ exists and grows each block, where any user can call the weight recalculation function to give themselves a better spot price for the trade they want to make. + +Ignoring stampedes (many redundant weight updates in the same block) and MEV/front-running (another user positions their trade after the rebalance but before the desired trade), it is always profitable to rebalance the weights if the new spot price is better than the fees of the rebalance. This is because the weights monotonically drift downwards towards the book value floor. + +#### Overweight pool + +Balancer pools can never exceed a combined weight of `50` as the sum of the weights of the tokens. + +This is true even during a single operation so Balancer recommend never setting weights at exactly `50` if they need to change. + +We do need them to change according to the reweighting curve so there is a `POOL_HEADROOM` constant (currently `10 ** 18` which is "one" for Balancer math). +We require that the `Trust` bootstraps with combined weights equal to or lower than `BalancerConstants.MAX_WEIGHT - Constants.POOL_HEADROOM`. + +### Impermanent loss && price dumping + +Impermanent Loss (IL) is a near-ubiquitious issue in AMMs to be mitigated or at least discussed. + +In our case, because the Trust enforces that 100% of the freshly minted token is provided as liquidity in the AMM pool, the concept of IL doesn't quite apply. + +While it is true mathematically that, had the Trust hodled the tokens instead of providing them as liqudity, it would receive more value than putting them on the market, this is nonsensical in practise as hodling 100% of the tokens implies that there is no distribution and therefore no meaningful market! + +The worst case scenario is that zero trades occur, or equivalently, 100% of the token supply is dumped back into the pool in the same block that redemptions are unblocked. +In the worst case scenario, because the final weights are calculated against the final valuation that covers at leat the seeder, and the excess is forwarded to token holders, even the maximum theoretical token dump is safe for participants (albeit disappointing). + +### Pool dust + +Balancer pools cannot be totally shutdown (this has been confirmed by the Balancer team) so the larger of `10^-7` times the final reserve or `10 ** 6` absolute units of the reserve will be trapped in the pool on distribution end. + +This is unavoidable but usually harmless. The limitation gets worse for reserve assets with fewer `decimals`. For example, USDC and USDT only support `6` decimals rather than the standard `18` decimals for native erc20 tokens. This means that the minimum pool dust is $1 of USDC or USDT. + +For this reason we require that the minimum seed is `10 ** 8` ($100 for stables) so that the maximum theroetical pool dust is capped at 1% of the initial seed. + +This could make tokens with very small decimals in the range of `0 - 5` infeasible as reserve assets due to the minimum seed requirements being too large in the reserve denomination. + +### Rounding errors + +There are some rounding errors when burning/redeeming tokens that can cause the pro-rate token calculations to differ by one or two in absolute terms between otherwise identical redemptions. + +For tokens with `10 ** 18` decimals this should be harmless as the rounding error will be `10 ^ -18`. + +For tokens with very small decimals this may be problematic. + +### Whales + +Whales are a double edged sword in general. + +On one hand it is great when a large investor takes interest in a project as it is a big vote of confidence. + +Whales may represent a buyer with long term goals well aligned with the team, or they may simply be taking advantage of a short term exploitable situation. + +The redeemable tokens being bootstrapped here are designed specifically for fans of the underlying IP to participate in Tokens-as-an-Event (`TaaE`). + +While healthy speculation (free market price discovery) is one of the main goals of the distribution and redemption mechanisms, outright market manipulation for the gain of a few actors with disproportionate control over price is NOT desirable (e.g. pump and dump). + +One of the difficulties of mitigating whales is that there is always grey area in defining what 'a whale' is and what the difference between 'price discovery' and 'manipulation' is, + +Commonly whales also have ready access to 'soft' control over the marketplace like bots, hired technocrats, insider information, etc. in addition to their raw buying power. + +Rather than trying to define rules or whitelisting accounts or taking a 'top down' approach we choose to disincentivise whales at the level of the token and AMM mechanics. + +0. The Dutch Auction style AMM means that whales cannot bulk buy in the first block with a bot to achieve immediate control over the token +1. The Trust contract minting and controlling 100% of the supply (rather than the trust owner) means that nobody can 'premint' tokens for their whale-friends behind closed doors +2. The transaction freezing in the redemption phase means that whales have no ability to trade publically or privately in order to manipulate market prices, only their personal relationship with their own holdings are relevant in this phase + +### Scalpers + +Scalpers are always bad for users who want to use the token for its utility. + +Scalpers have no intent on using (hodling for rewards) the token and simply want to arbitrage 'being first in line' against 'not being first in line' for some scarce resource. + +In a traditional setting (e.g. tickets for a live event) scalpers are also bad for the event producer because they extract value from the event without adding value (i.e. the event producer receives less money than they could have). + +In a setting where the AMM is initialized with 100% of the token supply the event producer theoretically benefits from scalping as they ultimately exit with the total premium of all trades. + +In reality scalping still hurts the creator as well as users because the premium relative to the reserve asset should reach an equilibrium with the expected value of the rewards during the redemption phase. If a scalper manages to put a large premium on the token price paid by users of the utility of the token then the redemption phase will be less valuable - i.e. the creator will need to produce more value to at their own cost match the premium gap that the scalper extracted for themselves. Intuitively, using the live concert example, the event producer may be targeting $100 of value per ticket but scalpers pushing the price up to $200 per ticket will inevitably warp the event-goers expectations of 'good value' despite being fully aware of the scalping premium. + +Scalping is mitigated by starting the price much higher than the creator expects anybody to pay, i.e. the creator is communicating to the audience "I don't intend to produce that much value for _any_ user, so please wait for the weights to settle a bit before aping in." This also removes both the ability to (no early low price) and incentive to (expectation setting) scalp tokens. + +### Rampant speculation + +Speculation is the norm in crypto assets. + +We want to create a _relatively_ safe environment for our users. + +This means the token should never go to zero (bad for hodlers) or to the moon (prices out new participants). + +We don't subscribe to the idea that speculation is zero sum because token sales by the creator ultimately pay the cost of producing the value created by the creator, regardless of whether an individual trader takes a profit or loss. As long as there are users buying the token with the primary goal to achieve newly created value, and the creator delivers on this value creation, then issuance and purchase of the token is a win/win for the creator and token holders. + +So _some_ speculation is healthy and even fun but as all good things, in moderation. + +We effectively clamp the speculation between an upper and lower bound. + +Token holders should be actively educated and encouraged to never buy above the initial spot price, because they can always wait for the weights to rebalance and bring the price down. + +The spot price on the Balancer AMM can never drop below the redemption/book value because this is equivalent to dumping 100% of all tokens minted back to the AMM at the very final block of the weight redistribution, i.e. the lowest price. The redemption value is a fixed minimum because nobody, not even the creator or deployer, can withdraw the reserve token from the redeemable token without calling the `redeem` function. The redemption value can increase over time due to additional reserve deposits but never drop below the floor established at `Trust` initialization (sans gas fees). + +If you subscribe to the idea that crypto assets 'have no intrinsic value' and therefore they are 100% speculative, then having this token drop to the redemption value is the same as it dropping to zero. I.e. when the token reaches the book value, 100% of the speculative premium has been lost. However, by setting a redemption value for the token, we force buyers to match a non-zero non-speculative value on the token that locks up capital before they can consider speculating. +When a buyer purchases a vanilla ERC20 on the open market, 100% of the price they pay is subject to speculation (loss), whereas a redeemable token may be valued as 50% speculative and 50% stable/reserve, which should dampen price swings similar to a traditional diversified portfolio of assets. + +### Front running && MEV + +Balancer does NOT have a general solution for front-running or MEV as far as I am aware. + +The general problem is that someone (bot) can observe the mempool (pending transactions), the state of the blockchain including all available contracts, and execute some combination of transactions before and after (an arsehole sandwich) that profits the bot at the expense of the owner of the pending transaction as it finalises. + +A simple and relevant example is slippage on an AMM. If Alice places a large trade with 10% slippage then Bob can buy ahead of Alice (by being a miner or paying more gas to a miner), forcing Alice to pay an even higher price due to Bob's slippage, then Bob can immediately dump (by being a miner or paying slightly less gas to a miner) and arbitrage Alice's slippage. + +This problem is old, it is called 'front running' because brokers would literally run between desks to place their own trades ahead of the trades of their client's. + +The LBP does have a saving grace in that it passively incentivises relatively small and patient trades through the weight rebalancing. Ignoring gas fees, a simple and safe strategy as a participant in the distribution phase is to Dollar Cost Average (DCA) into the pool to minimise slippage and take advantage of lowering weights without missing the opportunity of high stock of token on sale. +Small trades are less profitable to front run as the slippage and therefore arbitrage opportunity is smaller in both percentage and absolute terms for the bot. + +The Balancer contract _mitigates_ front running and slippage opportunities by exposing parameters that will revert the transaction if a minimum price is exceeded. +If the parameters are set sensibly then any attempt at front-running (or an extra frothy market) will trip the safety on the trade and it will fail. The buyer will still need to pay gas up to the point of the reversion but they will not be forced to accept malicious or extreme slippage. + +**The GUI SHOULD expose or set the price thresholds for each trade to mitigate front-running.** + +### Rug pull + +A rug pull is a common scam where a 'team' (usually anon) mints a token, creates an AMM pool (e.g. TKN/WETH), promotes the token and then after a significant amount of the counter token (e.g. WETH) accumulates they mint a huge amount of the token to clear out the AMM pool. + +Effectively it is a reboot of the old ICO exit scams but facilitated by an AMM. + +The `Trust` contract does not construct or mint any tokens that can be rugged as all token supply changes are behind functions owned/administered by the `Trust` itself. + +### Non-delivery by the creator + +**The creator CAN always fail to deliver meaningful value during the redeem phase**. + +Any user that loses faith in the ability of the creator to deliver can always redeem their tokens during the redemption phase for a pro-rata withdrawal of the current balances of the `RedeemableERC20` contract. + +The intent is that many (hundreds or even thousands) of `Trust` contracts are created over time by many creators. + +This is mitigated by the curation of front ends that present `Trust` contracts to end-users. Obvious scams should be filtered out, leaving as high a ratio of well-intentioned creators as possible. + +Even still, many creators will fail, as this is reality unfortunately. At some point the end-user must apply their own curation metrics before swapping tokens, deciding which creators are worthy of their trust. + +## Flashloan attack + +A flashloan involves a user borrowing a large amount of token X in order to execute a series of methods on arbitrary contracts for personal profit, then returning token X in the same block for zero collateral. + +Flashloans amplify and lower the barrier to exploits that combine various economic incentives across multiple protocols into an aggregate extraction of value at the expense of users of the involved protocols. + +Flashloan risk is generally very difficult to analyse, or even attribute blame to for purposes of insurance, as exploits become increasingly sophisticated and involve valid interactions between many separate protocols. + +It is reasonable to assume that automated flashloan bots will be refined much like arbitrage bots, that constantly scan and simulate contract interactions then automatically execute any profitable trade. + +Flashloans have also been used to manipulate the voting process of 'governance tokens'. + +The usual mitigation strategy is to require at least one block to complete between acquisition of a token and the ability to use it in some functionality. + +It is reasonable to assume that future contracts MAY develop flashloan-like characteristics that can span multiple blocks. + +Our hybrid model is resistant to flashloans in their current form and probably future unknown evolutions of it: + +- Each TaaE token has distinct and fixed distribution and redemption phases so trading can never influence redemption +- Redemption is a one way event and tokens are fixed during redemption, so flash loans are impossible because transfers are impossible +- Redemption tokens have no utility during the distribution phase, there are no rewards, no voting, no contract interactions from creators during distribution that can be manipulated by a loan +- The Balancer pool is preconfigured so that maximum dump of the token is equivalent to the book value of the reserve, the theoretical worst case market action on the LBP is that the seeder has their reserve returned to them and no users participate in the redemption phase +- 100% of the token supply is provided to the LBP at its inception so there are no outside sources of liquidity to manipulate other than user-initiated secondary markets derived from the LBP during the distribution phase + +## Choice of reserve asset + +None of the code in this system has any control over the reserve asset code. + +It is up to the `Trust` deployer and each participating user to conduct their own risk assessment of the reserve asset. + +For example: + +- Stable coins may introduce regulatory risk, e.g. the American STABLE Act or similar may suddenly apply to a reedeemable token +- Centralised stable coins could censor the redemption or pool mechanisms by blocking transfers beyond our control +- The reserve asset could experience its own exit scams and/or exploits +- The reserve asset could somehow be 'wound down' out from underneath users who want to redeem against it + +It essentially comes down to counterparty risk (e.g. tether) + technical risk (e.g. hacks) + value risk (e.g. worthless/volatile reserve). + +Rough analysis of notable assets: + +- WETH: Zero counterparty risk, low technical risk, high value risk +- USDC/DAI: Some counterparty risk, some technical risk, low value risk +- NFT/partner token: Some counterparty risk, some technical risk, very high value risk + +## Contract upgrades && admin keys && hacks && exploits + +TaaE tokens have fixed scope and duration. + +Every phase change, from bootstrap, distribution and redemption is one-way with predictable timing. + +The final state of the system is that hodlers receive rewards and slowly drop out to the underlying asset as a one-way move, or hold a frozen asset indefinitely if they choose to. + +Every new token event requires a new `Trust` with its own lifecycle. + +If a vulnerability is found in a version of the `Trust` the theoretical maximum damage of an exploit is capped at the current locked reserve across the pool and token across vulnerable `Trust` contracts. + +By versioning and newly deploying `Trust` contracts, any fix to a discovered exploit will be available for all new `Trust` contracts after that point. + +There are no admin keys as the `Trust` performs all administrative tasks on the child contracts. diff --git a/docusaurus/versioned_docs/version-v0.0.11/api/claim/TierByConstructionClaim.md b/docusaurus/versioned_docs/version-v0.0.11/api/claim/TierByConstructionClaim.md new file mode 100644 index 000000000..116ad0fa0 --- /dev/null +++ b/docusaurus/versioned_docs/version-v0.0.11/api/claim/TierByConstructionClaim.md @@ -0,0 +1,106 @@ +`TierByConstructionClaim` is a base contract for other contracts to +inherit from. + +It builds on `TierByConstruction` with a `claim` function and `_afterClaim` +hook. + +The `claim` function checks `onlyTier` and exposes `isTier` for +`_afterClaim` hooks so that accounts can self-mint rewards such as erc20, +erc1155, erc721, etc. if they meet the tier requirements. + +The `claim` function can only be called once per account. + +Note that `claim` is an unrestricted function and only the tier of the +_recipient_ is checked. + +Implementing contracts must be careful to avoid griefing attacks where an +attacker calls `claim` against a third party in such a way that their +reward is minimised or damaged in some way. + +For example, `ERC20BalanceTier` used with `TierByConstructionClaim` opens +the ability for an attacker to `claim` every address they know that has not +reached the minimum balance, permanently voiding that address for future +claims even if they reach the minimum balance at a later date. + +Another example, `data_` is set to some empty value by the attacker for the +`claim` call that voids the ability for the recipient to receive more +rewards, had the `data_` been set to some meaningful value. + +The simplest fix is to require `msg.sender` and recipient account are the +same, thus requiring the receiver to ensure for themselves that they claim +only when and how they want. Of course, this also precludes a whole class +of delegated claims processing that may provide a superior user experience. + +Inheriting contracts MUST implement `_afterClaim` with restrictions that +are appropriate to the nature of the claim. + + + +## Details +Contract that can be inherited by anything that wants to manage claims +of erc20/721/1155/etc. based on tier. +The tier must be held continously since the contract construction according +to the tier contract. +In general it is INSECURE to inherit `TierByConstructionClaim` without +implementing `_afterClaim` with appropriate access checks. + +## Variables +### `enum ITier.Tier` `minimumTier` + +### `mapping(address => bool)` `claims` + + +## Events +### `Claim(address account, bytes data)` + +A claim has been successfully processed for an account. + + + + + +## Functions +### `constructor(contract ITier tierContract_, enum ITier.Tier minimumTier_)` (public) + +Nothing special needs to happen in the constructor. +Simply forwards the desired ITier contract to the `TierByConstruction` +constructor. +The minimum tier is set for `claim` logic. + + + +### `claim(address account_, bytes data_)` (external) + +The `onlyTier` modifier checks the claimant against minimumTier. +The ITier contract decides for itself whether the claimant is +`minimumTier` __as at the block this contract was constructed__. +This may be ambiguous for `ReadOnlyTier` contracts that may not have +accurate block times and fallback to `0` when the block is unknown. + +If `account_` gained `minimumTier` after this contract was deployed +but hold it at the time of calling `claim` they are NOT eligible. + +The claim can only be called successfully once per account. + +NOTE: This function is callable by anyone and can only be +called at most once per account. +The `_afterClaim` function can and MUST enforce all appropriate access +restrictions on when/how a claim is valid. + +Be very careful to manage griefing attacks when the `msg.sender` is not +`account_`, for example: +- An `ERC20BalanceTier` has no historical information so +anyone can claim for anyone else based on their balance at any time. +- `data_` may be set arbitrarily by `msg.sender` so could be +consumed frivilously at the expense of `account_`. + + + + + +### `_afterClaim(address account_, uint256 report_, bytes data_)` (internal) + +Implementing contracts need to define what is claimed. + + + diff --git a/docusaurus/versioned_docs/version-v0.0.11/api/cooldown/Cooldown.md b/docusaurus/versioned_docs/version-v0.0.11/api/cooldown/Cooldown.md new file mode 100644 index 000000000..a2b1261da --- /dev/null +++ b/docusaurus/versioned_docs/version-v0.0.11/api/cooldown/Cooldown.md @@ -0,0 +1,65 @@ +`Cooldown` is an abstract contract that rate limits functions on +the contract per `msg.sender`. + +Each time a function with the `onlyAfterCooldown` modifier is called the +`msg.sender` must wait N blocks before calling any modified function. + +This does nothing to prevent sybils who can generate an arbitrary number of +`msg.sender` values in parallel to spam a contract. + +`Cooldown` is intended to prevent rapid state cycling to grief a contract, +such as rapidly locking and unlocking a large amount of capital in the +`SeedERC20` contract. + +Requiring a lock/deposit of significant economic stake that sybils will not +have access to AND applying a cooldown IS a sybil mitigation. The economic +stake alone is NOT sufficient if gas is cheap as sybils can cycle the same +stake between each other. The cooldown alone is NOT sufficient as many +sybils can be created, each as a new `msg.sender`. + + + +## Details +Base for anything that enforces a cooldown delay on functions. +Cooldown requires a minimum time in blocks to elapse between actions that +cooldown. The modifier `onlyAfterCooldown` both enforces and triggers the +cooldown. There is a single cooldown across all functions per-contract +so any function call that requires a cooldown will also trigger it for +all other functions. + +Cooldown is NOT an effective sybil resistance alone, as the cooldown is +per-address only. It is always possible for many accounts to be created +to spam a contract with dust in parallel. +Cooldown is useful to stop a single account rapidly cycling contract +state in a way that can be disruptive to peers. Cooldown works best when +coupled with economic stake associated with each state change so that +peers must lock capital during the cooldown. Cooldown tracks the first +`msg.sender` it sees for a call stack so cooldowns are enforced across +reentrant code. + +## Variables +### `uint16` `cooldownDuration` + +### `mapping(address => uint256)` `cooldowns` + + + +## Modifiers +### `onlyAfterCooldown()` + +Modifies a function to enforce the cooldown for `msg.sender`. +Saves the original caller so that cooldowns are enforced across +reentrant code. + + + + +## Functions +### `constructor(uint16 cooldownDuration_)` (public) + +The cooldown duration is global to the contract. +Cooldown duration must be greater than 0. + + + + diff --git a/docusaurus/versioned_docs/version-v0.0.11/api/factory/Factory.md b/docusaurus/versioned_docs/version-v0.0.11/api/factory/Factory.md new file mode 100644 index 000000000..2f675d52c --- /dev/null +++ b/docusaurus/versioned_docs/version-v0.0.11/api/factory/Factory.md @@ -0,0 +1,46 @@ +Base contract for deploying and registering child contracts. + + + + + +## Functions +### `_createChild(bytes data_) → address` (internal) + +Implements `IFactory`. + +`_createChild` hook must be overridden to actually create child +contract. + +Implementers may want to overload this function with a typed equivalent +to expose domain specific structs etc. to the compiled ABI consumed by +tooling and other scripts. To minimise gas costs for deployment it is +expected that the tooling will consume the typed ABI, then encode the +arguments and pass them to this function directly. + + + + + +### `createChild(bytes data_) → address` (external) + +Implements `IFactory`. + +Calls the _createChild hook, which inheriting contracts must override. +Registers child contract address such that `isChild` is `true`. +Emits `NewContract` event. + + + + + +### `isChild(address maybeChild_) → bool` (external) + +Implements `IFactory`. + +Checks if address is registered as a child contract of this factory. + + + + + diff --git a/docusaurus/versioned_docs/version-v0.0.11/api/factory/IFactory.md b/docusaurus/versioned_docs/version-v0.0.11/api/factory/IFactory.md new file mode 100644 index 000000000..9965bc084 --- /dev/null +++ b/docusaurus/versioned_docs/version-v0.0.11/api/factory/IFactory.md @@ -0,0 +1,35 @@ + + + + +## Events +### `NewContract(address _contract)` + +Whenever a new child contract is deployed, a `NewContract` event +containing the new child contract address MUST be emitted. + + + + + +## Functions +### `createChild(bytes data_) → address` (external) + +Creates a new child contract. + + + + + +### `isChild(address maybeChild_) → bool` (external) + +Checks if address is registered as a child contract of this factory. + +Addresses that were not deployed by `createChild` MUST NOT return +`true` from `isChild`. This is CRITICAL to the security guarantees for +any contract implementing `IFactory`. + + + + + diff --git a/docusaurus/versioned_docs/version-v0.0.11/api/libraries/TierUtil.md b/docusaurus/versioned_docs/version-v0.0.11/api/libraries/TierUtil.md new file mode 100644 index 000000000..f4c7250a1 --- /dev/null +++ b/docusaurus/versioned_docs/version-v0.0.11/api/libraries/TierUtil.md @@ -0,0 +1,88 @@ +`TierUtil` implements several pure functions that can be +used to interface with reports. +- `tierAtBlockFromReport`: Returns the highest status achieved relative to +a block number and report. Statuses gained after that block are ignored. +- `tierBlock`: Returns the block that a given tier has been held +since according to a report. +- `truncateTiersAbove`: Resets all the tiers above the reference tier. +- `updateBlocksForTierRange`: Updates a report with a block +number for every tier in a range. +- `updateReportWithTierAtBlock`: Updates a report to a new tier. + + +## Details +Utilities to consistently read, write and manipulate tiers in reports. +The low-level bit shifting can be difficult to get right so this factors +that out. + +## Variables +### `uint256` `UNINITIALIZED` + + + + +## Functions +### `tierAtBlockFromReport(uint256 report_, uint256 blockNumber_) → enum ITier.Tier` (internal) + +Returns the highest tier achieved relative to a block number +and report. + +Note that typically the report will be from the _current_ contract +state, i.e. `block.number` but not always. Tiers gained after the +reference block are ignored. + +When the `report` comes from a later block than the `blockNumber` this +means the user must have held the tier continuously from `blockNumber` +_through_ to the report block. +I.e. NOT a snapshot. + + + + + +### `tierBlock(uint256 report_, enum ITier.Tier tier_) → uint256` (internal) + +Returns the block that a given tier has been held since from a report. + +The report MUST encode "never" as 0xFFFFFFFF. This ensures +compatibility with `tierAtBlockFromReport`. + + + + + +### `truncateTiersAbove(uint256 report_, enum ITier.Tier tier_) → uint256` (internal) + +Resets all the tiers above the reference tier to 0xFFFFFFFF. + + + + + +### `updateBlocksForTierRange(uint256 report_, enum ITier.Tier startTier_, enum ITier.Tier endTier_, uint256 blockNumber_) → uint256` (internal) + +Updates a report with a block number for every status integer in a +range. + +Does nothing if the end status is equal or less than the start status. + + + + +### `updateReportWithTierAtBlock(uint256 report_, enum ITier.Tier startTier_, enum ITier.Tier endTier_, uint256 blockNumber_) → uint256` (internal) + +Updates a report to a new status. + +Internally dispatches to `truncateTiersAbove` and +`updateBlocksForTierRange`. +The dispatch is based on whether the new tier is above or below the +current tier. +The `startTier_` MUST match the result of `tierAtBlockFromReport`. +It is expected the caller will know the current tier when +calling this function and need to do other things in the calling scope +with it. + + + + + diff --git a/docusaurus/versioned_docs/version-v0.0.11/api/phased/Phased.md b/docusaurus/versioned_docs/version-v0.0.11/api/phased/Phased.md new file mode 100644 index 000000000..845e80fcc --- /dev/null +++ b/docusaurus/versioned_docs/version-v0.0.11/api/phased/Phased.md @@ -0,0 +1,135 @@ +`Phased` is an abstract contract that defines up to `9` phases that +an implementing contract moves through. + +`Phase.ZERO` is always the first phase and does not, and cannot, be set +expicitly. Effectively it is implied that `Phase.ZERO` has been active +since block zero. + +Each subsequent phase `Phase.ONE` through `Phase.EIGHT` must be +scheduled sequentially and explicitly at a block number. + +Only the immediate next phase can be scheduled with `scheduleNextPhase`, +it is not possible to schedule multiple phases ahead. + +Multiple phases can be scheduled in a single block if each scheduled phase +is scheduled for the current block. + +Several utility functions and modifiers are provided. + +A single hook `_beforeScheduleNextPhase` is provided so contracts can +implement additional phase shift checks. + +One event `PhaseShiftScheduled` is emitted each time a phase shift is +scheduled (not when the scheduled phase is reached). + + + +## Details +`Phased` contracts have a defined timeline with available +functionality grouped into phases. +Every `Phased` contract starts at `Phase.ZERO` and moves sequentially +through phases `ONE` to `EIGHT`. +Every `Phase` other than `Phase.ZERO` is optional, there is no requirement +that all 9 phases are implemented. +Phases can never be revisited, the inheriting contract always moves through +each achieved phase linearly. +This is enforced by only allowing `scheduleNextPhase` to be called once per +phase. +It is possible to call `scheduleNextPhase` several times in a single block +but the `block.number` for each phase must be reached each time to schedule +the next phase. +Importantly there are events and several modifiers and checks available to +ensure that functionality is limited to the current phase. +The full history of each phase shift block is recorded as a fixed size +array of `uint32`. + +## Variables +### `uint32` `UNINITIALIZED` + +### `uint32[8]` `phaseBlocks` + + +## Events +### `PhaseShiftScheduled(uint32 newPhaseBlock_)` + +`PhaseShiftScheduled` is emitted when the next phase is scheduled. + + + + +## Modifiers +### `onlyPhase(enum Phase phase_)` + +Modifies functions to only be callable in a specific phase. + + + + +### `onlyAtLeastPhase(enum Phase phase_)` + +Modifies functions to only be callable in a specific phase OR if the +specified phase has passed. + + + + + +## Functions +### `phaseAtBlockNumber(uint32[8] phaseBlocks_, uint32 blockNumber_) → enum Phase` (public) + +Pure function to reduce an array of phase blocks and block number to a +specific `Phase`. +The phase will be the highest attained even if several phases have the +same block number. +If every phase block is after the block number then `Phase.ZERO` is +returned. +If every phase block is before the block number then `Phase.EIGHT` is +returned. + + + + +### `blockNumberForPhase(uint32[8] phaseBlocks_, enum Phase phase_) → uint32` (external) + +Pure function to reduce an array of phase blocks and phase to a +specific block number. +`Phase.ZERO` will always return block `0`. +Every other phase will map to a block number in `phaseBlocks_`. + + + + +### `currentPhase() → enum Phase` (public) + +Impure read-only function to return the "current" phase from internal +contract state. +Simply wraps `phaseAtBlockNumber` for current values of `phaseBlocks` +and `block.number`. + + + +### `scheduleNextPhase(uint32 nextPhaseBlock_)` (internal) + +Writes the block for the next phase. +Only uninitialized blocks can be written to. +Only the immediate next phase relative to `currentPhase` can be written +to. +Emits `PhaseShiftScheduled` with the next phase block. + + + + +### `_beforeScheduleNextPhase(uint32 nextPhaseBlock_)` (internal) + +Hook called before scheduling the next phase. +Useful to apply additional constraints or state changes on a phase +change. +Note this is called when scheduling the phase change, not on the block +the phase change occurs. +This is called before the phase change so that all functionality that +is behind a phase gate is still available at the moment of applying the +hook for scheduling the next phase. + + + + diff --git a/docusaurus/versioned_docs/version-v0.0.11/api/pool/IBalancerConstants.md b/docusaurus/versioned_docs/version-v0.0.11/api/pool/IBalancerConstants.md new file mode 100644 index 000000000..c561d26fa --- /dev/null +++ b/docusaurus/versioned_docs/version-v0.0.11/api/pool/IBalancerConstants.md @@ -0,0 +1,39 @@ + + + +## Variables +### `uint256` `BONE` + +### `uint256` `MIN_WEIGHT` + +### `uint256` `MAX_WEIGHT` + +### `uint256` `MAX_TOTAL_WEIGHT` + +### `uint256` `MIN_BALANCE` + +### `uint256` `MAX_BALANCE` + +### `uint256` `MIN_POOL_SUPPLY` + +### `uint256` `MAX_POOL_SUPPLY` + +### `uint256` `MIN_FEE` + +### `uint256` `MAX_FEE` + +### `uint256` `EXIT_FEE` + +### `uint256` `MAX_IN_RATIO` + +### `uint256` `MAX_OUT_RATIO` + +### `uint256` `MIN_ASSET_LIMIT` + +### `uint256` `MAX_ASSET_LIMIT` + +### `uint256` `MAX_UINT` + + + + diff --git a/docusaurus/versioned_docs/version-v0.0.11/api/pool/ICRPFactory.md b/docusaurus/versioned_docs/version-v0.0.11/api/pool/ICRPFactory.md new file mode 100644 index 000000000..5d72798e4 --- /dev/null +++ b/docusaurus/versioned_docs/version-v0.0.11/api/pool/ICRPFactory.md @@ -0,0 +1,13 @@ +https://github.com/balancer-labs/configurable-rights-pool/blob/5bd63657ac71a9e5f8484ea561de572193b3317b/contracts/CRPFactory.sol#L27 + + + + + +## Functions +### `newCrp(address factoryAddress, struct PoolParams poolParams, struct Rights rights) → address` (external) + + + + + diff --git a/docusaurus/versioned_docs/version-v0.0.11/api/pool/IConfigurableRightsPool.md b/docusaurus/versioned_docs/version-v0.0.11/api/pool/IConfigurableRightsPool.md new file mode 100644 index 000000000..5b86fdff3 --- /dev/null +++ b/docusaurus/versioned_docs/version-v0.0.11/api/pool/IConfigurableRightsPool.md @@ -0,0 +1,37 @@ +https://github.com/balancer-labs/configurable-rights-pool/blob/5bd63657ac71a9e5f8484ea561de572193b3317b/contracts/ConfigurableRightsPool.sol#L41 + + + + + +## Functions +### `bPool() → address` (external) + + + + + +### `bFactory() → address` (external) + + + + + +### `createPool(uint256 initialSupply, uint256 minimumWeightChangeBlockPeriodParam, uint256 addTokenTimeLockInBlocksParam)` (external) + + + + + +### `updateWeightsGradually(uint256[] newWeights, uint256 startBlock, uint256 endBlock)` (external) + + + + + +### `exitPool(uint256 poolAmountIn, uint256[] minAmountsOut)` (external) + + + + + diff --git a/docusaurus/versioned_docs/version-v0.0.11/api/pool/RedeemableERC20Pool.md b/docusaurus/versioned_docs/version-v0.0.11/api/pool/RedeemableERC20Pool.md new file mode 100644 index 000000000..42b25f854 --- /dev/null +++ b/docusaurus/versioned_docs/version-v0.0.11/api/pool/RedeemableERC20Pool.md @@ -0,0 +1,101 @@ +The Balancer functionality is wrapped by the +`RedeemableERC20Pool` contract. + +Balancer pools require significant configuration so this contract helps +decouple the implementation from the `Trust`. + +It also ensures the pool tokens created during the initialization of the +Balancer LBP are owned by the `RedeemableERC20Pool` and never touch either +the `Trust` nor an externally owned account (EOA). + +`RedeemableERC20Pool` has several phases: + +- `Phase.ZERO`: Deployed not trading but can be by owner calling +`ownerStartDutchAuction` +- `Phase.ONE`: Trading open +- `Phase.TWO`: Trading open but can be closed by owner calling +`ownerEndDutchAuction` +- `Phase.THREE`: Trading closed + + + +## Details +Deployer and controller for a Balancer ConfigurableRightsPool. +This contract is intended in turn to be owned by a `Trust`. + +Responsibilities of `RedeemableERC20Pool`: +- Configure and deploy Balancer contracts with correct weights, rights and + balances +- Allowing the owner to start and end a dutch auction raise modelled as + Balancer's "gradual weights" functionality +- Tracking and enforcing 3 phases: unstarted, started, ended +- Burning unsold tokens after the raise and forwarding all raised and + initial reserve back to the owner + +Responsibilities of the owner: +- Providing all token and reserve balances +- Calling start and end raise functions +- Handling the reserve proceeds of the raise + +## Variables +### `uint256` `MIN_BALANCER_POOL_BALANCE` + +### `uint256` `MIN_RESERVE_INIT` + +### `contract RedeemableERC20` `token` + +### `uint256` `minimumTradingDuration` + +### `contract IERC20` `reserve` + +### `uint256` `reserveInit` + +### `contract IConfigurableRightsPool` `crp` + +### `uint256` `finalWeight` + +### `uint256` `finalValuation` + + + + +## Functions +### `constructor(struct RedeemableERC20PoolConfig config_)` (public) + + + + + +### `startDutchAuction()` (external) + +Allow anyone to start the Balancer style dutch auction. +The auction won't start unless this contract owns enough of both the +tokens for the pool, so it is safe for anon to call. +`Phase.ZERO` indicates the auction can start. +`Phase.ONE` indicates the auction has started. +`Phase.TWO` indicates the auction can be ended. +`Phase.THREE` indicates the auction has ended. +Creates the pool via. the CRP contract and configures the weight change +curve. + + + +### `ownerEndDutchAuction()` (external) + +Allow the owner to end the Balancer style dutch auction. +Moves from `Phase.TWO` to `Phase.THREE` to indicate the auction has +ended. +`Phase.TWO` is scheduled by `startDutchAuction`. +Removes all LP tokens from the Balancer pool. +Burns all unsold redeemable tokens. +Forwards the reserve balance to the owner. + + + +### `_beforeScheduleNextPhase(uint32 nextPhaseBlock_)` (internal) + +Enforce `Phase.THREE` as the last phase. + + + + diff --git a/docusaurus/versioned_docs/version-v0.0.11/api/pool/RedeemableERC20PoolFactory.md b/docusaurus/versioned_docs/version-v0.0.11/api/pool/RedeemableERC20PoolFactory.md new file mode 100644 index 000000000..5aeca4f46 --- /dev/null +++ b/docusaurus/versioned_docs/version-v0.0.11/api/pool/RedeemableERC20PoolFactory.md @@ -0,0 +1,47 @@ +Factory for creating and registering new `RedeemableERC20Pool` +contracts. + + +## Variables +### `address` `crpFactory` + +### `address` `balancerFactory` + + + + +## Functions +### `constructor(struct RedeemableERC20PoolFactoryConfig config_)` (public) + + + + + +### `_createChild(bytes data_) → address` (internal) + +Implements `IFactory`. + +`_createChild` hook must be overridden to actually create child +contract. + +Implementers may want to overload this function with a typed equivalent +to expose domain specific structs etc. to the compiled ABI consumed by +tooling and other scripts. To minimise gas costs for deployment it is +expected that the tooling will consume the typed ABI, then encode the +arguments and pass them to this function directly. + + + + + +### `createChild(struct RedeemableERC20PoolFactoryRedeemableERC20PoolConfig config_) → address` (external) + +Allows calling `createChild` with +`RedeemableERC20PoolFactoryRedeemableERC20PoolConfig` struct. +Can use original Factory `createChild` function signature if function +parameters are already encoded. + + + + + diff --git a/docusaurus/versioned_docs/version-v0.0.11/api/redeemableERC20/RedeemableERC20.md b/docusaurus/versioned_docs/version-v0.0.11/api/redeemableERC20/RedeemableERC20.md new file mode 100644 index 000000000..f97a82f67 --- /dev/null +++ b/docusaurus/versioned_docs/version-v0.0.11/api/redeemableERC20/RedeemableERC20.md @@ -0,0 +1,206 @@ +This is the ERC20 token that is minted and distributed. + +During `Phase.ZERO` the token can be traded and so compatible with the +Balancer pool mechanics. + +During `Phase.ONE` the token is frozen and no longer able to be traded on +any AMM or transferred directly. + +The token can be redeemed during `Phase.ONE` which burns the token in +exchange for pro-rata erc20 tokens held by the `RedeemableERC20` contract +itself. + +The token balances can be used indirectly for other claims, promotions and +events as a proof of participation in the original distribution by token +holders. + +The token can optionally be restricted by the `Tier` contract to only allow +receipients with a specified membership status. + + + +## Details +`RedeemableERC20` is an ERC20 with 2 phases. + +`Phase.ZERO` is the distribution phase where the token can be freely +transfered but not redeemed. +`Phase.ONE` is the redemption phase where the token can be redeemed but no +longer transferred. + +Redeeming some amount of `RedeemableERC20` burns the token in exchange for +some other tokens held by the contract. For example, if the +`RedeemableERC20` token contract holds 100 000 USDC then a holder of the +redeemable token can burn some of their tokens to receive a % of that USDC. +If they redeemed (burned) an amount equal to 10% of the redeemable token +supply then they would receive 10 000 USDC. + +Up to 8 redeemable tokens can be registered on the redeemable contract. +These will be looped over by default in the `redeem` function. If there is +an error during redemption or more than 8 tokens are to be redeemed, there +is a `redeemSpecific` function that allows the caller to specify exactly +which of the redeemable tokens they want to receive. +Note: The same amount of `RedeemableERC20` is burned, regardless of which +redeemable tokens were specified. Specifying fewer redeemable tokens will +NOT increase the proportion of each that is returned. `redeemSpecific` is +intended as a last resort if the caller cannot resolve issues causing +errors for one or more redeemable tokens during redemption. + +`RedeemableERC20` has several owner administrative functions: +- Owner can add senders and receivers that can send/receive tokens even + during `Phase.ONE` +- Owner can add to the list of redeemable tokens + - But NOT remove them + - And everyone can call `redeemSpecific` to override the redeemable list +- Owner can end `Phase.ONE` during `Phase.ZERO` by specifying the address + of a distributor, which will have any undistributed tokens burned. + +The intent is that the redeemable token contract is owned by a `Trust` +contract, NOT an externally owned account. The `Trust` contract will add +the minimum possible senders/receivers to facilitate the AMM trading and +redemption. + +The `Trust` will also control access to managing redeemable tokens and +specifying the trading AMM pool as the distributor to burn to end +`Phase.ONE`. + +The redeem functions MUST be used to redeem and burn RedeemableERC20s +(NOT regular transfers). + +The `redeem` and `redeemSpecific` functions will simply revert if called +outside `Phase.ONE`. +A `Redeem` event is emitted on every redemption (per redeemed token) as +`(redeemer, redeemable, redeemAmount)`. + +## Variables +### `bytes32` `SENDER` + +### `bytes32` `RECEIVER` + +### `bytes32` `DISTRIBUTOR_BURNER` + +### `bytes32` `REDEEMABLE_ADDER` + +### `uint256` `MINIMUM_INITIAL_SUPPLY` + +### `uint8` `MAX_REDEEMABLES` + +### `enum ITier.Tier` `minimumTier` + + +## Events +### `Redeem(address redeemer, address redeemable, uint256[2] redeemAmounts)` + +Redeemable token burn amount. + + + + + +## Functions +### `constructor(struct RedeemableERC20Config config_)` (public) + +Mint the full ERC20 token supply and configure basic transfer +restrictions. + + + + +### `burnDistributor(address distributorAccount_)` (external) + +The admin can burn all tokens of a single address to end `Phase.ZERO`. +The intent is that during `Phase.ZERO` there is some contract +responsible for distributing the tokens. +The admin specifies the distributor to end `Phase.ZERO` and all +undistributed tokens are burned. +The distributor is NOT set during the constructor because it likely +doesn't exist at that point. For example, Balancer needs the paired +erc20 tokens to exist before the trading pool can be built. + + + + +### `addRedeemable(contract IERC20 newRedeemable_)` (external) + +Admin can add up to 8 redeemables to this contract. +Each redeemable will be sent to token holders when they call redeem +functions in `Phase.ONE` to burn tokens. +If the admin adds a non-compliant or malicious IERC20 address then +token holders can override the list with `redeemSpecific`. + + + + +### `getRedeemables() → address[8]` (external) + +Public getter for underlying registered redeemables as a fixed sized +array. +The underlying array is dynamic but fixed size return values provide +clear bounds on gas etc. + + + + +### `redeemSpecific(contract IERC20[] specificRedeemables_, uint256 redeemAmount_)` (public) + +Redeem tokens. +Tokens can be redeemed but NOT transferred during `Phase.ONE`. + +Calculate the redeem value of tokens as: + +``` +( redeemAmount / redeemableErc20Token.totalSupply() ) +* token.balanceOf(address(this)) +``` + +This means that the users get their redeemed pro-rata share of the +outstanding token supply burned in return for a pro-rata share of the +current balance of each redeemable token. + +I.e. whatever % of redeemable tokens the sender burns is the % of the +current reserve they receive. + +Note: Any tokens held by `address(0)` are burned defensively. + This is because transferring directly to `address(0)` will + succeed but the `totalSupply` won't reflect it. + + + +### `redeem(uint256 redeemAmount_)` (external) + +Default redemption behaviour. +Thin wrapper for `redeemSpecific`. +`msg.sender` specifies an amount of their own redeemable token to +redeem. +Each redeemable token specified by this contract's admin will be sent +to the sender pro-rata. +The sender's tokens are burned in the process. + + + + +### `_beforeScheduleNextPhase(uint32 nextPhaseBlock_)` (internal) + +Sanity check to ensure `Phase.ONE` is the final phase. + + + + +### `_beforeTokenTransfer(address sender_, address receiver_, uint256 amount_)` (internal) + +Apply phase sensitive transfer restrictions. +During `Phase.ZERO` only tier requirements apply. +During `Phase.ONE` all transfers except burns are prevented. +If a transfer involves either a sender or receiver with the relevant +`unfreezables` state it will ignore these restrictions. + + +Hook that is called before any transfer of tokens. This includes +minting and burning. +Calling conditions: +- when `from` and `to` are both non-zero, `amount` of ``from``'s tokens +will be to transferred to `to`. +- when `from` is zero, `amount` tokens will be minted for `to`. +- when `to` is zero, `amount` of ``from``'s tokens will be burned. +- `from` and `to` are never both zero. +To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + diff --git a/docusaurus/versioned_docs/version-v0.0.11/api/redeemableERC20/RedeemableERC20Factory.md b/docusaurus/versioned_docs/version-v0.0.11/api/redeemableERC20/RedeemableERC20Factory.md new file mode 100644 index 000000000..2ab01b38e --- /dev/null +++ b/docusaurus/versioned_docs/version-v0.0.11/api/redeemableERC20/RedeemableERC20Factory.md @@ -0,0 +1,34 @@ +Factory for deploying and registering `RedeemableERC20` contracts. + + + + + +## Functions +### `_createChild(bytes data_) → address` (internal) + +Implements `IFactory`. + +`_createChild` hook must be overridden to actually create child +contract. + +Implementers may want to overload this function with a typed equivalent +to expose domain specific structs etc. to the compiled ABI consumed by +tooling and other scripts. To minimise gas costs for deployment it is +expected that the tooling will consume the typed ABI, then encode the +arguments and pass them to this function directly. + + + + + +### `createChild(struct RedeemableERC20Config config_) → address` (external) + +Allows calling `createChild` with `RedeemableERC20Config` struct. +Use original `Factory` `createChild` function signature if function +parameters are already encoded. + + + + + diff --git a/docusaurus/versioned_docs/version-v0.0.11/api/seed/SeedERC20.md b/docusaurus/versioned_docs/version-v0.0.11/api/seed/SeedERC20.md new file mode 100644 index 000000000..e3d5bdb29 --- /dev/null +++ b/docusaurus/versioned_docs/version-v0.0.11/api/seed/SeedERC20.md @@ -0,0 +1,145 @@ +Facilitates raising seed reserve from an open set of seeders. + +When a single seeder address cannot be specified at the time the +`Trust` is constructed a `SeedERC20` will be deployed. + +The `SeedERC20` has two phases: + +- `Phase.ZERO`: Can swap seed tokens for reserve assets with +`seed` and `unseed` +- `Phase.ONE`: Can redeem seed tokens pro-rata for reserve assets + +When the last seed token is distributed the `SeedERC20` +immediately moves to `Phase.ONE` atomically within that +transaction and forwards all reserve to the configured recipient. + +For our use-case the recipient is a `Trust` contract but `SeedERC20` +could be used as a mini-fundraise contract for many purposes. In the case +that a recipient is not a `Trust` the recipient will need to be careful not +to fall afoul of KYC and securities law. + + + +## Details +Facilitates a pool of reserve funds to forward to a named recipient +contract. +The funds to raise and the recipient is fixed at construction. +The total is calculated as `( seedPrice * seedUnits )` and so is a fixed +amount. It is recommended to keep seedUnits relatively small so that each +unit represents a meaningful contribution to keep dust out of the system. + +The contract lifecycle is split into two phases: + +- `Phase.ZERO`: the `seed` and `unseed` functions are callable by anyone. +- `Phase.ONE`: holders of the seed erc20 token can redeem any reserve funds + in the contract pro-rata. + +When `seed` is called the `SeedERC20` contract takes ownership of reserve +funds in exchange for seed tokens. +When `unseed` is called the `SeedERC20` contract takes ownership of seed +tokens in exchange for reserve funds. + +When the last `seed` token is transferred to an external address the +`SeedERC20` contract immediately: + +- Moves to `Phase.ONE`, disabling both `seed` and `unseed` +- Transfers the full balance of reserve from itself to the recipient + address. + +Seed tokens are standard ERC20 so can be freely transferred etc. + +The recipient (or anyone else) MAY transfer reserve back to the `SeedERC20` +at a later date. +Seed token holders can call `redeem` in `Phase.ONE` to burn their tokens in +exchange for pro-rata reserve assets. + +## Variables +### `contract IERC20` `reserve` + +### `address` `recipient` + +### `uint256` `seedPrice` + + + + +## Functions +### `constructor(struct SeedERC20Config config_)` (public) + +Sanity checks on configuration. +Store relevant config as contract state. +Mint all seed tokens. + + + + +### `seed(uint256 minimumUnits_, uint256 desiredUnits_)` (external) + +Take reserve from seeder as `units * seedPrice`. + +When the final unit is sold the contract immediately: + +- enters `Phase.ONE` +- transfers its entire reserve balance to the recipient + +The desired units may not be available by the time this transaction +executes. This could be due to high demand, griefing and/or +front-running on the contract. +The caller can set a range between `minimumUnits_` and `desiredUnits_` +to mitigate errors due to the contract running out of stock. +The maximum available units up to `desiredUnits_` will always be +processed by the contract. Only the stock of this contract is checked +against the seed unit range, the caller is responsible for ensuring +their reserve balance. +Seeding enforces the cooldown configured in the constructor. + + + + +### `unseed(uint256 units_)` (external) + +Send reserve back to seeder as `( units * seedPrice )`. + +Allows addresses to back out until `Phase.ONE`. +Unlike `redeem` the seed tokens are NOT burned so become newly +available for another account to `seed`. + +In `Phase.ONE` the only way to recover reserve assets is: +- Wait for the recipient or someone else to deposit reserve assets into + this contract. +- Call redeem and burn the seed tokens + + + + + +### `redeem(uint256 units_)` (external) + +Burn seed tokens for pro-rata reserve assets. + +``` +(units * reserve held by seed contract) / total seed token supply += reserve transfer to `msg.sender` +``` + +The recipient or someone else must first transfer reserve assets to the +`SeedERC20` contract. +The recipient MUST be a TRUSTED contract or third party. +This contract has no control over the reserve assets once they are +transferred away at the start of `Phase.ONE`. +It is the caller's responsibility to monitor the reserve balance of the +`SeedERC20` contract. + +For example, if `SeedERC20` is used as a seeder for a `Trust` contract +(in this repo) it will receive a refund or refund + fee. + + + + +### `_beforeScheduleNextPhase(uint32 nextPhaseBlock_)` (internal) + +Sanity check the last phase is `Phase.ONE`. + + + + diff --git a/docusaurus/versioned_docs/version-v0.0.11/api/seed/SeedERC20Factory.md b/docusaurus/versioned_docs/version-v0.0.11/api/seed/SeedERC20Factory.md new file mode 100644 index 000000000..6bf8623a2 --- /dev/null +++ b/docusaurus/versioned_docs/version-v0.0.11/api/seed/SeedERC20Factory.md @@ -0,0 +1,34 @@ +Factory for creating and deploying `SeedERC20` contracts. + + + + + +## Functions +### `_createChild(bytes data_) → address` (internal) + +Implements `IFactory`. + +`_createChild` hook must be overridden to actually create child +contract. + +Implementers may want to overload this function with a typed equivalent +to expose domain specific structs etc. to the compiled ABI consumed by +tooling and other scripts. To minimise gas costs for deployment it is +expected that the tooling will consume the typed ABI, then encode the +arguments and pass them to this function directly. + + + + + +### `createChild(struct SeedERC20Config config_) → address` (external) + +Allows calling `createChild` with `SeedERC20Config` struct. +Use original `Factory` `createChild` function signature if function +parameters are already encoded. + + + + + diff --git a/docusaurus/versioned_docs/version-v0.0.11/api/tier/AlwaysTier.md b/docusaurus/versioned_docs/version-v0.0.11/api/tier/AlwaysTier.md new file mode 100644 index 000000000..6a06213e6 --- /dev/null +++ b/docusaurus/versioned_docs/version-v0.0.11/api/tier/AlwaysTier.md @@ -0,0 +1,33 @@ +`AlwaysTier` inherits from `ReadOnlyTier`. + +Always returns every tier, i.e. `0x00000000` for every address and tier. + + + +## Details +`AlwaysTier` is intended as a primitive for combining tier contracts. + +As the name implies: +- `AlwaysTier` is `ReadOnlyTier` and so can never call `setTier`. +- `report` is always `0x00000000` for every tier and every address. + + + + +## Functions +### `report(address) → uint256` (public) + +Every address is always every tier. + + +Returns the earliest block the account has held each tier for +continuously. +This is encoded as a uint256 with blocks represented as 8x +concatenated uint32. +I.e. Each 4 bytes of the uint256 represents a u32 tier start time. +The low bits represent low tiers and high bits the high tiers. +Implementing contracts should return 0xFFFFFFFF for lost & +never-held tiers. + + + diff --git a/docusaurus/versioned_docs/version-v0.0.11/api/tier/ERC20BalanceTier.md b/docusaurus/versioned_docs/version-v0.0.11/api/tier/ERC20BalanceTier.md new file mode 100644 index 000000000..9334c2f7a --- /dev/null +++ b/docusaurus/versioned_docs/version-v0.0.11/api/tier/ERC20BalanceTier.md @@ -0,0 +1,58 @@ +`ERC20BalanceTier` inherits from `ReadOnlyTier`. + +There is no internal accounting, the balance tier simply reads the balance +of the user whenever `report` is called. + +`setTier` always fails. + +There is no historical information so each tier will either be `0x00000000` +or `0xFFFFFFFF` for the block number. + + + +## Details +The `ERC20BalanceTier` simply checks the current balance of an erc20 +against tier values. As the current balance is always read from the erc20 +contract directly there is no historical block data. +All tiers held at the current value will be 0x00000000 and tiers not held +will be 0xFFFFFFFF. +`setTier` will error as this contract has no ability to write to the erc20 +contract state. + +Balance tiers are useful for: +- Claim contracts that don't require backdated tier holding + (be wary of griefing!). +- Assets that cannot be transferred, so are not eligible for + `ERC20TransferTier`. +- Lightweight, realtime checks that encumber the tiered address + as little as possible. + +## Variables +### `contract IERC20` `erc20` + + + + +## Functions +### `constructor(contract IERC20 erc20_, uint256[8] tierValues_)` (public) + + + + + +### `report(address account_) → uint256` (public) + +Report simply truncates all tiers above the highest value held. + + +Returns the earliest block the account has held each tier for +continuously. +This is encoded as a uint256 with blocks represented as 8x +concatenated uint32. +I.e. Each 4 bytes of the uint256 represents a u32 tier start time. +The low bits represent low tiers and high bits the high tiers. +Implementing contracts should return 0xFFFFFFFF for lost & +never-held tiers. + + + diff --git a/docusaurus/versioned_docs/version-v0.0.11/api/tier/ERC20TransferTier.md b/docusaurus/versioned_docs/version-v0.0.11/api/tier/ERC20TransferTier.md new file mode 100644 index 000000000..b336cbd18 --- /dev/null +++ b/docusaurus/versioned_docs/version-v0.0.11/api/tier/ERC20TransferTier.md @@ -0,0 +1,69 @@ +`ERC20TransferTier` inherits from `ReadWriteTier`. + +In addition to the standard accounting it requires that users transfer +erc20 tokens to achieve a tier. + +Data is ignored, the only requirement is that the user has approved +sufficient balance to gain the next tier. + +To avoid griefing attacks where accounts remove tiers from arbitrary third +parties, we `require(msg.sender == account_);` when a tier is removed. +When a tier is added the `msg.sender` is responsible for payment. + +The 8 values for gainable tiers and erc20 contract must be set upon +construction and are immutable. + +The `_afterSetTier` simply transfers the diff between the start/end tier +to/from the user as required. + +If a user sends erc20 tokens directly to the contract without calling +`setTier` the FUNDS ARE LOST. + + + +## Details +The `ERC20TransferTier` takes ownership of an erc20 balance by +transferring erc20 token to itself. The `msg.sender` must pay the +difference on upgrade; the tiered address receives refunds on downgrade. +This allows users to "gift" tiers to each other. +As the transfer is a state changing event we can track historical block +times. +As the tiered address moves up/down tiers it sends/receives the value +difference between its current tier only. + +The user is required to preapprove enough erc20 to cover the tier change or +they will fail and lose gas. + +`ERC20TransferTier` is useful for: +- Claims that rely on historical holdings so the tiered address + cannot simply "flash claim" +- Token demand and lockup where liquidity (trading) is a secondary goal +- erc20 tokens without additonal restrictions on transfer + +## Variables +### `contract IERC20` `erc20` + + + + +## Functions +### `constructor(contract IERC20 erc20_, uint256[8] tierValues_)` (public) + + + + + +### `_afterSetTier(address account_, enum ITier.Tier startTier_, enum ITier.Tier endTier_, bytes)` (internal) + +Transfers balances of erc20 from/to the tiered account according to the +difference in values. Any failure to transfer in/out will rollback the +tier change. The tiered account must ensure sufficient approvals before +attempting to set a new tier. +The `msg.sender` is responsible for paying the token cost of a tier +increase. +The tiered account is always the recipient of a refund on a tier +decrease. + + + + diff --git a/docusaurus/versioned_docs/version-v0.0.11/api/tier/ITier.md b/docusaurus/versioned_docs/version-v0.0.11/api/tier/ITier.md new file mode 100644 index 000000000..89ac0b940 --- /dev/null +++ b/docusaurus/versioned_docs/version-v0.0.11/api/tier/ITier.md @@ -0,0 +1,168 @@ +`ITier` is a simple interface that contracts can +implement to provide membership lists for other contracts. + +There are many use-cases for a time-preserving, +conditional membership list. + +Some examples include: + +- Self-serve whitelist to participate in fundraising +- Lists of users who can claim airdrops and perks +- Pooling resources with implied governance/reward tiers +- POAP style attendance proofs allowing access to future exclusive events + + + +## Details +Standard interface to a tiered membership. + +A "membership" can represent many things: +- Exclusive access. +- Participation in some event or process. +- KYC completion. +- Combination of sub-memberships. +- Etc. + +The high level requirements for a contract implementing `ITier`: +- MUST represent held tiers with the `Tier` enum. +- MUST implement `report`. + - The report is a `uint256` that SHOULD represent the block each tier has + been continuously held since encoded as `uint32`. + - The encoded tiers start at ONE; ZERO is implied if no tier has ever + been held. + - `Tier.ZERO` is NOT encoded in the report, it is simply the fallback + value. + - If a tier is lost the block data is erased for that tier and will be + set if/when the tier is regained to the new block. + - If the historical block information is not available the report MAY + return `0x00000000` for all held tiers. + - Tiers that are lost or have never been held MUST return `0xFFFFFFFF`. +- SHOULD implement `setTier`. + - Contracts SHOULD revert with `SET_TIER` error if they cannot + meaningfully set a tier directly. + For example a contract that can only derive a membership tier by + reading the state of an external contract cannot set tiers. + - Contracts implementing `setTier` SHOULD error with `SET_ZERO_TIER` + if `Tier.ZERO` is being set. +- MUST emit `TierChange` when `setTier` successfully writes a new tier. + - Contracts that cannot meaningfully set a tier are exempt. + + +## Events +### `TierChange(address account, enum ITier.Tier startTier, enum ITier.Tier endTier)` + +Every time a Tier changes we log start and end Tier against the +account. +This MAY NOT be emitted if reports are being read from the state of an +external contract. + + + + + +## Functions +### `setTier(address account, enum ITier.Tier endTier, bytes data)` (external) + +Users can set their own tier by calling `setTier`. + +The contract that implements `ITier` is responsible for checking +eligibility and/or taking actions required to set the tier. + +For example, the contract must take/refund any tokens relevant to +changing the tier. + +Obviously the user is responsible for any approvals for this action +prior to calling `setTier`. + +When the tier is changed a `TierChange` event will be emmited as: +``` +event TierChange(address account, Tier startTier, Tier endTier); +``` + +The `setTier` function includes arbitrary data as the third +parameter. This can be used to disambiguate in the case that +there may be many possible options for a user to achieve some tier. + +For example, consider the case where `Tier.THREE` can be achieved +by EITHER locking 1x rare NFT or 3x uncommon NFTs. A user with both +could use `data` to explicitly state their intent. + +NOTE however that _any_ address can call `setTier` for any other +address. + +If you implement `data` or anything that changes state then be very +careful to avoid griefing attacks. + +The `data` parameter can also be ignored by the contract implementing +`ITier`. For example, ERC20 tokens are fungible so only the balance +approved by the user is relevant to a tier change. + +The `setTier` function SHOULD prevent users from reassigning +`Tier.ZERO` to themselves. + +The `Tier.ZERO` status represents never having any status. + + +Updates the tier of an account. + +The implementing contract is responsible for all checks and state +changes required to set the tier. For example, taking/refunding +funds/NFTs etc. + +Contracts may disallow directly setting tiers, preferring to derive +reports from other onchain data. +In this case they should `revert("SET_TIER");`. + + + +### `report(address account) → uint256` (external) + +A tier report is a `uint256` that contains each of the block +numbers each tier has been held continously since as a `uint32`. +There are 9 possible tier, starting with `Tier.ZERO` for `0` offset or +"never held any tier" then working up through 8x 4 byte offsets to the +full 256 bits. + +Low bits = Lower tier. + +In hexadecimal every 8 characters = one tier, starting at `Tier.EIGHT` +from high bits and working down to `Tier.ONE`. + +`uint32` should be plenty for any blockchain that measures block times +in seconds, but reconsider if deploying to an environment with +significantly sub-second block times. + +~135 years of 1 second blocks fit into `uint32`. + +`2^8 / (365 * 24 * 60 * 60)` + +When a user INCREASES their tier they keep all the block numbers they +already had, and get new block times for each increased tiers they have +earned. + +When a user DECREASES their tier they return to `0xFFFFFFFF` (never) +for every tier level they remove, but keep their block numbers for the +remaining tiers. + +GUIs are encouraged to make this dynamic very clear for users as +round-tripping to a lower status and back is a DESTRUCTIVE operation +for block times. + +The intent is that downstream code can provide additional benefits for +members who have maintained a certain tier for/since a long time. +These benefits can be provided by inspecting the report, and by +on-chain contracts directly, +rather than needing to work with snapshots etc. + + +Returns the earliest block the account has held each tier for +continuously. +This is encoded as a uint256 with blocks represented as 8x +concatenated uint32. +I.e. Each 4 bytes of the uint256 represents a u32 tier start time. +The low bits represent low tiers and high bits the high tiers. +Implementing contracts should return 0xFFFFFFFF for lost & +never-held tiers. + + + diff --git a/docusaurus/versioned_docs/version-v0.0.11/api/tier/NeverTier.md b/docusaurus/versioned_docs/version-v0.0.11/api/tier/NeverTier.md new file mode 100644 index 000000000..b75fe5c9e --- /dev/null +++ b/docusaurus/versioned_docs/version-v0.0.11/api/tier/NeverTier.md @@ -0,0 +1,33 @@ +`NeverTier` inherits from `ReadOnlyTier`. + +Never returns any tier, i.e. `0xFFFFFFFF` for every address and tier. + + + +## Details +`NeverTier` is intended as a primitive for combining tier contracts. + +As the name implies: +- `NeverTier` is `ReadOnlyTier` and so can never call `setTier`. +- `report` is always `uint256(-1)` as every tier is unobtainable. + + + + +## Functions +### `report(address) → uint256` (public) + +Every tier in the report is unobtainable. + + +Returns the earliest block the account has held each tier for +continuously. +This is encoded as a uint256 with blocks represented as 8x +concatenated uint32. +I.e. Each 4 bytes of the uint256 represents a u32 tier start time. +The low bits represent low tiers and high bits the high tiers. +Implementing contracts should return 0xFFFFFFFF for lost & +never-held tiers. + + + diff --git a/docusaurus/versioned_docs/version-v0.0.11/api/tier/ReadOnlyTier.md b/docusaurus/versioned_docs/version-v0.0.11/api/tier/ReadOnlyTier.md new file mode 100644 index 000000000..f446c2e9b --- /dev/null +++ b/docusaurus/versioned_docs/version-v0.0.11/api/tier/ReadOnlyTier.md @@ -0,0 +1,36 @@ +`ReadOnlyTier` is a base contract that other contracts +are expected to inherit. + +It does not allow `setStatus` and expects `report` to derive from +some existing onchain data. + + + +## Details +A contract inheriting `ReadOnlyTier` cannot call `setTier`. + +`ReadOnlyTier` is abstract because it does not implement `report`. +The expectation is that `report` will derive tiers from some +external data source. + + + + +## Functions +### `setTier(address, enum ITier.Tier, bytes)` (external) + +Always reverts because it is not possible to set a read only tier. + + +Updates the tier of an account. + +The implementing contract is responsible for all checks and state +changes required to set the tier. For example, taking/refunding +funds/NFTs etc. + +Contracts may disallow directly setting tiers, preferring to derive +reports from other onchain data. +In this case they should `revert("SET_TIER");`. + + + diff --git a/docusaurus/versioned_docs/version-v0.0.11/api/tier/ReadWriteTier.md b/docusaurus/versioned_docs/version-v0.0.11/api/tier/ReadWriteTier.md new file mode 100644 index 000000000..6a0312ed7 --- /dev/null +++ b/docusaurus/versioned_docs/version-v0.0.11/api/tier/ReadWriteTier.md @@ -0,0 +1,73 @@ +`ReadWriteTier` is a base contract that other contracts are +expected to inherit. + +It handles all the internal accounting and state changes for `report` +and `setTier`. + +It calls an `_afterSetTier` hook that inheriting contracts can override to +enforce tier requirements. + + + +## Details +ReadWriteTier can `setTier` in addition to generating reports. +When `setTier` is called it automatically sets the current blocks in the +report for the new tiers. Lost tiers are scrubbed from the report as tiered +addresses move down the tiers. + +## Variables +### `mapping(address => uint256)` `reports` + + + + +## Functions +### `report(address account_) → uint256` (public) + +Either fetch the report from storage or return UNINITIALIZED. + + +Returns the earliest block the account has held each tier for +continuously. +This is encoded as a uint256 with blocks represented as 8x +concatenated uint32. +I.e. Each 4 bytes of the uint256 represents a u32 tier start time. +The low bits represent low tiers and high bits the high tiers. +Implementing contracts should return 0xFFFFFFFF for lost & +never-held tiers. + + + +### `setTier(address account_, enum ITier.Tier endTier_, bytes data_)` (external) + +Errors if the user attempts to return to the `Tier.ZERO` tier. +Updates the report from `report` using default `TierUtil` logic. +Calls `_afterSetTier` that inheriting contracts SHOULD override to +enforce status requirements. +Emits `TierChange` event. + + +Updates the tier of an account. + +The implementing contract is responsible for all checks and state +changes required to set the tier. For example, taking/refunding +funds/NFTs etc. + +Contracts may disallow directly setting tiers, preferring to derive +reports from other onchain data. +In this case they should `revert("SET_TIER");`. + + + +### `_afterSetTier(address account_, enum ITier.Tier startTier_, enum ITier.Tier endTier_, bytes data_)` (internal) + +Inheriting contracts SHOULD override this to enforce requirements. + +All the internal accounting and state changes are complete at +this point. +Use `require` to enforce additional requirements for tier changes. + + + + + diff --git a/docusaurus/versioned_docs/version-v0.0.11/api/tier/TierByConstruction.md b/docusaurus/versioned_docs/version-v0.0.11/api/tier/TierByConstruction.md new file mode 100644 index 000000000..d742b0aa1 --- /dev/null +++ b/docusaurus/versioned_docs/version-v0.0.11/api/tier/TierByConstruction.md @@ -0,0 +1,80 @@ +`TierByConstruction` is a base contract for other +contracts to inherit from. + +It exposes `isTier` and the corresponding modifier `onlyTier`. + +This ensures that the address has held at least the given tier +since the contract was constructed. + +We check against the construction time of the contract rather +than the current block to avoid various exploits. + +Users should not be able to gain a tier for a single block, claim +benefits then remove the tier within the same block. + +The construction block provides a simple and generic reference +point that is difficult to manipulate/predict. + +Note that `ReadOnlyTier` contracts must carefully consider use +with `TierByConstruction` as they tend to return `0x00000000` for +any/all tiers held. There needs to be additional safeguards to +mitigate "flash tier" attacks. + +Note that an account COULD be `TierByConstruction` then lower/ +remove a tier, then no longer be eligible when they regain the +tier. Only _continuously held_ tiers are valid against the +construction block check as this is native behaviour of the +`report` function in `ITier`. + +Technically the `ITier` could re-enter the `TierByConstruction` +so the `onlyTier` modifier runs AFTER the modified function. + + + +## Details +Enforces tiers held by contract contruction block. +The construction block is compared against the blocks returned by `report`. +The `ITier` contract is paramaterised and set during construction. + +## Variables +### `contract ITier` `tierContract` + +### `uint256` `constructionBlock` + + + +## Modifiers +### `onlyTier(address account_, enum ITier.Tier minimumTier_)` + +https://consensys.github.io/smart-contract-best-practices/recommendations/#use-modifiers-only-for-checks + +Do NOT use this to guard setting the tier on an `ITier` contract. +The initial tier would be checked AFTER it has already been +modified which is unsafe. + + + + + + +## Functions +### `constructor(contract ITier tierContract_)` (public) + + + + + +### `isTier(address account_, enum ITier.Tier minimumTier_) → bool` (public) + +Check if an account has held AT LEAST the given tier according to +`tierContract` since construction. +The account MUST have held the tier continuously from construction +until the "current" state according to `report`. +Note that `report` PROBABLY is current as at the block this function is +called but MAYBE NOT. +The `ITier` contract is free to manage reports however makes sense. + + + + + diff --git a/docusaurus/versioned_docs/version-v0.0.11/api/tier/ValueTier.md b/docusaurus/versioned_docs/version-v0.0.11/api/tier/ValueTier.md new file mode 100644 index 000000000..174c4bc85 --- /dev/null +++ b/docusaurus/versioned_docs/version-v0.0.11/api/tier/ValueTier.md @@ -0,0 +1,44 @@ + + +## Details +A contract that is `ValueTier` expects to derive tiers from explicit +values. For example an address must send or hold an amount of something to +reach a given tier. +Anything with predefined values that map to tiers can be a `ValueTier`. + +Note that `ValueTier` does NOT implement `ITier`. +`ValueTier` does include state however, to track the `tierValues` so is not +a library. + + + + +## Functions +### `constructor(uint256[8] tierValues_)` (public) + +Set the `tierValues` on construction to be referenced immutably. + + + +### `tierValues() → uint256[8] tierValues_` (public) + +Complements the default solidity accessor for `tierValues`. +Returns all the values in a list rather than requiring an index be +specified. + + + + +### `tierToValue(enum ITier.Tier tier_) → uint256` (internal) + +Converts a Tier to the minimum value it requires. +`Tier.ZERO` is always value 0 as it is the fallback. + + + +### `valueToTier(uint256 value_) → enum ITier.Tier` (internal) + +Converts a value to the maximum Tier it qualifies for. + + + diff --git a/docusaurus/versioned_docs/version-v0.0.11/api/tier/VerifyTier.md b/docusaurus/versioned_docs/version-v0.0.11/api/tier/VerifyTier.md new file mode 100644 index 000000000..7cd7dde48 --- /dev/null +++ b/docusaurus/versioned_docs/version-v0.0.11/api/tier/VerifyTier.md @@ -0,0 +1,37 @@ + + +## Details +A contract that is `VerifyTier` expects to derive tiers from the time +the account was approved by the underlying `Verify` contract. The approval +block numbers defer to `State.since` returned from `Verify.state`. + +## Variables +### `contract Verify` `verify` + + + + +## Functions +### `constructor(contract Verify verify_)` (public) + +Sets the `verify` contract immutably. + + + +### `report(address account_) → uint256` (public) + +Every tier will be the `State.since` block if `account_` is approved +otherwise every tier will be uninitialized. + + +Returns the earliest block the account has held each tier for +continuously. +This is encoded as a uint256 with blocks represented as 8x +concatenated uint32. +I.e. Each 4 bytes of the uint256 represents a u32 tier start time. +The low bits represent low tiers and high bits the high tiers. +Implementing contracts should return 0xFFFFFFFF for lost & +never-held tiers. + + + diff --git a/docusaurus/versioned_docs/version-v0.0.11/api/trust/Trust.md b/docusaurus/versioned_docs/version-v0.0.11/api/trust/Trust.md new file mode 100644 index 000000000..4e2b7068d --- /dev/null +++ b/docusaurus/versioned_docs/version-v0.0.11/api/trust/Trust.md @@ -0,0 +1,183 @@ +Coordinates the mediation and distribution of tokens +between stakeholders. + +The `Trust` contract is responsible for configuring the +`RedeemableERC20` token, `RedeemableERC20Pool` Balancer wrapper +and the `SeedERC20` contract. + +Internally the `TrustFactory` calls several admin/owner only +functions on its children and these may impose additional +restrictions such as `Phased` limits. + +The `Trust` builds and references `RedeemableERC20`, +`RedeemableERC20Pool` and `SeedERC20` contracts internally and +manages all access-control functionality. + +The major functions of the `Trust` contract, apart from building +and configuring the other contracts, is to start and end the +fundraising event, and mediate the distribution of funds to the +correct stakeholders: + +- On `Trust` construction, all minted `RedeemableERC20` tokens + are sent to the `RedeemableERC20Pool` +- `anonStartDistribution` can be called by anyone to begin the + Dutch Auction. This will revert if this is called before seeder reserve + funds are available on the `Trust`. +- `anonEndDistribution` can be called by anyone (only when + `RedeemableERC20Pool` is in `Phase.TWO`) to end the Dutch Auction + and distribute funds to the correct stakeholders, depending on + whether or not the auction met the fundraising target. + - On successful raise + - seed funds are returned to `seeder` address along with + additional `seederFee` if configured + - `redeemInit` is sent to the `redeemableERC20` address, to back + redemptions + - the `creator` gets the remaining balance, which should + equal or exceed `minimumCreatorRaise` + - On failed raise + - seed funds are returned to `seeder` address + - the remaining balance is sent to the `redeemableERC20` address, to + back redemptions + - the `creator` gets nothing + + +## Details +Mediates stakeholders and creates internal Balancer pools and tokens +for a distribution. + +The goals of a distribution: +- Mint and distribute a `RedeemableERC20` as fairly as possible, + prioritising true fans of a creator. +- Raise a minimum reserve so that a creator can deliver value to fans. +- Provide a safe space through membership style filters to enhance + exclusivity for fans. +- Ensure that anyone who seeds the raise (not fans) by risking and + providing capital is compensated. + +Stakeholders: +- Creator: Have a project of interest to their fans +- Fans: Will purchase project-specific tokens to receive future rewards + from the creator +- Seeder(s): Provide initial reserve assets to seed a Balancer trading pool +- Deployer: Configures and deploys the `Trust` contract + +The creator is nominated to receive reserve assets on a successful +distribution. The creator must complete the project and fans receive +rewards. There is no on-chain mechanism to hold the creator accountable to +the project completion. Requires a high degree of trust between creator and +their fans. + +Fans are willing to trust and provide funds to a creator to complete a +project. Fans likely expect some kind of reward or "perks" from the +creator, such as NFTs, exclusive events, etc. +The distributed tokens are untransferable after trading ends and merely act +as records for who should receive rewards. + +Seeders add the initial reserve asset to the Balancer pool to start the +automated market maker (AMM). +Ideally this would not be needed at all. +Future versions of `Trust` may include a bespoke distribution mechanism +rather than Balancer contracts. Currently it is required by Balancer so the +seeder provides some reserve and receives a fee on successful distribution. +If the distribution fails the seeder is returned their initial reserve +assets. The seeder is expected to promote and mentor the creator in +non-financial ways. + +The deployer has no specific priviledge or admin access once the `Trust` is +deployed. They provide the configuration, including nominating +creator/seeder, and pay gas but that is all. +The deployer defines the conditions under which the distribution is +successful. The seeder/creator could also act as the deployer. + +Importantly the `Trust` contract is the owner/admin of the contracts it +creates. The `Trust` never transfers ownership so it directly controls all +internal workflows. No stakeholder, even the deployer or creator, can act +as owner of the internals. + +## Variables +### `address` `creator` + +### `uint256` `minimumCreatorRaise` + +### `address` `seeder` + +### `uint256` `seederFee` + +### `uint16` `seederUnits` + +### `uint16` `seederCooldownDuration` + +### `uint256` `redeemInit` + +### `contract SeedERC20Factory` `seedERC20Factory` + +### `uint256` `finalBalance` + +### `uint256` `successBalance` + +### `contract RedeemableERC20` `token` + +### `contract RedeemableERC20Pool` `pool` + + + + +## Functions +### `constructor(struct TrustConfig config_, struct TrustRedeemableERC20Config trustRedeemableERC20Config_, struct TrustRedeemableERC20PoolConfig trustRedeemableERC20PoolConfig_)` (public) + +Sanity checks configuration. +Creates the `RedeemableERC20` contract and mints the redeemable ERC20 +token. +Creates the `RedeemableERC20Pool` contract. +(optional) Creates the `SeedERC20` contract. Pass a non-zero address to +bypass this. +Adds the Balancer pool contracts to the token sender/receiver lists as +needed. +Adds the Balancer pool reserve asset as the first redeemable on the +`RedeemableERC20` contract. + +Note on slither: +Slither detects a benign reentrancy in this constructor. +However reentrancy is not possible in a contract constructor. +Further discussion with the slither team: +https://github.com/crytic/slither/issues/887 + + + + + +### `getContracts() → struct TrustContracts` (external) + +Accessor for the `TrustContracts` of this `Trust`. + + + +### `getTrustConfig() → struct TrustConfig` (external) + +Accessor for the `TrustConfig` of this `Trust`. + + + +### `getDistributionProgress() → struct DistributionProgress` (external) + +Accessor for the `DistributionProgress` of this `Trust`. + + + +### `getDistributionStatus() → enum DistributionStatus` (public) + +Accessor for the `DistributionStatus` of this `Trust`. + + + +### `anonEndDistribution()` (external) + +Anyone can end the distribution. +The requirement is that the `minimumTradingDuration` has elapsed. +If the `successBalance` is reached then the creator receives the raise +and seeder earns a fee. +Else the initial reserve is refunded to the seeder and sale proceeds +rolled forward to token holders (not the creator). + + + diff --git a/docusaurus/versioned_docs/version-v0.0.11/api/trust/TrustFactory.md b/docusaurus/versioned_docs/version-v0.0.11/api/trust/TrustFactory.md new file mode 100644 index 000000000..777061671 --- /dev/null +++ b/docusaurus/versioned_docs/version-v0.0.11/api/trust/TrustFactory.md @@ -0,0 +1,56 @@ +The `TrustFactory` contract is the only contract that the +deployer uses to deploy all contracts for a single project +fundraising event. It takes references to +`RedeemableERC20Factory`, `RedeemableERC20PoolFactory` and +`SeedERC20Factory` contracts, and builds a new `Trust` contract. + + +## Details +Factory for creating and registering new Trust contracts. + +## Variables +### `contract RedeemableERC20Factory` `redeemableERC20Factory` + +### `contract RedeemableERC20PoolFactory` `redeemableERC20PoolFactory` + +### `contract SeedERC20Factory` `seedERC20Factory` + + + + +## Functions +### `constructor(struct TrustFactoryConfig config_)` (public) + + + + + +### `createChild(struct TrustFactoryTrustConfig trustFactoryTrustConfig_, struct TrustFactoryTrustRedeemableERC20Config trustFactoryTrustRedeemableERC20Config_, struct TrustFactoryTrustRedeemableERC20PoolConfig trustFactoryTrustRedeemableERC20PoolConfig_) → address` (external) + +Allows calling `createChild` with TrustConfig, +TrustRedeemableERC20Config and +TrustRedeemableERC20PoolConfig parameters. +Can use original Factory `createChild` function signature if function +parameters are already encoded. + + + + + +### `_createChild(bytes data_) → address` (internal) + +Implements `IFactory`. + +`_createChild` hook must be overridden to actually create child +contract. + +Implementers may want to overload this function with a typed equivalent +to expose domain specific structs etc. to the compiled ABI consumed by +tooling and other scripts. To minimise gas costs for deployment it is +expected that the tooling will consume the typed ABI, then encode the +arguments and pass them to this function directly. + + + + + diff --git a/docusaurus/versioned_docs/version-v0.0.11/api/verify/Verify.md b/docusaurus/versioned_docs/version-v0.0.11/api/verify/Verify.md new file mode 100644 index 000000000..a3f3f6571 --- /dev/null +++ b/docusaurus/versioned_docs/version-v0.0.11/api/verify/Verify.md @@ -0,0 +1,91 @@ + + + +## Variables +### `uint32` `UNINITIALIZED` + +### `bytes32` `APPROVER_ADMIN` + +### `bytes32` `APPROVER` + +### `bytes32` `REMOVER_ADMIN` + +### `bytes32` `REMOVER` + +### `bytes32` `BANNER_ADMIN` + +### `bytes32` `BANNER` + +### `mapping(address => struct State)` `states` + + +## Events +### `Add(address account, uint256 id)` + +Emitted when a session ID is first associated with an account. + + + +### `Approve(address account)` + +Emitted when a previously added account is approved. + + + +### `Ban(address account)` + +Emitted when an added or approved account is banned. + + + +### `Remove(address account)` + +Emitted when an account is scrubbed from blockchain state. + + + + + +## Functions +### `constructor(address admin_)` (public) + +Defines RBAC logic for each role under Open Zeppelin. + + + +### `state(address account_) → struct State` (external) + +/ Typed accessor into states. + + + +### `statusAtBlock(struct State state_, uint32 blockNumber) → enum Status` (external) + +/ Derives a single `Status` from a `State` and a reference block number. + + + +### `add(uint256 id_)` (external) + + + + + +### `remove(address account_)` (external) + + + + + +### `approve(address account_)` (external) + + + + + +### `ban(address account_)` (external) + + + + + diff --git a/docusaurus/versioned_docs/version-v0.0.11/api/verify/VerifyFactory.md b/docusaurus/versioned_docs/version-v0.0.11/api/verify/VerifyFactory.md new file mode 100644 index 000000000..e1ed60367 --- /dev/null +++ b/docusaurus/versioned_docs/version-v0.0.11/api/verify/VerifyFactory.md @@ -0,0 +1,34 @@ +Factory for creating and deploying `Verify` contracts. + + + + + +## Functions +### `_createChild(bytes data_) → address` (internal) + +Implements `IFactory`. + +`_createChild` hook must be overridden to actually create child +contract. + +Implementers may want to overload this function with a typed equivalent +to expose domain specific structs etc. to the compiled ABI consumed by +tooling and other scripts. To minimise gas costs for deployment it is +expected that the tooling will consume the typed ABI, then encode the +arguments and pass them to this function directly. + + + + + +### `createChild(address admin_) → address` (external) + +Typed wrapper for `createChild` with admin address. +Use original `Factory` `createChild` function signature if function +parameters are already encoded. + + + + + diff --git a/docusaurus/versioned_sidebars/version-v0.0.11-sidebars.json b/docusaurus/versioned_sidebars/version-v0.0.11-sidebars.json new file mode 100644 index 000000000..a48589bdb --- /dev/null +++ b/docusaurus/versioned_sidebars/version-v0.0.11-sidebars.json @@ -0,0 +1,28 @@ +{ + "version-v0.0.11/tutorialSidebar": [ + { + "type": "doc", + "id": "version-v0.0.11/introduction" + }, + { + "type": "doc", + "id": "version-v0.0.11/glossary" + }, + { + "type": "doc", + "id": "version-v0.0.11/risk-mitigation" + }, + { + "type": "category", + "label": "API", + "items": [ + { + "type": "autogenerated", + "dirName": "api" + } + ], + "collapsible": true, + "collapsed": true + } + ] +} diff --git a/docusaurus/versions.json b/docusaurus/versions.json index dbabfef90..41e21beb8 100644 --- a/docusaurus/versions.json +++ b/docusaurus/versions.json @@ -1,3 +1,4 @@ [ + "v0.0.11", "v0.0.10" ]