├── tutorials
├── create-a-prize-strategy.md
├── networks.md
├── getting-started.md
├── buying-tickets.md
├── withdrawing-from-a-prize-pool.md
└── operate-a-prize-pool.md
├── .gitbook
└── assets
│ ├── 1_cu6o0qf_purcupmqiuv1aa.png
│ ├── screen-shot-2020-05-05-at-4.52.53-pm.png
│ ├── screen-shot-2020-07-28-at-1.26.44-pm.png
│ ├── screen-shot-2021-01-05-at-4.39.03-pm.png
│ ├── screen-shot-2021-01-05-at-5.08.06-pm.png
│ ├── screen-shot-2021-01-05-at-5.10.29-pm.png
│ ├── screen-shot-2021-01-05-at-5.11.24-pm.png
│ ├── screen-shot-2021-01-06-at-9.34.16-am.png
│ ├── screen-shot-2021-03-11-at-1.54.17-pm.png
│ ├── screen-shot-2021-03-11-at-2.03.50-pm.png
│ ├── screen-shot-2021-03-11-at-2.50.55-pm.png
│ ├── screen-shot-2021-03-11-at-4.43.14-pm.png
│ ├── screen-shot-2021-03-11-at-4.44.38-pm.png
│ ├── screen-shot-2021-03-29-at-5.02.37-pm.png
│ ├── screen-shot-2021-05-05-at-2.20.38-pm.png
│ └── prizepool.json
├── protocol
├── tokens
│ ├── sponsorship.md
│ ├── README.md
│ ├── ticket.md
│ └── token-listener.md
├── prize-pool
│ ├── compound-prize-pool.md
│ ├── stake-prize-pool.md
│ ├── ticket.md
│ ├── custom-yield-sources.md
│ ├── yvault-prize-pool.md
│ ├── fairness.md
│ └── README.md
├── random-number-generator
│ ├── blockhash.md
│ ├── chainlink-vrf.md
│ └── README.md
├── gas-usage.md
├── prize-strategy
│ ├── README.md
│ └── multiple-winners.md
├── lootbox.md
├── overview.md
└── prize-strategy.md
├── faq.md
├── security
├── audits-and-testing.md
├── bug-bounties.md
├── bounties.md
└── risks.md
├── migrating-from-v2-to-v3.md
├── resources.md
├── governance
└── overview.md
├── SUMMARY.md
├── README.md
└── networks.md
/tutorials/create-a-prize-strategy.md:
--------------------------------------------------------------------------------
1 | # Create a Prize Strategy
2 |
3 |
--------------------------------------------------------------------------------
/.gitbook/assets/1_cu6o0qf_purcupmqiuv1aa.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pooltogether/documentation/HEAD/.gitbook/assets/1_cu6o0qf_purcupmqiuv1aa.png
--------------------------------------------------------------------------------
/.gitbook/assets/screen-shot-2020-05-05-at-4.52.53-pm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pooltogether/documentation/HEAD/.gitbook/assets/screen-shot-2020-05-05-at-4.52.53-pm.png
--------------------------------------------------------------------------------
/.gitbook/assets/screen-shot-2020-07-28-at-1.26.44-pm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pooltogether/documentation/HEAD/.gitbook/assets/screen-shot-2020-07-28-at-1.26.44-pm.png
--------------------------------------------------------------------------------
/.gitbook/assets/screen-shot-2021-01-05-at-4.39.03-pm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pooltogether/documentation/HEAD/.gitbook/assets/screen-shot-2021-01-05-at-4.39.03-pm.png
--------------------------------------------------------------------------------
/.gitbook/assets/screen-shot-2021-01-05-at-5.08.06-pm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pooltogether/documentation/HEAD/.gitbook/assets/screen-shot-2021-01-05-at-5.08.06-pm.png
--------------------------------------------------------------------------------
/.gitbook/assets/screen-shot-2021-01-05-at-5.10.29-pm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pooltogether/documentation/HEAD/.gitbook/assets/screen-shot-2021-01-05-at-5.10.29-pm.png
--------------------------------------------------------------------------------
/.gitbook/assets/screen-shot-2021-01-05-at-5.11.24-pm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pooltogether/documentation/HEAD/.gitbook/assets/screen-shot-2021-01-05-at-5.11.24-pm.png
--------------------------------------------------------------------------------
/.gitbook/assets/screen-shot-2021-01-06-at-9.34.16-am.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pooltogether/documentation/HEAD/.gitbook/assets/screen-shot-2021-01-06-at-9.34.16-am.png
--------------------------------------------------------------------------------
/.gitbook/assets/screen-shot-2021-03-11-at-1.54.17-pm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pooltogether/documentation/HEAD/.gitbook/assets/screen-shot-2021-03-11-at-1.54.17-pm.png
--------------------------------------------------------------------------------
/.gitbook/assets/screen-shot-2021-03-11-at-2.03.50-pm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pooltogether/documentation/HEAD/.gitbook/assets/screen-shot-2021-03-11-at-2.03.50-pm.png
--------------------------------------------------------------------------------
/.gitbook/assets/screen-shot-2021-03-11-at-2.50.55-pm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pooltogether/documentation/HEAD/.gitbook/assets/screen-shot-2021-03-11-at-2.50.55-pm.png
--------------------------------------------------------------------------------
/.gitbook/assets/screen-shot-2021-03-11-at-4.43.14-pm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pooltogether/documentation/HEAD/.gitbook/assets/screen-shot-2021-03-11-at-4.43.14-pm.png
--------------------------------------------------------------------------------
/.gitbook/assets/screen-shot-2021-03-11-at-4.44.38-pm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pooltogether/documentation/HEAD/.gitbook/assets/screen-shot-2021-03-11-at-4.44.38-pm.png
--------------------------------------------------------------------------------
/.gitbook/assets/screen-shot-2021-03-29-at-5.02.37-pm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pooltogether/documentation/HEAD/.gitbook/assets/screen-shot-2021-03-29-at-5.02.37-pm.png
--------------------------------------------------------------------------------
/.gitbook/assets/screen-shot-2021-05-05-at-2.20.38-pm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pooltogether/documentation/HEAD/.gitbook/assets/screen-shot-2021-05-05-at-2.20.38-pm.png
--------------------------------------------------------------------------------
/protocol/tokens/sponsorship.md:
--------------------------------------------------------------------------------
1 | # 🎁 Sponsorship
2 |
3 | Users may "sponsor" the prize pool by depositing funds that don't make them eligible to win.
4 |
5 | This can be useful for the creators of the pool to bootstrap its liquidity.
6 |
7 |
--------------------------------------------------------------------------------
/faq.md:
--------------------------------------------------------------------------------
1 | # FAQ
2 |
3 | ## Can I become who I want to be?
4 |
5 | That's a tough question but thankfully, our team is on it. Please bear with us while we're investigating.
6 |
7 | ## How is fairness managed?
8 |
9 | Yes, after a few months we finally found the answer. Sadly, Mike is on vacations right now so I'm afraid we are not able to provide the answer at this point.
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/tutorials/networks.md:
--------------------------------------------------------------------------------
1 | # 📡 Networks
2 |
3 | ## Networks
4 |
5 | PoolTogether 3.0-alpha is currently deployed to the following networks:
6 |
7 | ### Kovan
8 |
9 | | Contract Name | Address |
10 | | :--- | :--- |
11 | | [CompoundPrizePoolBuilder](../protocol/builders/) | [0x6e12233ac8ccD7cC0d0481787D7e7dd943315984](https://kovan.etherscan.io/address/0x6e12233ac8ccD7cC0d0481787D7e7dd943315984) |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/protocol/tokens/README.md:
--------------------------------------------------------------------------------
1 | # 🎟️ Tokens
2 |
3 | When users deposit into a Prize Pool they receive an ERC20 compatible [ticket](ticket.md).
4 |
5 | External ERC721 and ERC20's can also be [added, controlled and removed](../prize-strategy/multiple-winners.md#external-erc20-and-erc721-awards) by Prize Pools.
6 |
7 | [Sponsorship](sponsorship.md) tokens are created when funds are added to the pool that are not eligible to win any prizes.
8 |
9 |
--------------------------------------------------------------------------------
/protocol/prize-pool/compound-prize-pool.md:
--------------------------------------------------------------------------------
1 | # Compound Prize Pool
2 |
3 | The Compound Prize Pool is a Prize Pool that uses [Compound](https://compound.finance) as the yield source. When a Compound Prize Pool is created it is configured with the cToken to use for minting and redeeming.
4 |
5 | ## Retrieving the Underlying cToken
6 |
7 | To access the underlying [cToken](https://compound.finance/docs/ctokens), simply call this function:
8 |
9 | ```javascript
10 | function cToken() returns (address);
11 | ```
12 |
13 |
--------------------------------------------------------------------------------
/protocol/random-number-generator/blockhash.md:
--------------------------------------------------------------------------------
1 | # Blockhash
2 |
3 | The Blockhash RNG uses a future blockhash as the random number. This is the least secure method of random number generation, but also the simplest and cheapest.
4 |
5 | When a user request a random number their lock block will be the current block. Their request is considered 'complete' when at least one block has been mined since the lock block. Upon retrieval the last blockhash will be stored as the random number and returned.
6 |
7 | ## Usage
8 |
9 | A prize strategy can use a [RNGBlockhash](../../networks.md) RNG service. No additional work is needed: the blockhash service is free.
10 |
11 |
--------------------------------------------------------------------------------
/protocol/prize-pool/stake-prize-pool.md:
--------------------------------------------------------------------------------
1 | # Stake Prize Pool
2 |
3 | The Stake Prize Pool is a prize pool that uses an ERC-20 compatible token as the underlying asset.
4 |
5 | Users's can stake their tokens to become eligible for whatever prize is defined as the prize strategy for that pool.
6 |
7 | This is particularly useful for protocols that are sitting inactively in users's wallets - why not stake them in a pool and become eligible for rewards?
8 |
9 | The returned [ticket](../tokens/ticket.md) can be thought of as a "proof-of-liquidity".
10 |
11 | ### Retrieving the Underlying ERC-20
12 |
13 | The underlying staked asset can be retrieved by calling:
14 |
15 | ```javascript
16 | function token() returns (address);
17 | ```
18 |
19 |
--------------------------------------------------------------------------------
/security/audits-and-testing.md:
--------------------------------------------------------------------------------
1 | # Audits & Testing
2 |
3 | The PoolTogether Protocol has undergone three formal professional third party audits. Two have been [conducted by Open Zeppelin](https://blog.openzeppelin.com/pooltogether-v3-audit/), and one by ditCraft.
4 |
5 | Additionally the PoolTogether core team has a long term security relationship with [ConsenSys Diligence](https://diligence.consensys.net/audits/) including monthly code reviews.
6 |
7 | Notwithstanding, portions of the PoolTogether Protocol codebase will continue to evolve and **it should never be expected that 100% of the deployed code has been formally audited.**
8 |
9 | We encourage responsible disclosure of any vulnerabilities in the smart contracts and will pay up to $25,000 for those. See the [Bounties](bounties.md) for more details.
10 |
11 |
--------------------------------------------------------------------------------
/protocol/prize-pool/ticket.md:
--------------------------------------------------------------------------------
1 | # Ticket
2 |
3 | The Ticket contract is an [ERC20](https://eips.ethereum.org/EIPS/eip-20)-compatible token that allows users to be selected by a token index.
4 |
5 | The contract organizes the balances into a sum tree data structure, so that each address holds a "range" of tokens. A number can be used as an index within that range, and the holder of the tokens in that range is selected:
6 |
7 | ```javascript
8 | function draw(uint256 randomNumber) public view returns (address)
9 | ```
10 |
11 | The **randomNumber** will be used as a token index into a specialized data structure that stores the user balances. The randomNumber is constrained to the token supply and modulo bias is corrected.
12 |
13 | The returned address is the user who holds the token index corresponding to the random number.
14 |
15 |
--------------------------------------------------------------------------------
/protocol/tokens/ticket.md:
--------------------------------------------------------------------------------
1 | # 🎟️ Ticket
2 |
3 | The Ticket contract is an [ERC20](https://eips.ethereum.org/EIPS/eip-20)-compatible token that allows users to be selected by a token index.
4 |
5 | The contract organizes the balances into a sum tree data structure, so that each address holds a "range" of tokens. A number can be used as an index within that range, and the holder of the tokens in that range is selected:
6 |
7 | ```javascript
8 | function draw(uint256 randomNumber) public view returns (address)
9 | ```
10 |
11 | The **randomNumber** will be used as a token index into a specialized data structure that stores the user balances. The randomNumber is constrained to the token supply and modulo bias is corrected.
12 |
13 | The returned address is the user who holds the token index corresponding to the random number.
14 |
15 |
--------------------------------------------------------------------------------
/protocol/prize-pool/custom-yield-sources.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Create a Prize Pool that Uses a Custom Yield Source
3 | ---
4 |
5 | # Custom Yield Sources
6 |
7 | If you would like to create a Prize Pool that generates prizes with a custom yield source, you'll need to:
8 |
9 | 1. Subclass the [Prize Pool](https://github.com/pooltogether/pooltogether-pool-contracts/blob/master/contracts/prize-pool/PrizePool.sol).
10 | 2. Implement the [Yield Source](https://github.com/pooltogether/pooltogether-pool-contracts/blob/master/contracts/prize-pool/YieldSource.sol) interface
11 |
12 | Once the subclass is written, you'll need to deploy it. The simplest approach will be to follow the [PoolWithMultipleWinnersBuilder](https://github.com/pooltogether/pooltogether-pool-contracts/blob/master/contracts/builders/PoolWithMultipleWinnersBuilder.sol) and create a contract that builds your custom prize pool with the appropriate strategy.
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/security/bug-bounties.md:
--------------------------------------------------------------------------------
1 | # Bug Bounties
2 |
3 | We value contributions from the community to strengthen the security of the core contracts. We want to reward any hackers in good faith who report vulnerabilities.
4 |
5 | The scope of this bounty includes the PoolTogether smart contracts. The determination of the bug severity will be made by the PoolTogether team.
6 |
7 | Payouts will be as follows:
8 |
9 | High: $25,000 DAI
10 | Medium: $10,000 DAI
11 | Low: $1,000 DAI
12 |
13 | The issue must:
14 |
15 | * be a previously unreported, non-public vulnerability.
16 | * include enough detail for us to identify and reproduce the problem
17 |
18 | All reports should start with an email to [hello@pooltogether.us](mailto:hello@pooltogether.us) and they will receive a response within 24 hours. Non-security issues are not eligible for this bounty.
19 |
20 | We determine the severity of an issue according to the [Smart Contract Security Alliance Severity Levels](https://www.smartcontractsecurityalliance.com/)
21 |
22 | Determinations of eligibility and all terms related to this award are at the sole and final discretion of the PoolTogether team.
23 |
24 |
--------------------------------------------------------------------------------
/protocol/gas-usage.md:
--------------------------------------------------------------------------------
1 | # ⛽ Gas Usage
2 |
3 | PoolTogether is conscious that to become a truly lossless prize protocol the transaction fees involved must be minimal. The current design utilizes the Minimal Proxy Factory design where possible to reduce gas usage.
4 |
5 | Note that these fees are paid to the Ethereum Network and not to PoolTogether. The amount a transaction costs in USD is calculated as: the amount of gas used \* gasPrice \* USD/ETH.
6 |
7 | Here is a list of common actions and their costs:
8 |
9 | | Function Call | Estimated Gas Cost | $USD \(40 GWei, $600/ETH\) |
10 | | :--- | :--- | :--- |
11 | | **Creating Pools with the Builder** | | |
12 | | createCompoundPoolMultipleWinners\(\) | 1.3M | 33 |
13 | | createStakePoolMultipleWinners\(\) | 1.25M | 30 |
14 | | createVaultPoolMultipleWinners\(\) | 1.2M | 30 |
15 | | **Entering and Leaving Pools** | | |
16 | | depositTo\(\) | 0.5M | 12 |
17 | | withdrawInstantlyFrom\(\) | 0.5M | 12 |
18 | | **Award Process** | | |
19 | | RNG request - [Chainlink VRF](random-number-generator/chainlink-vrf.md) | 2 LINK | 20 \(@ 10 USD/LINK\) |
20 | | startAward\(\) | 200k | 4.8 |
21 | | completeAward\(\) | 250k+ \(variable\) | 6 |
22 | | **Transferring Tickets** | 290k | 7 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/migrating-from-v2-to-v3.md:
--------------------------------------------------------------------------------
1 | # 💱 Migrating from V2 to V3
2 |
3 | Users of PoolTogether V2 can exchange their old tickets for new ones using the [new interface](https://app.pooltogether.com). See the "accounts" section.
4 |
5 | Users can exchange:
6 |
7 | * Dai Pool tickets
8 | * USDC Pool tickets
9 | * Dai Pod tickets
10 | * USDC Pod tickets
11 |
12 | All of these tickets will be exchange 1:1 for new V3 Pool Dai tickets. Note that you will not receive USDC back, you will be **exchanging your USDC Tickets for Dai Tickets**.
13 |
14 | ## Migrating Your Tickets
15 |
16 | 1. Do an ER20 token transfer to the migration contract.
17 | 2. The migration contract will transfer PcDAI to the sender.
18 |
19 | PoolTogether V2 tickets and Pod shares are ERC777 tokens; this token standard triggers a callback on the recipient when the recipient is a contract. When the migration contract is triggered it automatically send PcDAI back to the sender.
20 |
21 | For the latest address see the [Networks](networks.md) page. Look for the Migration contract on mainnet.
22 |
23 | ## Troubleshooting
24 |
25 | The migration contract needs to be stocked with liquidity, so if your ticket exchange fails please contact us on [our Discord](https://discord.gg/hxPhPDW).
26 |
27 |
--------------------------------------------------------------------------------
/protocol/random-number-generator/chainlink-vrf.md:
--------------------------------------------------------------------------------
1 | # Chainlink VRF
2 |
3 | **A verifiable random function is a pseudo-random function whose output is unique and can be publicly verified.**
4 |
5 | ChainLink has implemented their VRF using public key cryptography. It works like so:
6 |
7 | 1. The user creates a “seed” value
8 | 2. A ChainLink operator, who has publicly committed to a keypair, uses their secret to sign the seed value.
9 | 3. The user is able to verify that the operator has signed the seed value, and consume the signature as the “random number”.
10 |
11 | **ChainLink VRF Documentation:** [**https://docs.chain.link/docs/chainlink-vrf**](https://docs.chain.link/docs/chainlink-vrf)
12 |
13 | This approach has some benefits in that the operator cannot “lie”: they must sign the seed using the secret they have committed to. The algorithm is also instantaneous: there is no delay or waiting period to get the answer. ****
14 |
15 | ## Usage
16 |
17 | To use the [RNGChainlink](../../networks.md) RNG service, create a new prize pool using the service or set it on an existing pool.
18 |
19 | 🚨🚨🚨 **Chainlink RNG requires 2 LINK tokens per RNG request** 🚨🚨🚨
20 |
21 | 🚨🚨🚨 **You must deposit LINK into the PRIZE STRATEGY** 🚨🚨🚨
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/resources.md:
--------------------------------------------------------------------------------
1 | # 🚰 Resources
2 |
3 | ## Tools
4 |
5 | * [Prize Pool Builder](https://builder.pooltogether.com) ([Source Code](https://github.com/pooltogether/pooltogether-pool-builder-ui))
6 | * [Prize Pool Reference App](https://reference-app.pooltogether.com) ([Source Code](https://github.com/pooltogether/pooltogether-reference-pool-ui))
7 |
8 | ## Code
9 |
10 | * [Prize Pool Contracts](https://github.com/pooltogether/pooltogether-pool-contracts)
11 | * [Random Number Generator Contracts](https://github.com/pooltogether/pooltogether-rng-contracts)
12 | * [PoolTogether V3 Subgraph](https://github.com/pooltogether/pooltogether-subgraph-v3)
13 | * [Loot Box Contracts](https://github.com/pooltogether/loot-box)
14 | * [OpenZeppelin Defender Award Autotask](https://github.com/pooltogether/defender-autotask-reward)
15 | * [V2 to V3 Migration Contracts](https://github.com/pooltogether/pooltogether-migrate-v3)
16 |
17 | ## Subgraphs
18 |
19 | * [mainnet Subgraph](https://thegraph.com/explorer/subgraph/pooltogether/pooltogether-v3\_1\_0)
20 | * [mainnet LootBox Subgraph](https://thegraph.com/explorer/subgraph/pooltogether/lootbox-v1\_0\_0)
21 | * [rinkeby Subgraph](https://thegraph.com/explorer/subgraph/pooltogether/rinkeby-v3\_1\_0)
22 |
23 | ## Workshops
24 |
25 | * [ETHOnline Hackathon Custom Prize Strategy](https://github.com/pooltogether/ethonline-workshop)
26 |
--------------------------------------------------------------------------------
/governance/overview.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: The Role of Governance
3 | ---
4 |
5 | # 🏛️ Overview
6 |
7 | _The PoolTogether protocol will be transitioning to decentralized governance. In the meantime, the core team serves as the interim governance body._
8 |
9 | PoolTogether Governance broadly serves two mandates:
10 |
11 | * Protocol improvement
12 | * Prize Pool management
13 |
14 | ## Protocol Improvement
15 |
16 | Governance will guide the evolution of the protocol towards the goal of building products that create financial health. The primary functions of governance are to:
17 |
18 | * Set [rewards](broken-reference) for prize pool users
19 | * Approve & implement new yield sources for prize pools
20 | * Implement new prize strategies
21 |
22 | In addition to these core functions governance may:
23 |
24 | * propose integrations with L2 systems
25 | * Add additional prizes or rewards
26 | * subsidized transactions
27 | * insurance coverage
28 | * Anything else!
29 |
30 | ## Prize Pool Management
31 |
32 | Governance also manages its own set of Prize Pools. These Prize Pools are displayed on the official [PoolTogether App](https://app-v3.pooltogether.com).
33 |
34 | ## Comptroller
35 |
36 | All Prize Pools link to a global protocol [Comptroller](broken-reference). The Comptroller is owned by governance, and determines the reserve rate and rewards Prize Pools.
37 |
--------------------------------------------------------------------------------
/protocol/tokens/token-listener.md:
--------------------------------------------------------------------------------
1 | # 👂 Token Listener
2 |
3 | The Token Listener interface allows contracts to "listen" to the complete token lifecycle of mint, transfer and burn. There are two functions that must be implemented: `beforeTokenMint` and `beforeTokenTransfer`
4 |
5 | The beforeTokenMint function must be called whenever a token is minted.
6 |
7 | ```javascript
8 | function beforeTokenMint(
9 | address to,
10 | uint256 amount,
11 | address controlledToken,
12 | address referrer
13 | ) external;
14 | ```
15 |
16 | | Paramater Name | Parameter Description |
17 | | :--- | :--- |
18 | | to | The address that is receiving the newly minted tokens |
19 | | amount | The amount of new tokens |
20 | | controlledToken | The token being minted |
21 | | referrer | The address that referred the user \(for rewards\) |
22 |
23 | The beforeTokenTransfer function must be called whenever a token is transferred or burned.
24 |
25 | ```javascript
26 | function beforeTokenTransfer(
27 | address from,
28 | address to,
29 | uint256 amount,
30 | address controlledToken
31 | ) external;
32 | ```
33 |
34 | | Paramater Name | Parameter Description |
35 | | :--- | :--- |
36 | | from | The address that is sending the tokens |
37 | | to | The address that is receiving tokens. May be the zero address if burning. |
38 | | amount | The amount of tokens |
39 | | controlledToken | The token being transferred |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/protocol/prize-strategy/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Customize how a Prize Pool distributes prizes
3 | ---
4 |
5 | # 💸 Prize Strategies
6 |
7 | A Prize Strategy handles prize distribution for a [Prize Pool](../prize-pool/). When a Prize Pool is constructed it is configured with a Prize Strategy. The Prize Strategy has the privileged ability to award tokens from the Prize Pool.
8 |
9 | The most popular Prize Strategy offering is the [Multiple Winner](https://app.gitbook.com/s/-M58QPye9-PujrSjSWqv-887967055/protocol/multiple-winners/) strategy. Earlier versions (< v3.1.0) of the protocol used the Single Random Winner strategy, which is now a trivial subset of Multiple Winners (with `numberofWinners = 1`).
10 |
11 | Prize Strategies must implement the [Token Listener](../tokens/token-listener.md) interface so that they can be aware of the full token lifecycle.
12 |
13 | ## Privileged Actions
14 |
15 | A [Prize Pool's](../prize-pool/) Prize Strategy is able to award tokens held by the Prize Pool contract. The Prize Strategy is able to:
16 |
17 | * [award yield](../prize-pool/#awarding-yield) that has accrued in the Prize Pool
18 | * [award any ERC20 balance](../prize-pool/#awarding-erc-20-s) held by the Prize Pool
19 | * [award any ERC721](../prize-pool/#awarding-erc-721-s-nfts) owned by the Prize Pool
20 |
21 | ## Required Behaviour
22 |
23 | A Prize Strategy must implement the [Token Listener](../tokens/token-listener.md) interface so that it can listen to pool token mint, transfer and burn actions by the Prize Pool.
24 |
--------------------------------------------------------------------------------
/SUMMARY.md:
--------------------------------------------------------------------------------
1 | # Table of contents
2 |
3 | * [✨ Introduction](README.md)
4 | * [📡 Networks](networks.md)
5 | * [🚰 Resources](resources.md)
6 | * [💱 Migrating from V2 to V3](migrating-from-v2-to-v3.md)
7 |
8 | ## Protocol
9 |
10 | * [🌐 Overview](protocol/overview.md)
11 | * [🏆 Prize Pools](protocol/prize-pool/README.md)
12 | * [⚖️ Fairness](protocol/prize-pool/fairness.md)
13 | * [Compound Prize Pool](protocol/prize-pool/compound-prize-pool.md)
14 | * [Stake Prize Pool](protocol/prize-pool/stake-prize-pool.md)
15 | * [yVault Prize Pool](protocol/prize-pool/yvault-prize-pool.md)
16 | * [Custom Yield Sources](protocol/prize-pool/custom-yield-sources.md)
17 | * [💸 Prize Strategies](protocol/prize-strategy/README.md)
18 | * [🤑 Multiple Winners](protocol/prize-strategy/multiple-winners.md)
19 | * [🎟️ Tokens](protocol/tokens/README.md)
20 | * [🎟️ Ticket](protocol/tokens/ticket.md)
21 | * [🎁 Sponsorship](protocol/tokens/sponsorship.md)
22 | * [👂 Token Listener](protocol/tokens/token-listener.md)
23 | * [🎲 Random Number Generator](protocol/random-number-generator/README.md)
24 | * [Blockhash](protocol/random-number-generator/blockhash.md)
25 | * [Chainlink VRF](protocol/random-number-generator/chainlink-vrf.md)
26 | * [🏴☠️ Loot Box](protocol/lootbox.md)
27 | * [⛽ Gas Usage](protocol/gas-usage.md)
28 |
29 | ## Governance
30 |
31 | * [🏛️ Overview](governance/overview.md)
32 |
33 | ## Security
34 |
35 | * [Risks](security/risks.md)
36 | * [Audits & Testing](security/audits-and-testing.md)
37 | * [Bounties](security/bounties.md)
38 |
--------------------------------------------------------------------------------
/tutorials/getting-started.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Start Building with PoolTogether
3 | ---
4 |
5 | # Getting Started
6 |
7 | There are many ways to integrate with PoolTogether! Follow the tutorials or browse the resources below.
8 |
9 | ## Tutorials
10 |
11 | * [Depositing into a Prize Pool](buying-tickets.md)
12 | * [Withdraw from a Prize Pool](withdrawing-from-a-prize-pool.md)
13 | * [Create a Prize Pool](creating-a-prize-pool.md)
14 | * Create a Prize Strategy
15 |
16 | ## Resources
17 |
18 | ### Create New Prize Pools
19 |
20 | * Use the [Builder](https://builder.pooltogether.com) user interface. Source code is on [Github](https://github.com/pooltogether/pooltogether-pool-builder-ui).
21 | * Use the core [PoolTogether Pool Contracts](../networks.md). Source code is on [Github](https://github.com/pooltogether/pooltogether-pool-contracts).
22 |
23 | ### Interact With Prize Pools
24 |
25 | * Use the official [PoolTogether App](https://staging-v3.pooltogether.com/) to interact with PoolTogether-managed prize pools
26 | * Pull in the [Current Pool Data](https://github.com/pooltogether/current-pool-data) npm package to programmatically get the list of pools
27 | * Use and fork the [PoolTogether Reference App](https://reference-app.pooltogether.com/) to interact with Prize Pools created by the builder
28 | * Use the [Buidler Console](https://github.com/pooltogether/buidler-console) project to interact with prize pools directly from the command line
29 | * Use the official [Graph Protocol Subgraph](https://github.com/pooltogether/pooltogether-subgraph-v3) to query data. See it on the [Graph Explorer](https://thegraph.com/explorer/subgraph/pooltogether/pooltogether-v3_1_0).
30 |
--------------------------------------------------------------------------------
/protocol/prize-pool/yvault-prize-pool.md:
--------------------------------------------------------------------------------
1 | # yVault Prize Pool
2 |
3 | The yVault Prize Pool is a prize pool that uses a yEarn [yVault](https://yearn.finance/vaults) as a yield source. When a yVault Prize Pool is created it is configured with a yVault to deposit and withdraw from. This particular prize pool retains a small reserve in order to cover yVault withdrawal fees.
4 |
5 | ## Prize Pool Reserve
6 |
7 | yVaults may charge users a fee upon withdrawal if the amount exceeds the vault holdings. In order to compensate for this the yVault Prize Pool retains a reserve at a rate matching the fee. For example, if the [yVault fee is 0.5%](https://docs.yearn.finance/products/yvaults#delegated-yvaults) then the yVault Prize Pool will retain 0.5% of the deposits as reserve. The reserve will **not** be exposed to the Prize Strategy for distribution: it will be retained to cover withdrawal fees.
8 |
9 | {% hint style="info" %}
10 | It may appear that users will immediately lose 0.5% upon deposit, but it is important to note that the reserve works in tandem with the [credit system](fairness.md). The credit system ensures users participate long enough to contribute to the prize and the reserve.
11 | {% endhint %}
12 |
13 | The reserve rate can be retrieved using:
14 |
15 | ```javascript
16 | function reserveRateMantissa() returns (uint256);
17 | ```
18 |
19 | This returns the reserve rate as a 18 decimal fixed point number \(like Ether\).
20 |
21 | The _owner_ of the prize pool can set the reserve rate using the function:
22 |
23 | ```javascript
24 | function setReserveRateMantissa(
25 | uint256 _reserveRateMantissa
26 | ) external onlyOwner
27 | ```
28 |
29 | ## Retrieving the Underlying yVault
30 |
31 | The underlying yVault address can be retrieved using the function:
32 |
33 | ```javascript
34 | function vault() returns (address);
35 | ```
36 |
37 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ✨ Introduction
2 |
3 | [](https://github.com/pooltogether/pooltogether--brand-assets)
4 |
5 | ## ✨ Introduction
6 |
7 | PoolTogether is a protocol for no-loss prize games on the Ethereum blockchain. The protocol:
8 |
9 | **1\) Enables developers to build their own no-loss prize games
10 | 2\)** **Offers governance-managed no-loss prize games**
11 |
12 | Prize games are pools of funds whose accrued interest is distributed as prizes. The concept is well-established and otherwise known as "[no loss lotteries](http://beniverson.org/papers/MaMa.pdf)" or "[prize savings accounts](https://en.wikipedia.org/wiki/Prize-linked_savings_account)". All prize games created by the protocol share the same key characteristics:
13 |
14 | * No loss of deposited funds
15 | * Ability to withdraw at any time
16 | * Fair prize distribution according to a prize strategy
17 |
18 | Prize games can be differentiated in the following ways:
19 |
20 | * The yield source the prize pool uses to generate no loss return
21 | * The prize strategy used to determine frequency and distribution of prizes
22 | * The additional rewards offered by the prize pool
23 | * The asset type the prize pool accepts for deposits
24 | * The fairness parameters
25 |
26 | ### Governance
27 |
28 | The PoolTogether Protocol governance serves two primary functions.
29 |
30 | * Governing the prize pool creation tools
31 | * Governing a sub-set of prize pools
32 |
33 | The protocol governed prize pools appear on the official [PoolTogether App](https://app-v3.pooltogether.com). Governance is currently the core PoolTogether team, but very soon governance control will be distributed amongst protocol stakeholders.
34 |
35 |
36 |
37 | ####
38 |
39 | ####
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/security/bounties.md:
--------------------------------------------------------------------------------
1 | # Bounties
2 |
3 | We value contributions from the community to strengthen the security of the core contracts. We want to reward any hackers in good faith who report vulnerabilities.
4 |
5 | The scope of this bounty includes the PoolTogether smart contracts. The determination of the bug severity will be made by the PoolTogether team. We determine the severity of an issue according to the [Smart Contract Security Alliance Severity Levels](https://www.smartcontractsecurityalliance.com/)
6 |
7 | Payouts will be as follows:
8 |
9 | High: $25,000 DAI
10 | Medium: $10,000 DAI
11 | Low: $1,000 DAI
12 |
13 | The issue must:
14 |
15 | * be a previously unreported, non-public vulnerability.
16 | * include enough detail for us to identify and reproduce the problem
17 |
18 | All reports should start with an email to [hello@pooltogether.us](mailto:hello@pooltogether.us) and they will receive a response within 24 hours. Non-security issues are not eligible for this bounty.
19 |
20 | Determinations of eligibility and all terms related to this award are at the sole and final discretion of the PoolTogether team.
21 |
22 | ## Past Bounties
23 |
24 | ### PermitAndDepositDai Contract: Unrestricted Sender
25 |
26 | Severity: Medium / High
27 | Date: Thursday, October 22nd, 2020
28 | Reporter: Kevin Foesenek
29 | Payout: $20,000 USD of WETH \([transaction](https://etherscan.io/tx/0xdd9fcf07a29a376b811c775d34cef4ceddf6e720981da34ac7142a8c38e7e7a6)\)
30 |
31 | **Vulnerability**
32 | Just prior to launch a security researcher discovered a flaw in the PermitAndDepositDai contract. This flaw would have allowed an attacker to front-run the "deposit" transaction and take the deposited amount. This would have affected any new deposits to the system.
33 |
34 | **Mitigation**
35 | References to the contract were removed from the user interface, and a fix was immediately deployed to mainnet and published via NPM.
36 |
37 |
--------------------------------------------------------------------------------
/protocol/random-number-generator/README.md:
--------------------------------------------------------------------------------
1 | # 🎲 Random Number Generator
2 |
3 | PoolTogether has abstracted the generation of random numbers by creating a request-based Random Number Generator interface.
4 |
5 | It functions like so:
6 |
7 | 1. The user will first get the request fee. The fee will be expressed using an \(address, amount\) pair representing the required ERC20 and amount.
8 | 2. The user will then approve the RNG to spend that ERC20 of the amount
9 | 3. The user will then request the random number. The RNG will transfer the cost into itself and begin the request. The request returns a request identifier.
10 | 4. The user may check to see if the random number is available using the identifier.
11 | 5. When the random number is available the user may retrieve it with the identifier.
12 |
13 | Let's look at these functions in detail.
14 |
15 | ## Get the Request Fee
16 |
17 | Many RNG services require tokens in order to operate. To get the cost of the rng you may do so using:
18 |
19 | ```javascript
20 | function getRequestFee() external view returns (address feeToken, uint256 requestFee);
21 | ```
22 |
23 | This function returns two values:
24 |
25 | * **feeToken:** the ERC20 that needs to be paid
26 | * **requestFee:** is the amount of the token that needs to be paid
27 |
28 | ## Request a Random Number
29 |
30 | Once the user has approved the RNG service spend, they may request a random number like so:
31 |
32 | ```javascript
33 | function requestRandomNumber() external returns (uint32 requestId, uint32 lockBlock);
34 | ```
35 |
36 | This function returns two values:
37 |
38 | * **requestId:** the unique id for this RNG request
39 | * **lockBlock:** the commitment block for this RNG request. Users of the RNG request shouldn't make any changes after the lockBlock, otherwise the RNG may be less secure. For example, the Prize Strategy will lock all ticket sales and movements after the lockBlock, as they affect the winner selection. Once the request is complete the Prize Strategy unlocks tickets.
40 |
41 | ## Check if Request is Complete
42 |
43 | The user may check if a request is complete:
44 |
45 | ```javascript
46 | function isRequestComplete(uint32 requestId) external view returns (bool isCompleted)
47 | ```
48 |
49 | ## Retrieve Random Number
50 |
51 | ```javascript
52 | function randomNumber(uint32 requestId) external returns (uint256 randomNum);
53 | ```
54 |
55 | ##
56 |
57 |
--------------------------------------------------------------------------------
/protocol/lootbox.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: What is a PoolTogether Loot Box?
3 | ---
4 |
5 | # 🏴☠️ Loot Box
6 |
7 | ### Overview
8 |
9 | The PoolTogether Loot Box is a permission-less token container. A Loot Box allows wallets to be transferred like an ERC721.
10 |
11 | Many different tokens can be controlled simply by one counterfactual address. The holding contract is created and destroyed within the same transaction. This cheap deployment and immediate destruction of the contract minimizes the gas overhead involved with containerization.
12 |
13 | The code can be found here: [https://github.com/pooltogether/loot-box](https://github.com/pooltogether/loot-box)
14 |
15 | ### How it works
16 |
17 | A LootBox contract ephemerally exists within a transaction. The owner of an `ERC721` owns the LootBox.
18 |
19 | 1. A `ERC721` is created by calling `createERC721Controlled()` on the `ERC721ProxyFactory` by anyone:
20 |
21 | ```javascript
22 | function createERC721Controlled(
23 | string memory name,
24 | string memory symbol,
25 | string memory baseURI
26 | ) external returns (ERC721Controlled)
27 | ```
28 |
29 | 1. `mint()` can then be called on the `ControlledERC721` which effectively creates a LootBox with an Owner defined by the `to` field:
30 |
31 | ```javascript
32 | function mint(address to) external onlyAdmin returns (uint256)
33 | ```
34 |
35 | 2\. The LootBox address is calculated by calling:
36 |
37 | ```javascript
38 | computeAddress(address erc721, uint256 tokenId)
39 | ```
40 |
41 | 3\. Tokens are transferred/minted to this address. In the case of PoolTogether, these are usually external ERC20, ERC721 and ERC1155 rewards for a Prize Period.
42 |
43 | 4\. Anyone can call `plunder()` on the LootBox controller which will transfer all the passed tokens to the LootBox owner.
44 |
45 | ```javascript
46 | function plunder(
47 | address erc721,
48 | uint256 tokenId,
49 | address[] calldata erc20s,
50 | WithdrawERC721[] calldata erc721s,
51 | WithdrawERC1155[] calldata erc1155s
52 | )
53 | ```
54 |
55 | where `erc20s` is defined as an array of ERC-20 addresses,
56 |
57 | `erc721s` is defined as:
58 |
59 | ```c
60 | struct WithdrawERC721 {
61 | address token;
62 | uint256[] tokenIds;
63 | }
64 | ```
65 |
66 | and `erc1155s` as:
67 |
68 | ```c
69 | struct WithdrawERC1155 {
70 | address token;
71 | uint256[] ids;
72 | uint256[] amounts;
73 | bytes data;
74 | }
75 | ```
76 |
--------------------------------------------------------------------------------
/protocol/overview.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: What are No-Loss Prize Games?
3 | ---
4 |
5 | # 🌐 Overview
6 |
7 | No-loss prize games are pools of funds whose accrued interest is distributed as prizes.
8 |
9 | The high level protocol architecture is outlined below. The code is available on [Github](https://github.com/pooltogether/pooltogether-pool-contracts).
10 |
11 | ## How it works
12 |
13 | 1. Users deposit funds into a Prize Pool. They receive pool tokens in exchange.
14 | 2. The funds earn interest.
15 | 3. The interest is distributed by the Prize Strategy as pool tokens.
16 | 4. Users withdraw their funds at any time by telling the Prize Pool to burn their pool tokens.
17 |
18 | ## Architecture
19 |
20 | ### [Prize Pools](prize-pool/)
21 |
22 | Prize Pools are the central building block of prize games. They pool user funds in a **yield source** and expose the yield to their **Prize Strategy**, which then disburses as desired.
23 |
24 | Prize Pools can be differentiated in four primary ways:
25 |
26 | * The yield source the prize pool uses to generate no loss return
27 | * The prize strategy used to determine frequency and distribution
28 | * The rewards offered by the prize pool
29 | * The asset type the prize pool accepts for deposits
30 | * The fairness parameters
31 |
32 | ### [Prize Strategies](prize-strategy/)
33 |
34 | Prize Strategies determine the prize distribution for the Prize Pool. They can define any logic to allocate tokens that the prize pool accrues. Specifically they can:
35 |
36 | * Award yield in the Prize Pool as pool tokens
37 | * Award ERC20 tokens held by the Prize Pool
38 | * Award ERC721 tokens held by the Prize Pool
39 |
40 | ### [Builders](broken-reference)
41 |
42 | Builders make it easy to create pre-configured prize games. There are currently three Prize Pool types paired with the MultipleWinners, documentation available [here](broken-reference).
43 |
44 | ### [Random Number Generator](random-number-generator/)
45 |
46 | There are many different ways to generate a random number, so we've abstracted them as request-based Random Number Generator services. Each RNG service has a different security profile, so be sure to use the appropriate one for your game.
47 |
48 | ## Conventions
49 |
50 | Fixed point math is used extensively in PoolTogether. We used fixed point math with 18 decimal places for all fractional numbers. You can think of this as being just like Ether and wei: a value of "1" Ether is represented as "1000000000000000000" wei.
51 |
52 | When a number is a fixed point 18 number we always suffix the number with _mantissa._ For example the credit rate is written as _creditRateMantissa_, because it is a fixed point number.
53 |
54 |
--------------------------------------------------------------------------------
/security/risks.md:
--------------------------------------------------------------------------------
1 | # Risks
2 |
3 | Using the protocol includes substantial risks of losing some or all of your funds. The PoolTogether core team and community have made every effort to ensure the security of funds.
4 |
5 | This section will help you understand the the types of risk you are taking what has been done to mitigate them and how to mitigate them further.
6 |
7 | ### Protocol Dependency Risk
8 |
9 | The PoolTogether Protocol uses several other protocols. Therefore the first type of risk is the risk that these other integrated protocols can fail.
10 |
11 | Specifically by using PoolTogether you are also taking on the risks of using the Ethereum network, the collateral you are depositing, and the yield service \(currently Compound.Finance\).
12 |
13 | To mitigate this risk the protocol is only integrated with highly reputable and well secured protocols.
14 |
15 | ### Smart Contract Exploit Risk
16 |
17 | The second type of risk is specific to PoolTogether. The risk is that there could be some sort of bug or exploit in the smart contracts that run the PoolTogether Protocol. This is a risk with any product on Ethereum. Depending on what the bug or exploit is, a nefarious person may be able to take some or all of the funds stored in the PoolTogether Protocol. Here’s what we’ve done to mitigate this risk.
18 |
19 | 1. Professional, third party smart contract auditing. PoolTogether has hired companies to professionally review and audit the smart contract code for any bugs or exploits. These auditors have produced reports with their findings. As PoolTogether continues to grow we’re committed to continuing to pay for audits however, it should be understood that at any given time, 100% of the code base has not been professionally audited.
20 | 2. Bug Bounty program. PoolTogether offers payment of up to $25,000 for reports of any bugs in the smart contracts. If someone was to discover a bug, this is a way for them to responsibly disclose it to us and be paid rather than exploit it.
21 | 3. All the smart contract code is open source, meaning it is publicly readable by anyone. At first this may sound strange but it actually makes the protocol more secure as anyone can review it for bugs and submit a bug bounty.
22 | 4. Before we even give our code to auditors we also do extensive internal testing.
23 |
24 | ### Wallet Loss Risk
25 |
26 | This risk doesn’t have anything to do with PoolTogether but we wanted to mention it. Using PoolTogether requires you to use an Ethereum wallet that supports Ethereum apps. If you permanently lose access to this wallet, you will not be able to recover your funds. Different wallets have different recovery mechanisms. It’s important for you to know what those are and be able to recover your wallet. [Argent Wallet](https://www.argent.xyz/) is one example of a wallet with good recovery methods.
27 |
28 |
--------------------------------------------------------------------------------
/tutorials/buying-tickets.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: How to Buy Tickets in a PoolTogether Prize Pool
3 | ---
4 |
5 | # Deposit into a Prize Pool
6 |
7 | Let's deposit into a Prize Pool. Each step of the way we'll show you how to do it in both Solidity and Javascript \(using [Ethers.js](https://docs.ethers.io)\).
8 |
9 | First, we'll need to identify what the underlying asset to be deposited is. If it's a Compound Prize Pool, we'll want to check which cToken it is.
10 |
11 | Let's assume we have a Compound Prize Pool that is built against cDai.
12 |
13 | ## Approve
14 |
15 | Let's approve the Prize Pool to spend 1 of our Dai:
16 |
17 | **Solidity**
18 |
19 | ```text
20 | DAI_ERC20.approve(CDAI_PRIZE_POOL, 1 ether);
21 | ```
22 |
23 | **JavaScript**
24 |
25 | ```javascript
26 | const ethers = require('ethers')
27 | const signer = ethers.Wallet.createRandom()
28 |
29 | const dai = new ethers.Contract(
30 | DAI_ADDRESS,
31 | ERC20_ABI,
32 | signer
33 | )
34 |
35 | const daiPrizePool = new ethers.Contract(
36 | DAI_PRIZE_POOL_ADDRESS,
37 | PRIZE_POOL_ABI,
38 | signer
39 | )
40 |
41 | await dai.approve(daiPrizePool.address, ethers.utils.parseEther('1'))
42 |
43 | ```
44 |
45 | ## Deposit
46 |
47 | Now let's deposit into the Prize Pool. Since we're depositing into a [Compound Prize Pool](../protocol/prize-pool/compound-prize-pool.md) that uses a [Single Random Winner]() strategy, we'll want to mint Tickets so that we're eligible for prizes.
48 |
49 | We can retrieve the Ticket [controlled token](../protocol/prize-pool/#controlled-tokens) address from the Single Random Winner prize strategy:
50 |
51 | **Solidity**
52 |
53 | ```javascript
54 | address ticketAddress = SINGLE_RANDOM_WINNER.ticket();
55 | ```
56 |
57 | **JavaScript**
58 |
59 | ```javascript
60 | const strategyAddress = await daiPrizePool.prizeStrategy()
61 |
62 | const singleRandomWinner = new ethers.Contract(
63 | strategyAddress,
64 | SINGLE_RANDOM_WINNER_ABI,
65 | signer
66 | )
67 |
68 | const ticketAddress = await singleRandomWinner.ticket()
69 | ```
70 |
71 | Now let's deposit to mint tickets for ourselves:
72 |
73 | **Solidity**
74 |
75 | ```javascript
76 | CDAI_PRIZE_POOL.depositTo(
77 | MY_ADDRESS,
78 | 1 ether,
79 | ticketAddress,
80 | address(0)
81 | );
82 | ```
83 |
84 | **JavaScript**
85 |
86 | ```javascript
87 | await daiPrizePool.depositTo(
88 | signer._address,
89 | ethers.utils.parseEther(1),
90 | ticketAddress,
91 | ethers.constants.AddressZero
92 | )
93 | ```
94 |
95 | ## Depositing Sponsorship
96 |
97 | If you wish to deposit and receive sponsorship, or any other controlled token, you simply need to pass it in as the `controlledToken` argument.
98 |
99 | ## Depositing for Someone Else
100 |
101 | If you'd like to deposit on someone else's behalf, you can simply change the `to` address in the call to whomever you want to receive the tickets. Note that the caller will not be able to withdraw the funds; those funds can only be withdrawn by the recipient unless they increase your allowance.
102 |
103 | ## Capturing Referral Rewards
104 |
105 | The last parameter to the depositTo function is the referral address. The protocol may drip referral awards globally to Prize Pools. Referrals can earn tokens based on the fraction of referral volume they supply.
106 |
107 | Any interface for a PrizePool will want to pass it's own address as the referrer so that it can capture sweet, sweet rewards.
108 |
109 | For more information see [Rewards]()
110 |
111 |
--------------------------------------------------------------------------------
/protocol/prize-strategy.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Customize how a Prize Pool distributes prizes
3 | ---
4 |
5 | # 💸 Prize Strategies
6 |
7 | A Prize Strategy handles prize distribution for a [Prize Pool](prize-pool/). When a Prize Pool is constructed it is configured with a Prize Strategy.
8 |
9 | The Prize Strategy created by the [Compound Prize Pool Builder](builders/) is upgradeable by the governor contract.
10 |
11 | ## Prize Strategy Interface
12 |
13 | ### Calculating the Early Exit Fee
14 |
15 | When a user wishes to redeem their tickets instantly, the prize pool will ask the strategy what the fairness fee should be.
16 |
17 | The function signature is:
18 |
19 | ```javascript
20 | function calculateInstantWithdrawalFee(
21 | address from,
22 | uint256 amount,
23 | address controlledToken
24 | )
25 | external
26 | returns (uint256 remainingFee, uint256 burnedCredit)
27 | ```
28 |
29 | The strategy will be given the user, the number of tickets they are attempting to withdraw, and is expected to return the fee amount.
30 |
31 | ### Calculating the Withdrawal Timelock
32 |
33 | When a user wishes to redeem their tickets without paying any fees, then prize pool will ask the strategy what the unlock timestamp is:
34 |
35 | ```javascript
36 | function calculateTimelockDurationAndFee(
37 | address from,
38 | uint256 amount,
39 | address controlledToken
40 | )
41 | external
42 | returns (uint256 durationSeconds, uint256 burnedCredit)
43 | ```
44 |
45 | The strategy will be passed the user and the amount of tickets and be expected to return the timestamp after which the user may withdraw.
46 |
47 | ## Prize Strategy Privileges
48 |
49 | Only the Prize Strategy is able to award prizes on its associated [Prize Pool](prize-pool/). See [Awarding Prizes](prize-pool/#awarding-prizes).
50 |
51 | ## Awarding Prizes
52 |
53 | Prizes are awarded in two phases. The first phase locks the Pool and requests a random number from the Random Number Generation service. The second phase retrieves the random number, award the prize, and unlocks the pool.
54 |
55 | The first phase of the award process begins by calling:
56 |
57 | ```javascript
58 | function startAward() external
59 | ```
60 |
61 | **startAward\(\)** will:
62 |
63 | * Lock the pool: minting and redemption not allowed.
64 | * Request a random number from the RNG service
65 |
66 | Once the random number is available, a user can call:
67 |
68 | ```javascript
69 | function completeAward() external
70 | ```
71 |
72 | **completeAward\(\)** will:
73 |
74 | * Unlock the pool
75 | * Disburse the prize
76 | * Start the new prize
77 |
78 | Both startAward\(\) and completeAward\(\) have functions to check whether they can be called:
79 |
80 | ```javascript
81 | function canStartAward() external view returns (bool);
82 | ```
83 |
84 | and
85 |
86 | ```javascript
87 | function canCompleteAward() external view returns (bool);
88 | ```
89 |
90 | ## Reporting
91 |
92 | ### Current Prize
93 |
94 | To retrieve amount of accrued prize interest so far you may call:
95 |
96 | ```javascript
97 | function currentPrize() external returns (uint256);
98 | ```
99 |
100 | ### Estimating Prize
101 |
102 | To estimate what the prize will be you can call:
103 |
104 | ```javascript
105 | function estimatePrize() external returns (uint256);
106 | ```
107 |
108 | ### Time
109 |
110 | To retrieve when the current prize started:
111 |
112 | ```javascript
113 | function prizePeriodStartedAt() external view returns (uint256)
114 | ```
115 |
116 | To retrieve when the prize will end:
117 |
118 | ```javascript
119 | function prizePeriodEndAt() external view returns (uint256)
120 | ```
121 |
122 | ## Miscellaneous
123 |
124 | | Function | Description |
125 | | :--- | :--- |
126 | | function sponsorship\(\) returns \([ERC20](https://eips.ethereum.org/EIPS/eip-20)\) | Returns the address of the sponsorship token. |
127 | | function ticket\(\) returns \([Ticket](prize-pool/ticket.md)\) | Returns the address of the ticket token. |
128 |
129 |
130 |
131 |
--------------------------------------------------------------------------------
/tutorials/withdrawing-from-a-prize-pool.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: How to Withdraw Funds from a Prize Pool
3 | ---
4 |
5 | # Withdraw from a Prize Pool
6 |
7 | When it comes time to withdraw funds from a Prize Pool you can withdraw funds for yourself, or for others if they have given you an allowance.
8 |
9 | If the funds have [**matured**](https://docs.pooltogether.com/protocol/fairness#credit), then they can be withdrawn fully and instantly. If they haven't, then the funds will first enter a timelock before being unlocked and available to sweep back to the user. Alternatively, you can "pay off" the timelock and forfeit a small fee that goes to the prize.
10 |
11 | Let's see how these two approaches work.
12 |
13 | ## Withdrawing Your Funds With a Timelock
14 |
15 | Assuming you have previously [deposited into a Prize Pool](buying-tickets.md), let's see how to withdraw funds.
16 |
17 | The primary means of withdrawal is using a timelock. Most people will have accrued enough credit such that the timelock duration will be zero, but they still have to call the same function.
18 |
19 | **Solidity**
20 |
21 | ```javascript
22 | uint256 unlockTimestamp = PRIZE_POOL.withdrawWithTimelockFrom(
23 | fromAddress,
24 | amount,
25 | controlledToken
26 | );
27 | ```
28 |
29 | * **fromAddress** is the address from which we are withdrawing funds. This address must have a balance of the **controlledToken** greater than the given **amount**. This address must either be the caller, or the caller must an allowance greater than or equal to the amount for the given controlledToken.
30 | * **amount** is the amount of controlledTokens to burn in exchange for funds. Pool tokens are exchanged 1:1 with the underlying asset supplied to [depositTo\(\)](buying-tickets.md)
31 | * **controlledToken** is the address of the pool token you wish to burn.
32 |
33 | **JavaScript**
34 |
35 | ```javascript
36 | const ethers = require('ethers')
37 | const signer = ethers.Wallet.createRandom()
38 |
39 | const daiPrizePool = new ethers.Contract(
40 | DAI_PRIZE_POOL_ADDRESS,
41 | PRIZE_POOL_ABI,
42 | signer
43 | )
44 |
45 | const controlledTokens = await daiPrizePool.tokens();
46 |
47 | await daiPrizePool.withdrawWithTimelockFrom(
48 | signer._address,
49 | ethers.utils.parseEther('1'),
50 | controlledTokens[0]
51 | )
52 |
53 | const unlockTimestamp = await daiPrizePool.balanceAvailableAt(signer._address)
54 | ```
55 |
56 | ## Withdrawing Funds Instantly
57 |
58 | If the user doesn't have sufficient [credit](../protocol/prize-pool/fairness.md#credit) to cover the timelock they can "pay off" the timelock by contributing to the prize.
59 |
60 | **Solidity**
61 |
62 | ```javascript
63 | uint256 exitFee = PRIZE_POOL.calculateEarlyExitFee(
64 | fromAddress,
65 | controlledToken,
66 | amount
67 | );
68 |
69 | uint256 actualExitFee = PRIZE_POOL.withdrawInstantlyFrom(
70 | fromAddress,
71 | amount,
72 | controlledToken,
73 | exitFee
74 | );
75 | ```
76 |
77 | * **from** is the address to withdraw from. This must be the caller, or the caller must have receive prior approval via the controlled token.
78 | * **amount** is the amount of controlled token to burn.
79 | * **controlledToken** is the pool token the user wishes to burn in exchange for assets.
80 | * **maximumExitFee** allows the caller to declare the maximum fee that is taken from their withdrawal amount.
81 |
82 | This function returns the actual exit fee that was consumed. The exit fee is taken from the withdrawal amount. For example, if the user is withdrawing 100 Dai and the exit fee is 10 Dai, then they will burn 100 pool tokens and be transferred 90 Dai.
83 |
84 | **JavaScript**
85 |
86 | ```javascript
87 | const ethers = require('ethers')
88 | const signer = ethers.Wallet.createRandom()
89 |
90 | const daiPrizePool = new ethers.Contract(
91 | DAI_PRIZE_POOL_ADDRESS,
92 | PRIZE_POOL_ABI,
93 | signer
94 | )
95 |
96 | const controlledTokens = await daiPrizePool.tokens();
97 |
98 | const exitFee = await daiPrizePool.callStatic.calculateEarlyExitFee(
99 | controlledTokens[0],
100 | ethers.utils.parseEther('1')
101 | )
102 |
103 | await daiPrizePool.withdrawInstantlyFrom(
104 | signer._address,
105 | ethers.utils.parseEther('1'),
106 | controlledTokens[0],
107 | exitFee
108 | )
109 |
110 | ```
111 |
112 | ## Getting Approval
113 |
114 | Both methods of withdrawal allow users to withdraw on behalf of others, as long as they have sufficient ERC20 allowance for the user and controlled token in question.
115 |
116 | The funds will be transferred back to the original user, not to the caller.
117 |
118 |
--------------------------------------------------------------------------------
/tutorials/operate-a-prize-pool.md:
--------------------------------------------------------------------------------
1 | # 🎛️ Operate a Prize Pool
2 |
3 | Now that you've created a Prize Pool, it is time to learn what goes into operating a Prize Pool. Viewing details about any Prize Pool is made easy with the [PoolTogether Reference App](https://reference-app.pooltogether.com/), which displays all the relevant information about any Pool. An example Prize Pool on a testnet can be viewed [here](https://reference-app.pooltogether.com/pools/rinkeby/0x4706856FA8Bb747D50b4EF8547FE51Ab5Edc4Ac2/manage).
4 |
5 | ## Owner Privileges
6 |
7 | When a Prize Pool is created with the Builder, the address that sent the transaction is the owner of both the Prize Pool and default Prize Strategy. These permissions allow the owner to change certain parameters in both the Pool and Strategy contracts once they have been deployed.
8 |
9 | Owner privileges include, but are not limited to:
10 |
11 | * Managing Awards
12 | * Changing the number of winners
13 | * Updating fairness parameters
14 | * Switching to a Custom Prize Strategy
15 | * Transferring ownership to another address
16 |
17 | The [Reference App](https://reference-app.pooltogether.com) has an Admin dashboard which allows for easy access for managing the Prize Pool. Click manage pool and then select the Admin tab to view the different actions.
18 |
19 | 
20 |
21 | ## Awarding a Prize
22 |
23 | The default [Multiple Winners](../protocol/prize-strategy/multiple-winners.md) prize strategy awards prizes periodically; the prize can be awarded as soon as the prize period has elapsed. The prize is awarded into two phases:
24 |
25 | 1. **Start Award**: when the prize period has elapsed, anyone can execute the start award transaction. This will cause the prize strategy to make a request for a new random number from the RNG service. The **prize strategy** must have enough tokens to pay for the RNG request if payment is required.
26 | 2. **Complete Award**: when the RNG is ready with the random number, the complete award transaction can be executed by anyone. The prize strategy will use the random number to pick the winners, and start a new prize period.
27 |
28 | ## Awards
29 |
30 | Both the Compound Prize Pool and Stake Prize Pool will award the stake token as a prize if there is excess balance. Excess balance may be due to interest accruing, or from users leaving prematurely and paying the early exit fee.
31 |
32 | Prize Pools can also award any other ERC20 or ERC721 tokens as prizes. These other tokens must be whitelisted in the [Multiple Winners](../protocol/prize-strategy/multiple-winners.md) strategy in order to be awarded.
33 |
34 | * When an ERC20 is whitelisted, the Multiple Winners strategy will award the token as a prize if the **prize pool** has a non-zero balance.
35 | * When an ERC721 token is whitelisted, the Multiple Winners strategy will award the token as a prize to the **first** winner \(if there are multiple winners\).
36 |
37 | 
38 |
39 | ## Number of Winners
40 |
41 | The owner has the ability to increase or decrease the number of winners. The default behaviour of multiple winners differs between the Compound Prize Pool and the Stake Prize Pool:
42 |
43 | **Compound Prize Pool**
44 |
45 | * Any accrued stake tokens are distributed evenly among the winners
46 | * All other ERC20 and ERC721 tokens are given to the first winner
47 |
48 | **Stake Prize Pool**
49 |
50 | * Any accrued stake tokens are distributed evenly among the winners
51 | * All other ERC20 tokens are split evenly among the winners
52 | * All ERC721 tokens go to the first winner.
53 |
54 | 
55 |
56 | ## Fairness
57 |
58 | The early exit fee must be paid when a user withdraws from a Prize Pool. The fee is a percentage of the withdrawal amount that they must contribute to the prize. However, the fee will decay to zero over time so that users can withdraw without paying any fee.
59 |
60 | Here we can see the early exit fee is 1% and the decay time is 14 days. If a user deposits 100 Dai then immediately withdraws, they will need to contribute 1 Dai to the prize. However, if the user waits 14 days after depositing then they can withdraw their full amount.
61 |
62 | **Please view the** [**Fairness**](https://docs.pooltogether.com/protocol/prize-pool/fairness) **section of the documentation for more details.**
63 |
64 | 
65 |
66 |
--------------------------------------------------------------------------------
/protocol/prize-pool/fairness.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: How Prize Pools Ensure Fair Play
3 | ---
4 |
5 | # ⚖️ Fairness
6 |
7 | When users play a game they want it to be fair. In PoolTogether, this means that everyone has contributed the same amount of interest to prizes they are eligible to win. Interest accrues over time, so the Prize Pool needs to measure and enforce the time that funds are held. Without this mechanism, it would be very easy to game the system by depositing right before a prize, having a chance to win, and withdrawing right after.
8 |
9 | Prize Pools measure the duration of time funds are held by accruing **credit** for each user at the **credit rate**. The longer a user holds tokens, the more credit they accrue.
10 |
11 | Prize Pools enforce the duration of time funds are held by setting a **credit limit**. Once a credit limit is reached a user can withdraw instantly with no loss. If the credit limit has not been reached the user can either use a withdrawal **timelock** or pay an early exit contribution to the prize.
12 |
13 | ## Credit
14 |
15 | After a user deposits funds they begin to accrue credit according to the credit rate. The credit rate is expressed in tokens per second.
16 |
17 | For example: if the user deposits 100 DAI and the credit rate is 0.1, then they will have accrued 1 DAI in credit after 10 seconds. Note that they cannot withdraw the 1 DAI credit; it's simply a measure of their contribution.
18 |
19 | Users will accrue credit up until the **credit limit**. The credit limit is a fraction, so a users credit limit is that fraction of their entire balance. For example, if the user holds 100 DAI and the credit limit is 0.1, then they will accrue a maximum of 10 DAI in credit.
20 |
21 | Once a deposit has accrued maximum credit, it is considered **matured**.
22 |
23 | ## Timelock
24 |
25 | A deposit can be withdrawn instantly from the Prize Pool if it has matured. Otherwise, upon withdrawal the deposit will be timelocked until it has matured, at which point the funds can be swept back to the user by anyone.
26 |
27 | The timelock duration is calculated based on the spare credit the user has. The spare credit for a withdrawal is their credit balance _less the credit limit for their remaining balance of tokens_. For example: let's say a user has 100 DAI and is attempting to withdraw 10 DAI. They currently have 9 DAI in credit and the credit limit is 0.1. The user's spare credit is 9 - \(100 - 10\) \* 0.1 = 0 DAI. If the user was instead withdrawing 50 DAI, then they would have 9 - \(100 - 50\) \* 0.1 = 4 DAI in spare credit.
28 |
29 | The duration of the timelock is the time it takes for the withdrawal to mature less the spare credit. For example: if the withdrawal amount is 100 DAI, and the user has 5 DAI in spare credit, and the credit rate is 0.1, then the timelock will be \(\(100 \* 0.1\) - 5\) / 0.1 = 50 seconds. The spare credit is burned and the funds are placed in a timelock that can be swept after the duration has elapsed.
30 |
31 | ### Paying Off the Timelock
32 |
33 | It's possible for a user to withdraw their funds instantly. Instead of a timelock, the Prize Pool will capture the remaining contribution directly from the withdrawal amount. The user will receive the withdrawal amount less the remaining contribution. Their spare credit will be burned. We call this an **instant withdrawal.**
34 |
35 | ## What should the credit rate and credit limit for a pool be?
36 |
37 | In principal, we want the timelock to be as short as possible and most users should never encounter it. We are trying to prevent abuse of the system by a small subset of users while keeping the smoothest experience for the majority of users.
38 |
39 | At first glance the credit limit should simply be equal to the amount of interest a deposit would contribute over a prize period. But there are several factors that can change the cost / benefit balance for depositors, specifically:
40 |
41 | * Any subsidies to the prize \(whether through sponsored deposits or direct additions\)
42 | * Any rewards given to deposits through the token drips
43 | * Fluctuations in the yield rate
44 | * Total amount of outstanding tickets for a given prize
45 | * Gas fees of entering and exiting the pool
46 |
47 | To find the ideal credit limit it is best to estimate the **effective APR** a pool is offering.
48 |
49 | **Example**
50 |
51 | Assume a pool has a yield source that returns 5% APR. The pool awards prizes weekly, which means that each week approximately 5% / 52 = 0.096% accrues. A fair credit limit could be 0.1%: if the user decides to game the prize, they will need to contribute 0.1% of their deposit.
52 |
53 | However, we want users who have been in the pool since the beginning to not have to pay anything. Let's say we wish for users to accrue 0.1% credit per week, so that they can withdraw losslessly. The credit rate is applied per second and does not compound, so we can calculate the credit rate as the credit limit / seconds in a week, or 0.1% / 86400 = 0.0000011574074074074074.
54 |
55 | This means that users will need to stay in the pool for a week, otherwise they'll need to pay an early exit fee of 0.1%. Note, however, that this fee diminishes over time.
56 |
57 |
--------------------------------------------------------------------------------
/protocol/prize-strategy/multiple-winners.md:
--------------------------------------------------------------------------------
1 | # 🤑 Multiple Winners
2 |
3 | The Multiple Winners prize strategy periodically selects a predefined number of winners and awards to them an equal share of the prizes available in the Prize Pool.
4 |
5 | ## Initialization
6 |
7 | A Multiple Winners prize strategy is initialized with:
8 |
9 | **Prize Period Start:** the timestamp at which the prize period should start
10 |
11 | **Prize Period Seconds**: the duration of time between prizes
12 |
13 | **PrizePool Address**: the address of the [prize pool](../prize-pool/) that implements the pool functionality such as deposit and withdraw
14 |
15 | [**Ticket**](../tokens/ticket.md)**:** The interface to use to select winners
16 |
17 | \*\*\*\*[**Sponsorship**](../tokens/sponsorship.md)**:** The token that represents sponsorship
18 |
19 | \*\*\*\*[**Random Number Generator**](../random-number-generator/): used to generate random numbers for winner selection
20 |
21 | **Number of Winners**: the number of winners in a prize period. This can be later changed by the owner calling set number of winners.
22 |
23 | ## Strategy Settings
24 |
25 | ### Set Number of Winners
26 |
27 | The number of winners in a prize period can be set by calling:
28 |
29 | ```javascript
30 | function setNumberOfWinners(uint256 count)
31 | external onlyOwner requireAwardNotInProgress
32 | ```
33 |
34 | * Requires that the Award process is not in progress
35 | * `count` must be greater than 0
36 |
37 | ### View Number of Winners
38 |
39 | The number of winners setting can be viewed by calling:
40 |
41 | ```javascript
42 | function numberOfWinners() external view returns (uint256
43 | ```
44 |
45 | ### Set Split External ERC-20 Awards
46 |
47 | The `SplitExternalErc20Awards` flag can be set by calling:
48 |
49 | ```javascript
50 | function setSplitExternalErc20Awards(bool _splitExternalErc20Awards)
51 | external onlyOwner requireAwardNotInProgress
52 | ```
53 |
54 | This controls how externally added ERC-20's are distributed. Setting to `true` results in the ERC-20's paid out uniformly \(similar to the main prize\), while `false` does not pay out external ERC-20's for that award.
55 |
56 | ### Set Random Number Generation Service
57 |
58 | The [Random Number Generation](../random-number-generator/) Service can be set when the award process has not started by the Prize Pool owner by calling:
59 |
60 | ```javascript
61 | function setRngService(RNGInterface rngService)
62 | external onlyOwner requireAwardNotInProgress
63 | ```
64 |
65 | ### Set Random Number Generator Request Timeout
66 |
67 | The RNG request timeout parameter can be set \(in seconds\) when the award process has not started by the Prize Pool owner by calling:
68 |
69 | ```javascript
70 | function setRngRequestTimeout(uint32 _rngRequestTimeout)
71 | external onlyOwner requireAwardNotInProgress {
72 | ```
73 |
74 | ## Prize Period Information
75 |
76 | #### View if the Prize Period is Over
77 |
78 | To check if the prize period is finished call:
79 |
80 | ```javascript
81 | function isPrizePeriodOver() external view returns (bool)
82 | ```
83 |
84 | Returns `true` if the prize period is over, `false` otherwise.
85 |
86 | #### View when the Prize Period Finishes
87 |
88 | To check the unix time when the prize period ends call:
89 |
90 | ```javascript
91 | function prizePeriodEndAt() external view returns (uint256)
92 | ```
93 |
94 | #### View Estimate of Number of Blocks to Prize Block
95 |
96 | To estimate the remaining blocks until the prize given a number of seconds per block call `estimateRemainingBlocksToPrize` with `secondPerBlockMantissa` set to 15 seconds for Ethereum mainnet:
97 |
98 | ```javascript
99 | function estimateRemainingBlocksToPrize(uint256 secondsPerBlockMantissa) public
100 | view returns (uint256)
101 | ```
102 |
103 | #### View Prize Period Remaining Time \(in seconds\)
104 |
105 | To get the number of seconds remaining until the prize can be awarded call:
106 |
107 | ```javascript
108 | function prizePeriodRemainingSeconds() external view returns (uint256)
109 | ```
110 |
111 | #### View Next Prize Period Start Time
112 |
113 | To get the Unix timestamp of when the next prize period will start call `calculateNextPrizePeriodStartTime` with `currentTime` set to the current Unix time:
114 |
115 | ```javascript
116 | function calculateNextPrizePeriodStartTime(uint256 currentTime)
117 | external view returns (uint256)
118 | ```
119 |
120 | ## Award Process
121 |
122 | At the end of the prize period, anyone can begin the award process. This happens in two main stages - `startAward` and `completeAward`. `startAward` triggers the configured Random Number Generator request, which will take some blocks. `completeAward` can then be called, which selects the winners using the RNG result and pushes the tokens out to the winners.
123 |
124 | ### Start Award
125 |
126 | The award process can be started by calling `startAward`. This function starts the award process by starting the configured random number request. The prize period must have ended. The RNG-Request-Fee is expected to be held within this contract before calling this function.
127 |
128 | ```text
129 | function startAward() external requireCanStartAward
130 | ```
131 |
132 | Upon completion this function fires the following event:
133 |
134 | ```csharp
135 | event PrizePoolAwardStarted(
136 | address indexed operator,
137 | address indexed prizePool,
138 | uint32 indexed rngRequestId,
139 | uint32 rngLockBlock
140 | );
141 | ```
142 |
143 | ### Complete Award
144 |
145 | The award process can be finished by calling `completeAward`. The random number must have been requested and now available \(is can be checked by calling `isRngCompleted()`\).
146 |
147 | ```javascript
148 | function completeAward() external requireCanCompleteAward
149 | ```
150 |
151 | This function fires two events upon completion:
152 |
153 | ```csharp
154 | event PrizePoolAwarded(
155 | address indexed operator,
156 | uint256 randomNumber
157 | );
158 | ```
159 |
160 | Since Prize Pools are continuously rolling the next prize period is now open:
161 |
162 | ```csharp
163 | event PrizePoolOpened(
164 | address indexed operator,
165 | uint256 indexed prizePeriodStartedAt
166 | );
167 | ```
168 |
169 | ### Cancel Award
170 |
171 | This function can be called by anyone to unlock the tickets if the RNG has timed out:
172 |
173 | ```javascript
174 | function cancelAward() public
175 | ```
176 |
177 | This function will fire the event:
178 |
179 | ```csharp
180 | event PrizePoolAwardCancelled(
181 | address indexed operator,
182 | address indexed prizePool,
183 | uint32 indexed rngRequestId,
184 | uint32 rngLockBlock
185 | );
186 | ```
187 |
188 | ### Listeners
189 |
190 | A prize strategy can have both a [token listener](https://github.com/pooltogether/pooltogether-pool-contracts/blob/master/contracts/token/TokenListener.sol) and a periodic prize strategy listener in order execute code for certain callbacks \(event hooks\).
191 |
192 | #### Set Token Listener
193 |
194 | The token listener can be set by the prize pool owner when the award process is not in progress by calling `setTokenListener` with the address of the new `tokenList` :
195 |
196 | ```javascript
197 | function setTokenListener(TokenListenerInterface _tokenListener)
198 | external onlyOwner requireAwardNotInProgress
199 | ```
200 |
201 | #### Set Periodic Prize Strategy Listener
202 |
203 | The periodic prize strategy listener can be set by the prize pool owner when the award process is not in progress by calling `setPeriodicPrizeStrategyListener` with the address of the new `PeriodicPrizeStrategyListener`:
204 |
205 | ```javascript
206 | function setPeriodicPrizeStrategyListener(PeriodicPrizeStrategyListenerInterface _periodicPrizeStrategyListener)
207 | external onlyOwner requireAwardNotInProgress
208 | ```
209 |
210 | This function will ensure the Listener Interface is implementing using ERC-165 introspection, and upon completion fire the following event:
211 |
212 | ```csharp
213 | event PeriodicPrizeStrategyListenerSet(
214 | PeriodicPrizeStrategyListenerInterface indexed periodicPrizeStrategyListener
215 | );
216 | ```
217 |
218 | ### External ERC20 and ERC721 Awards
219 |
220 | External awards can be added to the pool. This is particularly useful in the case of the stake pool. Although still possible for either the token listener or the owner to manually add or remove ERC-20's and ERC-721's, it is recommended to add a single [LootBox](../lootbox.md) per prize period and direct the external awards to this LootBox address.
221 |
222 | The pool owner or the token listener can add/remove ERC721's by calling:
223 |
224 | ```javascript
225 | function addExternalErc721Award(IERC721Upgradeable _externalErc721,
226 | uint256[] calldata _tokenIds)
227 | external onlyOwnerOrListener requireAwardNotInProgress
228 | ```
229 |
230 | ```javascript
231 | function removeExternalErc721Award(
232 | IERC721Upgradeable _externalErc721,
233 | IERC721Upgradeable _prevExternalErc721)
234 | external onlyOwner requireAwardNotInProgress
235 | ```
236 |
237 | The pool owner or the token listener can add/remove ERC20's by calling:
238 |
239 | ```javascript
240 | function addExternalErc20Awards(IERC20Upgradeable[] calldata _externalErc20s)
241 | external onlyOwnerOrListener requireAwardNotInProgress
242 | ```
243 |
244 | ```javascript
245 | function removeExternalErc20Award(
246 | IERC20Upgradeable _externalErc20,
247 | IERC20Upgradeable _prevExternalErc20)
248 | external onlyOwner requireAwardNotInProgress
249 | ```
250 |
251 | Corresponding events are fired for each ERC type added or removed:
252 |
253 | ```csharp
254 | event ExternalErc721AwardAdded(
255 | IERC721Upgradeable indexed externalErc721,
256 | uint256[] tokenIds
257 | );
258 |
259 | event ExternalErc20AwardAdded(
260 | IERC20Upgradeable indexed externalErc20
261 | );
262 |
263 | event ExternalErc721AwardRemoved(
264 | IERC721Upgradeable indexed externalErc721Award
265 | );
266 |
267 | event ExternalErc20AwardRemoved(
268 | IERC20Upgradeable indexed externalErc20Award
269 | );
270 | ```
271 |
272 |
--------------------------------------------------------------------------------
/networks.md:
--------------------------------------------------------------------------------
1 | # 📡 Networks
2 |
3 | _This document was generated_ [_automatically_](https://github.com/pooltogether/generate-networks-doc)
4 |
5 | ## Mainnet
6 |
7 | ### PoolTogether Pools & Supporting Contracts
8 |
9 | **@pooltogether/current-pool-data ^3.1.5** [**npm**](https://www.npmjs.com/package/@pooltogether/current-pool-data)
10 |
11 | | Contract | Address |
12 | | -------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
13 | | Dai Prize Pool | [0xEBfb47A7ad0FD6e57323C8A42B2E5A6a4F68fc1a](https://etherscan.io/address/0xEBfb47A7ad0FD6e57323C8A42B2E5A6a4F68fc1a) |
14 | | Dai Prize Strategy | [0x178969A87a78597d303C47198c66F68E8be67Dc2](https://etherscan.io/address/0x178969A87a78597d303C47198c66F68E8be67Dc2) |
15 | | UNI Prize Pool | [0x0650d780292142835F6ac58dd8E2a336e87b4393](https://etherscan.io/address/0x0650d780292142835F6ac58dd8E2a336e87b4393) |
16 | | UNI Prize Strategy | [0xe8726B85236a489a8E84C56c95790d07a368f913](https://etherscan.io/address/0xe8726B85236a489a8E84C56c95790d07a368f913) |
17 | | USDC Prize Pool | [0xde9ec95d7708b8319ccca4b8bc92c0a3b70bf416](https://etherscan.io/address/0xde9ec95d7708b8319ccca4b8bc92c0a3b70bf416) |
18 | | USDC Prize Strategy | [0x3d9946190907ada8b70381b25c71eb9adf5f9b7b](https://etherscan.io/address/0x3d9946190907ada8b70381b25c71eb9adf5f9b7b) |
19 | | Loot Box ERC721 | [0x4d695c615a7AACf2d7b9C481B66045BB2457Dfde](https://etherscan.io/address/0x4d695c615a7AACf2d7b9C481B66045BB2457Dfde) |
20 | | Loot Box Prize Strategy Listener | [0xfe7205DF55BA42c8801e44B55BF05F06cCe8565E](https://etherscan.io/address/0xfe7205DF55BA42c8801e44B55BF05F06cCe8565E) |
21 |
22 | ### RNG Contracts
23 |
24 | **@pooltogether/pooltogether-rng-contracts ^1.0.0** [**npm**](https://www.npmjs.com/package/@pooltogether/pooltogether-rng-contracts)
25 |
26 | | Contract | Address | Artifact |
27 | | ----------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
28 | | [RNGBlockhash](https://github.com/pooltogether/pooltogether-rng-contracts/tree/master/contracts/RNGBlockhash.sol) | [0xb1D89477d1b505C261bab6e73f08fA834544CD21](https://etherscan.io/address/0xb1D89477d1b505C261bab6e73f08fA834544CD21) | [Artifact](https://github.com/pooltogether/pooltogether-rng-contracts/tree/master/deployments/mainnet/RNGBlockhash.json) |
29 | | [RNGChainlink](https://github.com/pooltogether/pooltogether-rng-contracts/tree/master/contracts/RNGChainlink.sol) | [0xB2DC5571f477b1C5b36509a71013BFedD9Cc492F](https://etherscan.io/address/0xB2DC5571f477b1C5b36509a71013BFedD9Cc492F) | [Artifact](https://github.com/pooltogether/pooltogether-rng-contracts/tree/master/deployments/mainnet/RNGChainlink.json) |
30 |
31 | ### Loot Box Contracts
32 |
33 | **@pooltogether/loot-box ^1.0.0** [**npm**](https://www.npmjs.com/package/@pooltogether/loot-box)
34 |
35 | | Contract | Address | Artifact |
36 | | ------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
37 | | [ERC721ControlledFactory](https://github.com/pooltogether/loot-box/tree/main/contracts/ERC721ControlledFactory.sol) | [0x4E869b3A0978fA61DAbd7Da8F9B272AADc745Fb3](https://etherscan.io/address/0x4E869b3A0978fA61DAbd7Da8F9B272AADc745Fb3) | [Artifact](https://github.com/pooltogether/loot-box/tree/main/deployments/mainnet/ERC721ControlledFactory.json) |
38 | | [LootBoxController](https://github.com/pooltogether/loot-box/tree/main/contracts/LootBoxController.sol) | [0x2c2a966b7F5448A36EC9f896088DfB99B21d8A24](https://etherscan.io/address/0x2c2a966b7F5448A36EC9f896088DfB99B21d8A24) | [Artifact](https://github.com/pooltogether/loot-box/tree/main/deployments/mainnet/LootBoxController.json) |
39 | | [LootBoxPrizeStrategyListenerFactory](https://github.com/pooltogether/loot-box/tree/main/contracts/LootBoxPrizeStrategyListenerFactory.sol) | [0x25e6a78D93D2935A638fDbd684e7b39565d0B7eA](https://etherscan.io/address/0x25e6a78D93D2935A638fDbd684e7b39565d0B7eA) | [Artifact](https://github.com/pooltogether/loot-box/tree/main/deployments/mainnet/LootBoxPrizeStrategyListenerFactory.json) |
40 |
41 | ### V2-to-V3 Migration Contract
42 |
43 | **@pooltogether/migrate-v3 ^0.1.3** [**Github**](https://github.com/pooltogether/pooltogether-migrate-v3)
44 |
45 | | Contract | Address | Artifact |
46 | | ---------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
47 | | [MigrateV2ToV3](https://github.com/pooltogether/pooltogether-migrate-v3/tree/master/contracts/MigrateV2ToV3.sol) | [0x801B4872a635dCCc7E679eEaf04bEf08E562972a](https://etherscan.io/address/0x801B4872a635dCCc7E679eEaf04bEf08E562972a) | [Artifact](https://github.com/pooltogether/pooltogether-migrate-v3/tree/master/deployments/mainnet/MigrateV2ToV3.json) |
48 |
49 | ## Rinkeby
50 |
51 | ### PoolTogether Pools & Supporting Contracts
52 |
53 | **@pooltogether/current-pool-data ^3.1.5** [**npm**](https://www.npmjs.com/package/@pooltogether/current-pool-data)
54 |
55 | | Contract | Address |
56 | | ------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
57 | | Dai Prize Pool | [0x4706856FA8Bb747D50b4EF8547FE51Ab5Edc4Ac2](https://rinkeby.etherscan.io/address/0x4706856FA8Bb747D50b4EF8547FE51Ab5Edc4Ac2) |
58 | | Dai Prize Strategy | [0x5E0A6d336667EACE5D1b33279B50055604c3E329](https://rinkeby.etherscan.io/address/0x5E0A6d336667EACE5D1b33279B50055604c3E329) |
59 | | USDC Prize Pool | [0xde5275536231eCa2Dd506B9ccD73C028e16a9a32](https://rinkeby.etherscan.io/address/0xde5275536231eCa2Dd506B9ccD73C028e16a9a32) |
60 | | USDC Prize Strategy | [0x1b92BC2F339ef25161711e4EafC31999C005aF21](https://rinkeby.etherscan.io/address/0x1b92BC2F339ef25161711e4EafC31999C005aF21) |
61 | | BAT Prize Pool | [0xab068F220E10eEd899b54F1113dE7E354c9A8eB7](https://rinkeby.etherscan.io/address/0xab068F220E10eEd899b54F1113dE7E354c9A8eB7) |
62 | | BAT Prize Strategy | [0x41CF0758b7Cc2394b1C2dfF6133FEbb0Ef317C3b](https://rinkeby.etherscan.io/address/0x41CF0758b7Cc2394b1C2dfF6133FEbb0Ef317C3b) |
63 | | Loot Box ERC721 | [0xfbC6677806253dB9739d0F6CBD89b9e7Ed4A5c66](https://rinkeby.etherscan.io/address/0xfbC6677806253dB9739d0F6CBD89b9e7Ed4A5c66) |
64 |
65 | ### Core Contracts
66 |
67 | **@pooltogether/pooltogether-contracts ^3.1.0** [**npm**](https://www.npmjs.com/package/@pooltogether/pooltogether-contracts)
68 |
69 | | Contract | Address | Artifact |
70 | | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
71 | | [CompoundPrizePoolBuilder](https://github.com/pooltogether/pooltogether-pool-contracts/tree/version-3/contracts/builders/CompoundPrizePoolBuilder.sol) | [0xA8F32475438733B974CD4F19Ba8f97484EeB95a3](https://rinkeby.etherscan.io/address/0xA8F32475438733B974CD4F19Ba8f97484EeB95a3) | [Artifact](https://github.com/pooltogether/pooltogether-pool-contracts/tree/version-3/deployments/rinkeby/CompoundPrizePoolBuilder.json) |
72 | | [Comptroller](https://github.com/pooltogether/pooltogether-pool-contracts/tree/version-3/contracts/comptroller/Comptroller.sol) | [0xaF00636E7D943a62CCb87E8153c1C97bF657F11D](https://rinkeby.etherscan.io/address/0xaF00636E7D943a62CCb87E8153c1C97bF657F11D) | [Artifact](https://github.com/pooltogether/pooltogether-pool-contracts/tree/version-3/deployments/rinkeby/Comptroller.json) |
73 | | [ControlledTokenBuilder](https://github.com/pooltogether/pooltogether-pool-contracts/tree/version-3/contracts/builders/ControlledTokenBuilder.sol) | [0x239fC7c69Ba8079ebEC07156F13a6d78d234Fa6B](https://rinkeby.etherscan.io/address/0x239fC7c69Ba8079ebEC07156F13a6d78d234Fa6B) | [Artifact](https://github.com/pooltogether/pooltogether-pool-contracts/tree/version-3/deployments/rinkeby/ControlledTokenBuilder.json) |
74 | | [MultipleWinnersBuilder](https://github.com/pooltogether/pooltogether-pool-contracts/tree/version-3/contracts/builders/MultipleWinnersBuilder.sol) | [0x32e8D4c9d1B711BC958d0Ce8D14b41F77Bb03a64](https://rinkeby.etherscan.io/address/0x32e8D4c9d1B711BC958d0Ce8D14b41F77Bb03a64) | [Artifact](https://github.com/pooltogether/pooltogether-pool-contracts/tree/version-3/deployments/rinkeby/MultipleWinnersBuilder.json) |
75 | | [PermitAndDepositDai](https://github.com/pooltogether/pooltogether-pool-contracts/tree/version-3/contracts/permit/PermitAndDepositDai.sol) | [0x80768c51cDEd011B64A24Ba91b6d4471bB3Da150](https://rinkeby.etherscan.io/address/0x80768c51cDEd011B64A24Ba91b6d4471bB3Da150) | [Artifact](https://github.com/pooltogether/pooltogether-pool-contracts/tree/version-3/deployments/rinkeby/PermitAndDepositDai.json) |
76 | | [PoolWithMultipleWinnersBuilder](https://github.com/pooltogether/pooltogether-pool-contracts/tree/version-3/contracts/builders/PoolWithMultipleWinnersBuilder.sol) | [0x47a5ABfAcDebf5af312B034B3b748935A0259136](https://rinkeby.etherscan.io/address/0x47a5ABfAcDebf5af312B034B3b748935A0259136) | [Artifact](https://github.com/pooltogether/pooltogether-pool-contracts/tree/version-3/deployments/rinkeby/PoolWithMultipleWinnersBuilder.json) |
77 | | [Reserve](https://github.com/pooltogether/pooltogether-pool-contracts/tree/version-3/contracts/reserve/Reserve.sol) | [0x10f61a36e1327036E5E416D52ff0f4b5c9EfAAA3](https://rinkeby.etherscan.io/address/0x10f61a36e1327036E5E416D52ff0f4b5c9EfAAA3) | [Artifact](https://github.com/pooltogether/pooltogether-pool-contracts/tree/version-3/deployments/rinkeby/Reserve.json) |
78 | | ReserveRegistry | [0xAD1C620137FA76f520f9a39daAcD7B008D7d2F2D](https://rinkeby.etherscan.io/address/0xAD1C620137FA76f520f9a39daAcD7B008D7d2F2D) | [Artifact](https://github.com/pooltogether/pooltogether-pool-contracts/tree/version-3/deployments/rinkeby/ReserveRegistry.json) |
79 | | [StakePrizePoolBuilder](https://github.com/pooltogether/pooltogether-pool-contracts/tree/version-3/contracts/builders/StakePrizePoolBuilder.sol) | [0xdd4d117723C257CEe402285D3aCF218E9A8236E1](https://rinkeby.etherscan.io/address/0xdd4d117723C257CEe402285D3aCF218E9A8236E1) | [Artifact](https://github.com/pooltogether/pooltogether-pool-contracts/tree/version-3/deployments/rinkeby/StakePrizePoolBuilder.json) |
80 | | [VaultPrizePoolBuilder](https://github.com/pooltogether/pooltogether-pool-contracts/tree/version-3/contracts/builders/VaultPrizePoolBuilder.sol) | [0xd89a09084555a7D0ABe7B111b1f78DFEdDd638Be](https://rinkeby.etherscan.io/address/0xd89a09084555a7D0ABe7B111b1f78DFEdDd638Be) | [Artifact](https://github.com/pooltogether/pooltogether-pool-contracts/tree/version-3/deployments/rinkeby/VaultPrizePoolBuilder.json) |
81 |
82 | ### RNG Contracts
83 |
84 | **@pooltogether/pooltogether-rng-contracts ^1.0.0** [**npm**](https://www.npmjs.com/package/@pooltogether/pooltogether-rng-contracts)
85 |
86 | | Contract | Address | Artifact |
87 | | ----------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
88 | | [RNGBlockhash](https://github.com/pooltogether/pooltogether-rng-contracts/tree/master/contracts/RNGBlockhash.sol) | [0xA932e74d5263A754Ea04432E5c53658434b0484B](https://rinkeby.etherscan.io/address/0xA932e74d5263A754Ea04432E5c53658434b0484B) | [Artifact](https://github.com/pooltogether/pooltogether-rng-contracts/tree/master/deployments/rinkeby/RNGBlockhash.json) |
89 | | [RNGChainlink](https://github.com/pooltogether/pooltogether-rng-contracts/tree/master/contracts/RNGChainlink.sol) | [0x11D94431718934868C4339aFc5ea27585F46C99A](https://rinkeby.etherscan.io/address/0x11D94431718934868C4339aFc5ea27585F46C99A) | [Artifact](https://github.com/pooltogether/pooltogether-rng-contracts/tree/master/deployments/rinkeby/RNGChainlink.json) |
90 |
91 | ### Loot Box Contracts
92 |
93 | **@pooltogether/loot-box ^1.0.0** [**npm**](https://www.npmjs.com/package/@pooltogether/loot-box)
94 |
95 | | Contract | Address | Artifact |
96 | | ------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
97 | | [ERC721ControlledFactory](https://github.com/pooltogether/loot-box/tree/main/contracts/ERC721ControlledFactory.sol) | [0x1D90F79a8515F63881075Ec2C212e18272aD9E38](https://rinkeby.etherscan.io/address/0x1D90F79a8515F63881075Ec2C212e18272aD9E38) | [Artifact](https://github.com/pooltogether/loot-box/tree/main/deployments/rinkeby/ERC721ControlledFactory.json) |
98 | | [LootBoxController](https://github.com/pooltogether/loot-box/tree/main/contracts/LootBoxController.sol) | [0xb1EAc75da9bc31B078742C5AF9EDe62EFE31299D](https://rinkeby.etherscan.io/address/0xb1EAc75da9bc31B078742C5AF9EDe62EFE31299D) | [Artifact](https://github.com/pooltogether/loot-box/tree/main/deployments/rinkeby/LootBoxController.json) |
99 | | [LootBoxPrizeStrategyListenerFactory](https://github.com/pooltogether/loot-box/tree/main/contracts/LootBoxPrizeStrategyListenerFactory.sol) | [0xadB4D93D84b18b5D82063aCf58b21587c92fdfb5](https://rinkeby.etherscan.io/address/0xadB4D93D84b18b5D82063aCf58b21587c92fdfb5) | [Artifact](https://github.com/pooltogether/loot-box/tree/main/deployments/rinkeby/LootBoxPrizeStrategyListenerFactory.json) |
100 |
--------------------------------------------------------------------------------
/protocol/prize-pool/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: Pool deposits and award accrued interest periodically as a prize
3 | ---
4 |
5 | # 🏆 Prize Pools
6 |
7 | ## Introduction
8 |
9 | Prize Pools allow funds to be pooled together into a no-loss yield source, such as Compound, and have the yield safely exposed to a separate Prize Strategy. They are the primary way through which users interact with PoolTogether prize games.
10 |
11 | Prize Pools provide controls to the owner so that participation can be made fair. See [Fairness](https://app.gitbook.com/s/-M58QPye9-PujrSjSWqv-887967055/protocol/fairness.md) for more information.
12 |
13 | There is a different type of prize pool for each yield source. For example, if you wish to use Compound you will use the Compound Prize Pool.
14 |
15 | All Prize Pools share the functionality below.
16 |
17 | ## Owner
18 |
19 | When a Prize Pool is created, the creator is set as the pool's "owner". The owner is able to:
20 |
21 | * Add additional pool tokens
22 | * Change the Prize Strategy
23 | * Set the [credit rate and credit limit](https://app.gitbook.com/s/-M58QPye9-PujrSjSWqv-887967055/protocol/fairness.md#credit)
24 | * Shutdown the prize pool
25 | * Transfer ownership
26 | * Renounce ownership
27 |
28 | **The prize pool is not upgradeable and therefore the owner can never seize the funds deposited into the prize pool**
29 |
30 | ## Limits
31 |
32 | When a Prize Pool is created it is initialized with some hard-coded limits to protect users. See [Fairness](https://app.gitbook.com/s/-M58QPye9-PujrSjSWqv-887967055/protocol/fairness.md) for more details.
33 |
34 | ### **Maximum Timelock Duration**
35 |
36 | The maximum timelock duration ensures that a user has to wait at most X amount of time to withdraw their funds loss-lessly. If the owner of a pool sets the credit rate to be way too low, this limit ensures users will still be able to withdraw.
37 |
38 | If using the Single Random Winner Prize Strategy, it would make sense to set the maximum timelock duration to 2x the prize period. That way the owner has some flexibility when adjusting the credit limit and credit rate.
39 |
40 | ### **Maximum Credit Limit**
41 |
42 | The maximum credit limit ensures that the credit limit cannot be set higher than this number. This prevents the owner of the Prize Pool from capturing \*all\* of a user's deposit at withdrawal time.
43 |
44 | ### **Maximum Liquidity Limit**
45 |
46 | The maximum liquidity limit allows the PrizePool owner to set a cap on the amount of liquidity the pool can hold. This can be set by calling:
47 |
48 | ```javascript
49 | function setLiquidityCap(uint256 _liquidityCap) external override onlyOwner
50 | ```
51 |
52 | ## Token Model
53 |
54 | A Prize Pool accepts a single type of ERC20 token for deposits. This token depends on the implementation: for a Compound Prize Pool bound to cDai it will be Dai, for a yEarn yUSDC vault it will be USDC. This is the underlying **asset** of the Prize Pool.
55 |
56 | Prize Pools use **Controlled Tokens** for their internal accounting. These tokens are minted when depositing or awarding prizes. Controlled Tokens are burned when users withdraw. They are exchanged at a ratio of 1:1 to the asset.
57 |
58 | The tokens associated with a PrizePool can be seen by calling:
59 |
60 | ```javascript
61 | function tokens() external override view returns (address[] memory)
62 | ```
63 |
64 | ### Controlled Tokens
65 |
66 | A Controlled Token is a standard ERC20 that is bound to a **Token Controller**.
67 |
68 | The Token Controller has the privileged ability to mint and burn tokens on user's behalf, and has a callback that listens for token transfers. Controlled Tokens are expected to trigger this callback on any mint, burns or transfers.
69 |
70 | The Prize Pool must be the Token Controller for the controlled tokens that it is initialized with at construction.
71 |
72 | The default [Compound Prize Pool Builder](https://app.gitbook.com/s/-M58QPye9-PujrSjSWqv-887967055/builders/) creates a Ticket controlled token and a [Sponsorship](../tokens/sponsorship.md) controlled token.
73 |
74 | A Controlled Token can added by the PrizePool owner by calling:
75 |
76 | ```javascript
77 | function addControlledToken(ControlledTokenInterface _controlledToken)
78 | external override onlyOwner
79 | ```
80 |
81 | ### Minting
82 |
83 | When a user deposits into a Prize Pool they must request what type of controlled token they receive in exchange. This token will be minted to them at an exchange rate of 1:1 for the asset.
84 |
85 | ### Burning
86 |
87 | When a user wishes to withdraw from a Prize Pool they must burn controlled tokens.
88 |
89 | ## Depositing
90 |
91 | Users can deposit into the Prize Pool using the **depositTo** function. A user is instantly minted tokens upon deposit.
92 |
93 | ```javascript
94 | function depositTo(
95 | address to,
96 | uint256 amount,
97 | address controlledToken,
98 | address referrer
99 | ) external;
100 | ```
101 |
102 | | Parameter | Description |
103 | | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
104 | | to | The address to whom the controlled tokens should be minted |
105 | | amount | The amount of the underlying asset the user wishes to deposit. The Prize Pool contract should have been pre-approved by the caller to transfer the underlying ERC20 tokens. |
106 | | controlledToken | The address of the token that they wish to mint. For our default Prize Strategy this will either be the Ticket address or the Sponsorship address. Those addresses can be looked up on the Prize Strategy. |
107 | | referrer | The address that should receive [referral awards](https://app.gitbook.com/s/governance/untitled.md#referral-volume-drips), if any. |
108 |
109 | Depositing fires the event:
110 |
111 | ```javascript
112 | event Deposited(
113 | address indexed operator,
114 | address indexed to,
115 | address indexed token,
116 | uint256 amount
117 | );
118 | ```
119 |
120 | | Event Data | Description |
121 | | ---------- | --------------------------------------------------------------------------------------------- |
122 | | operator | The caller that made the deposit |
123 | | to | The address that received the minted tokens |
124 | | token | The address of the controlled token that was minted |
125 | | amount | The amount of both the underlying asset that was transferred and the tokens that were minted. |
126 |
127 | ### Depositing Using Timelocked Funds
128 |
129 | If a user wishes to re-deposit their timelocked funds, they can do so using this function:
130 |
131 | ```javascript
132 | function timelockDepositTo(
133 | address to,
134 | uint256 amount,
135 | address controlledToken
136 | ) external;
137 | ```
138 |
139 | | Parameter | Description |
140 | | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
141 | | to | The address to whom the controlled tokens should be minted |
142 | | amount | The amount of the underlying asset the user wishes to deposit. The Prize Pool contract should have been pre-approved by the caller to transfer the underlying ERC20 tokens. |
143 | | controlledToken | The address of the token that they wish to mint. For our default Prize Strategy this will either be the Ticket address or the Sponsorship address. Those addresses can be looked up on the Prize Strategy. |
144 |
145 | ## Withdrawing
146 |
147 | When a user withdraws they may need to contribute to the prize according to the [fairness rules](https://app.gitbook.com/s/-M58QPye9-PujrSjSWqv-887967055/protocol/fairness.md). They may either cover the contribution by time-locking their funds, or cover the contribution explicitly using funds.
148 |
149 | ### **Withdraw with Timelock**
150 |
151 | Funds can be withdrawn losslessly by time-locking the funds. The withdrawal amount will be unlocked at a later date at which point the funds can be swept back to the user. The timelock duration is calculated based on the users accrued credit, the credit rate, and the fairness fee.
152 |
153 | If the user has sufficient credit, the unlockTimestamp may be "now" and the funds are instantly swept to the `from` address.
154 |
155 | Tip: You can call this function in a constant way to see when the users funds will be unlocked.
156 |
157 | To start a lossless withdrawal a user may call:
158 |
159 | ```javascript
160 | function withdrawWithTimelockFrom(
161 | address from,
162 | uint256 amount,
163 | address controlledToken
164 | ) external returns (uint256 unlockTimestamp);
165 | ```
166 |
167 | | Parameter Name | Parameter Description |
168 | | --------------- | -------------------------------------------------------------------------------------------------------------------------------- |
169 | | from | The user from whom to withdraw. This means you may withdraw on another user's behalf if they have given you an ERC20 allowance. |
170 | | amount | The amount of collateral to withdraw. |
171 | | controlledToken | The type of controlled token to withdraw. |
172 |
173 | ### Checking Timelock Balances
174 |
175 | To see how many funds have been timelocked for a `user` call:
176 |
177 | ```javascript
178 | function timelockBalanceOf(address user) external view returns (uint256)
179 | ```
180 |
181 | After funds have been time-locked, you can see at what timestamp they'll be available:
182 |
183 | ```javascript
184 | function timelockBalanceAvailableAt(address user) external view returns (uint256)
185 | ```
186 |
187 | ### Checking Timelock Duration
188 |
189 | To calculate a timelocked withdrawal duration and credit consumption call:
190 |
191 | ```javascript
192 | function calculateTimelockDuration(address from, address controlledToken, uint256 amount)
193 | external override returns (uint256 durationSeconds,uint256 burnedCredit)
194 | ```
195 |
196 | | Parameter Name | Description |
197 | | --------------- | ----------------------------------------- |
198 | | from | The user who is withdrawing. |
199 | | amount | The amount the user is withdrawing. |
200 | | controlledToken | The type of controlled token to withdraw. |
201 |
202 | **returns**:
203 |
204 | | Returned Parameter Name | Description |
205 | | ----------------------- | ----------------------------------------- |
206 | | `durationSeconds` | The duration of the timelock in seconds |
207 | | `burned` | The amount of credit that would be burned |
208 |
209 | ### Estimating Credit Accrual Time
210 |
211 | Similarly it is also possible to calculate how long a user must keep their funds in the pool:
212 |
213 | ```javascript
214 | function estimateCreditAccrualTime(address _controlledToken,
215 | uint256 _principal,
216 | uint256 _interest)
217 | external override view returns (uint256 durationSeconds)
218 | ```
219 |
220 | | Parameter Name | Parameter Description |
221 | | ----------------- | --------------------------------------------------- |
222 | | \_controlledToken | The type of controlled token. |
223 | | \_principal | The principal amount on which interest is accruing. |
224 | | \_interest | The amount of interest that must accrue. |
225 |
226 | ### Sweeping Timelocked Funds
227 |
228 | When a user's withdrawal timelocks have ended, the funds may be swept to their wallets:
229 |
230 | ```javascript
231 | function sweepTimelockBalances(
232 | address[] memory users
233 | ) external returns (uint256 totalWithdrawal);
234 | ```
235 |
236 | The function accepts an array of addresses and will attempt to sweep the time-locked funds for each one. The funds will be transferred back to the users wallets.
237 |
238 | ### Withdraw Instantly
239 |
240 | If a user would like their tickets right away, they may pay an early exit fee to the prize. The early exit fee is determined by the [Prize Strategy](https://app.gitbook.com/s/-M58QPye9-PujrSjSWqv-887967055/prize-strategy/).
241 |
242 | The instant withdrawal function returns the amount of the withdrawal that was retained as payment. This means you can call this function in a constant way to check to see what the exit fee will be. When it comes time to run the tx, that exit fee can be passed as the `maximumExitFee` to ensure it doesn't exceed the expected limit.
243 |
244 | ```javascript
245 | function withdrawInstantlyFrom(
246 | address from,
247 | uint256 amount,
248 | address controlledToken,
249 | uint256 maximumExitFee
250 | )
251 | external
252 | returns (uint256 exitFee);
253 | ```
254 |
255 | | Parameter Name | Parameter Description |
256 | | --------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
257 | | from | The address to withdraw from. This means you can withdraw on another user's behalf if you have an allowance for the controlled token. |
258 | | amount | The amount to withdraw |
259 | | controlledToken | The controlled token to withdraw from |
260 | | maximumExitFee | The maximum early exit fee the caller is willing to pay. This prevents the Prize Strategy from changing the fee on-the-fly. |
261 |
262 | This early exit fee can also be calculated by calling:
263 |
264 | ```javascript
265 | function calculateEarlyExitFee(address from, address controlledToken, uint256 amount)
266 | external override returns (uint256 exitFee, uint256 burnedCredit)
267 | ```
268 |
269 | | Parameter Name | Parameter Description |
270 | | --------------- | ------------------------------------- |
271 | | from | The address to withdraw from |
272 | | controlledToken | The controlled token to withdraw from |
273 | | amount | The amount to withdraw |
274 |
275 | returns the `exitFee` that would be paid along with the credit that would be burned (`burnedCredit`).
276 |
277 | ## Awarding
278 |
279 | Only the Prize Strategy can call the award functions. These functions allow prizes to be disbursed to users.
280 |
281 | ### Awarding Yield
282 |
283 | Yield that accrues in the Prize Pool can be awarded by the Prize Strategy. The yield must first be **captured** and then it can be **awarded.**
284 |
285 | To capture the yield the prize strategy can call the `captureAwardBalance` function:
286 |
287 | ```javascript
288 | function captureAwardBalance() external onlyPrizeStrategy returns (uint256);
289 | ```
290 |
291 | This function will:
292 |
293 | * add the current yield balance to the available award balance
294 | * capture a portion for the reserve
295 | * return the total available award balance.
296 |
297 | To award the captured yield to an address, the Prize strategy uses the `award` function. The yield must be awarded as one of the controlled tokens configured in the Prize Pool.
298 |
299 | ```javascript
300 | function award(
301 | address to,
302 | uint256 amount,
303 | address controlledToken
304 | ) external onlyPrizeStrategy;
305 | ```
306 |
307 | | Parameter Name | Parameter Description |
308 | | --------------- | ---------------------------------------------- |
309 | | to | The address to receive the newly minted tokens |
310 | | amount | The amount of tokens to mint |
311 | | controlledToken | The type of token to mint |
312 |
313 | ### Awarding ERC20s
314 |
315 | The Prize Strategy can award ERC20 tokens that are held by the Prize Pool.
316 |
317 | ```javascript
318 | function awardExternalERC20(
319 | address to,
320 | address externalToken,
321 | uint256 amount
322 | ) external onlyPrizeStrategy;
323 | ```
324 |
325 | However, some tokens are be blacklisted if they need to be held to generate yield (i.e. Compound cTokens).
326 |
327 | | Parameter Name | Parameter Description |
328 | | -------------- | ----------------------------------- |
329 | | to | The address to receive the transfer |
330 | | externalToken | The ERC20 to transfer |
331 | | amount | The amount of tokens to transfer |
332 |
333 | ### Awarding ERC721s (NFTs)
334 |
335 | The Prize Strategy can award ERC721 tokens that are held by the Prize Pool.
336 |
337 | ```javascript
338 | function awardExternalERC721(
339 | address to,
340 | address externalToken,
341 | uint256[] calldata tokenIds
342 | )
343 | external
344 | onlyPrizeStrategy;
345 | ```
346 |
347 | | Parameter Name | Parameter Description |
348 | | -------------- | ------------------------------- |
349 | | to | The address to receive the NFTs |
350 | | externalToken | The ERC721 contract address |
351 | | tokenIds | The NFT token ids to transfer. |
352 |
353 | ## Credit
354 |
355 | Credit accrues differently for each of the Prize Pool's controlled tokens, so each token will have its own credit rate and credit limit.
356 |
357 | ### Credit Balance
358 |
359 | To get a users credit balance for a controlled token:
360 |
361 | ```javascript
362 | function balanceOfCredit(
363 | address user,
364 | address controlledToken
365 | ) external returns (uint256);
366 | ```
367 |
368 | | Parameter Name | Parameter Description |
369 | | --------------- | ------------------------------------------------------- |
370 | | user | The user whose credit balance should be returned |
371 | | controlledToken | The token for which the credit balance should be pulled |
372 |
373 | ### Credit Rate
374 |
375 | The credit rate for a controlled token can be checked like so:
376 |
377 | ```javascript
378 | function creditRateOf(
379 | address controlledToken
380 | ) external view returns (
381 | uint128 creditLimitMantissa,
382 | uint128 creditRateMantissa
383 | );
384 | ```
385 |
386 | | Parameter Name | Parameter Description |
387 | | --------------- | -------------------------------------------------------------------- |
388 | | controlledToken | The controlled token whose credit limit and rate should be returned. |
389 |
390 | Note that the returned values are "mantissas": i.e. fixed point numbers with 18 decimal places.
391 |
392 | ### Credit Plan
393 |
394 | The credit plan associated with a `controlledToken` can be found by calling:
395 |
396 | ```javascript
397 | function creditPlanOf(address controlledToken) external override view returns (uint128 creditLimitMantissa, uint128 creditRateMantissa)
398 | ```
399 |
400 | ## Prizes
401 |
402 | ### Current Award Balance
403 |
404 | The following function returns the amount calculated by `captureAwardBalance()`:
405 |
406 | ```javascript
407 | function awardBalance() external override view returns (uint256)
408 | ```
409 |
410 | ### Total Balances
411 |
412 | The total of all controlled tokens (including timelocked) can be obtained by calling:
413 |
414 | ```javascript
415 | function accountedBalance() external override view returns (uint256)
416 | ```
417 |
418 | The total underlying balance of all assets (including both principal and interest) can be obtained by calling:
419 |
420 | ```javascript
421 | function balance() external returns (uint256)
422 | ```
423 |
424 | ## External Prizes
425 |
426 | ### Adding Tokens
427 |
428 | The owner can add "external" ERC20 tokens as prizes. The strategy will award the entire balance held by the Prize Pool to the winner.
429 |
430 | ```javascript
431 | function addExternalErc20Award(address _externalErc20) external onlyOwner;
432 | ```
433 |
434 | The owner can add "external" ERC721 tokens as prizes. These tokens will be transferred to the winner.
435 |
436 | ```javascript
437 | function addExternalErc721Award(
438 | address _externalErc721,
439 | uint256[] calldata _tokenIds
440 | ) external onlyOwner
441 | ```
442 |
443 | ### Checking Tokens
444 |
445 | Checks with the Prize Pool if a specific token type (`_externalToken`) may be awarded as an external prize:
446 |
447 | ```javascript
448 | function canAwardExternal(address _externalToken) external view returns (bool)
449 | ```
450 |
451 | ## Prize Time Periods
452 |
453 | To retrieve when the current prize started:
454 |
455 | ```javascript
456 | function prizePeriodStartedAt() external view returns (uint256)
457 | ```
458 |
459 | To retrieve when the prize will end:
460 |
461 | ```javascript
462 | function prizePeriodEndAt() external view returns (uint256)
463 | ```
464 |
465 | ## Reserve
466 |
467 | ### Calculate Reserve Fee
468 |
469 | Calculates the reserve portion of the given `amount` of funds. If there is no reserve address, the Reserve fee portion will be zero.
470 |
471 | ```javascript
472 | function calculateReserveFee(uint256 amount) public view returns (uint256)
473 | ```
474 |
475 | ## Prize Strategy
476 |
477 | ### Set the Prize Strategy
478 |
479 | The associated Prize Strategy can be set by calling:
480 |
481 | ```javascript
482 | function setPrizeStrategy(TokenListenerInterface _prizeStrategy) external override onlyOwner
483 | ```
484 |
485 | Only the Prize Pool owner can call this function.
486 |
487 |
--------------------------------------------------------------------------------
/.gitbook/assets/prizepool.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "anonymous": false,
4 | "inputs": [
5 | {
6 | "indexed": true,
7 | "internalType": "address",
8 | "name": "winner",
9 | "type": "address"
10 | },
11 | {
12 | "indexed": true,
13 | "internalType": "address",
14 | "name": "token",
15 | "type": "address"
16 | },
17 | {
18 | "indexed": false,
19 | "internalType": "uint256",
20 | "name": "amount",
21 | "type": "uint256"
22 | }
23 | ],
24 | "name": "Awarded",
25 | "type": "event"
26 | },
27 | {
28 | "anonymous": false,
29 | "inputs": [
30 | {
31 | "indexed": true,
32 | "internalType": "address",
33 | "name": "winner",
34 | "type": "address"
35 | },
36 | {
37 | "indexed": true,
38 | "internalType": "address",
39 | "name": "token",
40 | "type": "address"
41 | },
42 | {
43 | "indexed": false,
44 | "internalType": "uint256",
45 | "name": "amount",
46 | "type": "uint256"
47 | }
48 | ],
49 | "name": "AwardedExternalERC20",
50 | "type": "event"
51 | },
52 | {
53 | "anonymous": false,
54 | "inputs": [
55 | {
56 | "indexed": true,
57 | "internalType": "address",
58 | "name": "winner",
59 | "type": "address"
60 | },
61 | {
62 | "indexed": true,
63 | "internalType": "address",
64 | "name": "token",
65 | "type": "address"
66 | },
67 | {
68 | "indexed": false,
69 | "internalType": "uint256[]",
70 | "name": "tokenIds",
71 | "type": "uint256[]"
72 | }
73 | ],
74 | "name": "AwardedExternalERC721",
75 | "type": "event"
76 | },
77 | {
78 | "anonymous": false,
79 | "inputs": [
80 | {
81 | "indexed": true,
82 | "internalType": "address",
83 | "name": "token",
84 | "type": "address"
85 | }
86 | ],
87 | "name": "ControlledTokenAdded",
88 | "type": "event"
89 | },
90 | {
91 | "anonymous": false,
92 | "inputs": [
93 | {
94 | "indexed": true,
95 | "internalType": "address",
96 | "name": "user",
97 | "type": "address"
98 | },
99 | {
100 | "indexed": true,
101 | "internalType": "address",
102 | "name": "token",
103 | "type": "address"
104 | },
105 | {
106 | "indexed": false,
107 | "internalType": "uint256",
108 | "name": "amount",
109 | "type": "uint256"
110 | }
111 | ],
112 | "name": "CreditBurned",
113 | "type": "event"
114 | },
115 | {
116 | "anonymous": false,
117 | "inputs": [
118 | {
119 | "indexed": true,
120 | "internalType": "address",
121 | "name": "user",
122 | "type": "address"
123 | },
124 | {
125 | "indexed": true,
126 | "internalType": "address",
127 | "name": "token",
128 | "type": "address"
129 | },
130 | {
131 | "indexed": false,
132 | "internalType": "uint256",
133 | "name": "amount",
134 | "type": "uint256"
135 | }
136 | ],
137 | "name": "CreditMinted",
138 | "type": "event"
139 | },
140 | {
141 | "anonymous": false,
142 | "inputs": [
143 | {
144 | "indexed": false,
145 | "internalType": "address",
146 | "name": "token",
147 | "type": "address"
148 | },
149 | {
150 | "indexed": false,
151 | "internalType": "uint128",
152 | "name": "creditLimitMantissa",
153 | "type": "uint128"
154 | },
155 | {
156 | "indexed": false,
157 | "internalType": "uint128",
158 | "name": "creditRateMantissa",
159 | "type": "uint128"
160 | }
161 | ],
162 | "name": "CreditPlanSet",
163 | "type": "event"
164 | },
165 | {
166 | "anonymous": false,
167 | "inputs": [
168 | {
169 | "indexed": true,
170 | "internalType": "address",
171 | "name": "operator",
172 | "type": "address"
173 | },
174 | {
175 | "indexed": true,
176 | "internalType": "address",
177 | "name": "to",
178 | "type": "address"
179 | },
180 | {
181 | "indexed": true,
182 | "internalType": "address",
183 | "name": "token",
184 | "type": "address"
185 | },
186 | {
187 | "indexed": false,
188 | "internalType": "uint256",
189 | "name": "amount",
190 | "type": "uint256"
191 | },
192 | {
193 | "indexed": false,
194 | "internalType": "address",
195 | "name": "referrer",
196 | "type": "address"
197 | }
198 | ],
199 | "name": "Deposited",
200 | "type": "event"
201 | },
202 | {
203 | "anonymous": false,
204 | "inputs": [],
205 | "name": "EmergencyShutdown",
206 | "type": "event"
207 | },
208 | {
209 | "anonymous": false,
210 | "inputs": [
211 | {
212 | "indexed": false,
213 | "internalType": "address",
214 | "name": "trustedForwarder",
215 | "type": "address"
216 | },
217 | {
218 | "indexed": false,
219 | "internalType": "address",
220 | "name": "reserve",
221 | "type": "address"
222 | },
223 | {
224 | "indexed": false,
225 | "internalType": "uint256",
226 | "name": "maxExitFeeMantissa",
227 | "type": "uint256"
228 | },
229 | {
230 | "indexed": false,
231 | "internalType": "uint256",
232 | "name": "maxTimelockDuration",
233 | "type": "uint256"
234 | }
235 | ],
236 | "name": "Initialized",
237 | "type": "event"
238 | },
239 | {
240 | "anonymous": false,
241 | "inputs": [
242 | {
243 | "indexed": true,
244 | "internalType": "address",
245 | "name": "operator",
246 | "type": "address"
247 | },
248 | {
249 | "indexed": true,
250 | "internalType": "address",
251 | "name": "from",
252 | "type": "address"
253 | },
254 | {
255 | "indexed": true,
256 | "internalType": "address",
257 | "name": "token",
258 | "type": "address"
259 | },
260 | {
261 | "indexed": false,
262 | "internalType": "uint256",
263 | "name": "amount",
264 | "type": "uint256"
265 | },
266 | {
267 | "indexed": false,
268 | "internalType": "uint256",
269 | "name": "redeemed",
270 | "type": "uint256"
271 | },
272 | {
273 | "indexed": false,
274 | "internalType": "uint256",
275 | "name": "exitFee",
276 | "type": "uint256"
277 | }
278 | ],
279 | "name": "InstantWithdrawal",
280 | "type": "event"
281 | },
282 | {
283 | "anonymous": false,
284 | "inputs": [
285 | {
286 | "indexed": false,
287 | "internalType": "uint256",
288 | "name": "liquidityCap",
289 | "type": "uint256"
290 | }
291 | ],
292 | "name": "LiquidityCapSet",
293 | "type": "event"
294 | },
295 | {
296 | "anonymous": false,
297 | "inputs": [
298 | {
299 | "indexed": true,
300 | "internalType": "address",
301 | "name": "previousOwner",
302 | "type": "address"
303 | },
304 | {
305 | "indexed": true,
306 | "internalType": "address",
307 | "name": "newOwner",
308 | "type": "address"
309 | }
310 | ],
311 | "name": "OwnershipTransferred",
312 | "type": "event"
313 | },
314 | {
315 | "anonymous": false,
316 | "inputs": [
317 | {
318 | "indexed": true,
319 | "internalType": "address",
320 | "name": "prizeStrategy",
321 | "type": "address"
322 | }
323 | ],
324 | "name": "PrizeStrategySet",
325 | "type": "event"
326 | },
327 | {
328 | "anonymous": false,
329 | "inputs": [
330 | {
331 | "indexed": true,
332 | "internalType": "address",
333 | "name": "to",
334 | "type": "address"
335 | },
336 | {
337 | "indexed": true,
338 | "internalType": "address",
339 | "name": "token",
340 | "type": "address"
341 | },
342 | {
343 | "indexed": false,
344 | "internalType": "uint256",
345 | "name": "amount",
346 | "type": "uint256"
347 | }
348 | ],
349 | "name": "ReserveFeeCaptured",
350 | "type": "event"
351 | },
352 | {
353 | "anonymous": false,
354 | "inputs": [
355 | {
356 | "indexed": true,
357 | "internalType": "address",
358 | "name": "token",
359 | "type": "address"
360 | }
361 | ],
362 | "name": "ReserveFeeControlledTokenSet",
363 | "type": "event"
364 | },
365 | {
366 | "anonymous": false,
367 | "inputs": [
368 | {
369 | "indexed": true,
370 | "internalType": "address",
371 | "name": "operator",
372 | "type": "address"
373 | },
374 | {
375 | "indexed": true,
376 | "internalType": "address",
377 | "name": "to",
378 | "type": "address"
379 | },
380 | {
381 | "indexed": true,
382 | "internalType": "address",
383 | "name": "token",
384 | "type": "address"
385 | },
386 | {
387 | "indexed": false,
388 | "internalType": "uint256",
389 | "name": "amount",
390 | "type": "uint256"
391 | }
392 | ],
393 | "name": "TimelockDeposited",
394 | "type": "event"
395 | },
396 | {
397 | "anonymous": false,
398 | "inputs": [
399 | {
400 | "indexed": true,
401 | "internalType": "address",
402 | "name": "operator",
403 | "type": "address"
404 | },
405 | {
406 | "indexed": true,
407 | "internalType": "address",
408 | "name": "from",
409 | "type": "address"
410 | },
411 | {
412 | "indexed": true,
413 | "internalType": "address",
414 | "name": "token",
415 | "type": "address"
416 | },
417 | {
418 | "indexed": false,
419 | "internalType": "uint256",
420 | "name": "amount",
421 | "type": "uint256"
422 | },
423 | {
424 | "indexed": false,
425 | "internalType": "uint256",
426 | "name": "unlockTimestamp",
427 | "type": "uint256"
428 | }
429 | ],
430 | "name": "TimelockedWithdrawal",
431 | "type": "event"
432 | },
433 | {
434 | "anonymous": false,
435 | "inputs": [
436 | {
437 | "indexed": true,
438 | "internalType": "address",
439 | "name": "operator",
440 | "type": "address"
441 | },
442 | {
443 | "indexed": true,
444 | "internalType": "address",
445 | "name": "from",
446 | "type": "address"
447 | },
448 | {
449 | "indexed": false,
450 | "internalType": "uint256",
451 | "name": "amount",
452 | "type": "uint256"
453 | },
454 | {
455 | "indexed": false,
456 | "internalType": "uint256",
457 | "name": "redeemed",
458 | "type": "uint256"
459 | }
460 | ],
461 | "name": "TimelockedWithdrawalSwept",
462 | "type": "event"
463 | },
464 | {
465 | "anonymous": false,
466 | "inputs": [
467 | {
468 | "indexed": true,
469 | "internalType": "address",
470 | "name": "to",
471 | "type": "address"
472 | },
473 | {
474 | "indexed": true,
475 | "internalType": "address",
476 | "name": "token",
477 | "type": "address"
478 | },
479 | {
480 | "indexed": false,
481 | "internalType": "uint256",
482 | "name": "amount",
483 | "type": "uint256"
484 | }
485 | ],
486 | "name": "TransferredExternalERC20",
487 | "type": "event"
488 | },
489 | {
490 | "inputs": [],
491 | "name": "accountedBalance",
492 | "outputs": [
493 | {
494 | "internalType": "uint256",
495 | "name": "",
496 | "type": "uint256"
497 | }
498 | ],
499 | "stateMutability": "view",
500 | "type": "function"
501 | },
502 | {
503 | "inputs": [
504 | {
505 | "internalType": "address",
506 | "name": "_controlledToken",
507 | "type": "address"
508 | }
509 | ],
510 | "name": "addControlledToken",
511 | "outputs": [],
512 | "stateMutability": "nonpayable",
513 | "type": "function"
514 | },
515 | {
516 | "inputs": [
517 | {
518 | "internalType": "address",
519 | "name": "to",
520 | "type": "address"
521 | },
522 | {
523 | "internalType": "uint256",
524 | "name": "amount",
525 | "type": "uint256"
526 | },
527 | {
528 | "internalType": "address",
529 | "name": "controlledToken",
530 | "type": "address"
531 | }
532 | ],
533 | "name": "award",
534 | "outputs": [],
535 | "stateMutability": "nonpayable",
536 | "type": "function"
537 | },
538 | {
539 | "inputs": [],
540 | "name": "awardBalance",
541 | "outputs": [
542 | {
543 | "internalType": "uint256",
544 | "name": "",
545 | "type": "uint256"
546 | }
547 | ],
548 | "stateMutability": "view",
549 | "type": "function"
550 | },
551 | {
552 | "inputs": [
553 | {
554 | "internalType": "address",
555 | "name": "to",
556 | "type": "address"
557 | },
558 | {
559 | "internalType": "address",
560 | "name": "externalToken",
561 | "type": "address"
562 | },
563 | {
564 | "internalType": "uint256",
565 | "name": "amount",
566 | "type": "uint256"
567 | }
568 | ],
569 | "name": "awardExternalERC20",
570 | "outputs": [],
571 | "stateMutability": "nonpayable",
572 | "type": "function"
573 | },
574 | {
575 | "inputs": [
576 | {
577 | "internalType": "address",
578 | "name": "to",
579 | "type": "address"
580 | },
581 | {
582 | "internalType": "address",
583 | "name": "externalToken",
584 | "type": "address"
585 | },
586 | {
587 | "internalType": "uint256[]",
588 | "name": "tokenIds",
589 | "type": "uint256[]"
590 | }
591 | ],
592 | "name": "awardExternalERC721",
593 | "outputs": [],
594 | "stateMutability": "nonpayable",
595 | "type": "function"
596 | },
597 | {
598 | "inputs": [],
599 | "name": "balance",
600 | "outputs": [
601 | {
602 | "internalType": "uint256",
603 | "name": "",
604 | "type": "uint256"
605 | }
606 | ],
607 | "stateMutability": "nonpayable",
608 | "type": "function"
609 | },
610 | {
611 | "inputs": [
612 | {
613 | "internalType": "address",
614 | "name": "user",
615 | "type": "address"
616 | },
617 | {
618 | "internalType": "address",
619 | "name": "controlledToken",
620 | "type": "address"
621 | }
622 | ],
623 | "name": "balanceOfCredit",
624 | "outputs": [
625 | {
626 | "internalType": "uint256",
627 | "name": "",
628 | "type": "uint256"
629 | }
630 | ],
631 | "stateMutability": "nonpayable",
632 | "type": "function"
633 | },
634 | {
635 | "inputs": [
636 | {
637 | "internalType": "address",
638 | "name": "from",
639 | "type": "address"
640 | },
641 | {
642 | "internalType": "address",
643 | "name": "to",
644 | "type": "address"
645 | },
646 | {
647 | "internalType": "uint256",
648 | "name": "amount",
649 | "type": "uint256"
650 | }
651 | ],
652 | "name": "beforeTokenTransfer",
653 | "outputs": [],
654 | "stateMutability": "nonpayable",
655 | "type": "function"
656 | },
657 | {
658 | "inputs": [
659 | {
660 | "internalType": "address",
661 | "name": "from",
662 | "type": "address"
663 | },
664 | {
665 | "internalType": "address",
666 | "name": "controlledToken",
667 | "type": "address"
668 | },
669 | {
670 | "internalType": "uint256",
671 | "name": "amount",
672 | "type": "uint256"
673 | }
674 | ],
675 | "name": "calculateEarlyExitFee",
676 | "outputs": [
677 | {
678 | "internalType": "uint256",
679 | "name": "exitFee",
680 | "type": "uint256"
681 | },
682 | {
683 | "internalType": "uint256",
684 | "name": "burnedCredit",
685 | "type": "uint256"
686 | }
687 | ],
688 | "stateMutability": "nonpayable",
689 | "type": "function"
690 | },
691 | {
692 | "inputs": [
693 | {
694 | "internalType": "uint256",
695 | "name": "amount",
696 | "type": "uint256"
697 | }
698 | ],
699 | "name": "calculateReserveFee",
700 | "outputs": [
701 | {
702 | "internalType": "uint256",
703 | "name": "",
704 | "type": "uint256"
705 | }
706 | ],
707 | "stateMutability": "view",
708 | "type": "function"
709 | },
710 | {
711 | "inputs": [
712 | {
713 | "internalType": "address",
714 | "name": "from",
715 | "type": "address"
716 | },
717 | {
718 | "internalType": "address",
719 | "name": "controlledToken",
720 | "type": "address"
721 | },
722 | {
723 | "internalType": "uint256",
724 | "name": "amount",
725 | "type": "uint256"
726 | }
727 | ],
728 | "name": "calculateTimelockDuration",
729 | "outputs": [
730 | {
731 | "internalType": "uint256",
732 | "name": "durationSeconds",
733 | "type": "uint256"
734 | },
735 | {
736 | "internalType": "uint256",
737 | "name": "burnedCredit",
738 | "type": "uint256"
739 | }
740 | ],
741 | "stateMutability": "nonpayable",
742 | "type": "function"
743 | },
744 | {
745 | "inputs": [
746 | {
747 | "internalType": "address",
748 | "name": "_externalToken",
749 | "type": "address"
750 | }
751 | ],
752 | "name": "canAwardExternal",
753 | "outputs": [
754 | {
755 | "internalType": "bool",
756 | "name": "",
757 | "type": "bool"
758 | }
759 | ],
760 | "stateMutability": "view",
761 | "type": "function"
762 | },
763 | {
764 | "inputs": [],
765 | "name": "captureAwardBalance",
766 | "outputs": [
767 | {
768 | "internalType": "uint256",
769 | "name": "",
770 | "type": "uint256"
771 | }
772 | ],
773 | "stateMutability": "nonpayable",
774 | "type": "function"
775 | },
776 | {
777 | "inputs": [
778 | {
779 | "internalType": "address",
780 | "name": "controlledToken",
781 | "type": "address"
782 | }
783 | ],
784 | "name": "creditPlanOf",
785 | "outputs": [
786 | {
787 | "internalType": "uint128",
788 | "name": "creditLimitMantissa",
789 | "type": "uint128"
790 | },
791 | {
792 | "internalType": "uint128",
793 | "name": "creditRateMantissa",
794 | "type": "uint128"
795 | }
796 | ],
797 | "stateMutability": "view",
798 | "type": "function"
799 | },
800 | {
801 | "inputs": [
802 | {
803 | "internalType": "address",
804 | "name": "to",
805 | "type": "address"
806 | },
807 | {
808 | "internalType": "uint256",
809 | "name": "amount",
810 | "type": "uint256"
811 | },
812 | {
813 | "internalType": "address",
814 | "name": "controlledToken",
815 | "type": "address"
816 | },
817 | {
818 | "internalType": "address",
819 | "name": "referrer",
820 | "type": "address"
821 | }
822 | ],
823 | "name": "depositTo",
824 | "outputs": [],
825 | "stateMutability": "nonpayable",
826 | "type": "function"
827 | },
828 | {
829 | "inputs": [],
830 | "name": "emergencyShutdown",
831 | "outputs": [],
832 | "stateMutability": "nonpayable",
833 | "type": "function"
834 | },
835 | {
836 | "inputs": [
837 | {
838 | "internalType": "address",
839 | "name": "_controlledToken",
840 | "type": "address"
841 | },
842 | {
843 | "internalType": "uint256",
844 | "name": "_principal",
845 | "type": "uint256"
846 | },
847 | {
848 | "internalType": "uint256",
849 | "name": "_interest",
850 | "type": "uint256"
851 | }
852 | ],
853 | "name": "estimateCreditAccrualTime",
854 | "outputs": [
855 | {
856 | "internalType": "uint256",
857 | "name": "durationSeconds",
858 | "type": "uint256"
859 | }
860 | ],
861 | "stateMutability": "view",
862 | "type": "function"
863 | },
864 | {
865 | "inputs": [
866 | {
867 | "internalType": "address",
868 | "name": "_trustedForwarder",
869 | "type": "address"
870 | },
871 | {
872 | "internalType": "contract ReserveInterface",
873 | "name": "_reserve",
874 | "type": "address"
875 | },
876 | {
877 | "internalType": "address[]",
878 | "name": "_controlledTokens",
879 | "type": "address[]"
880 | },
881 | {
882 | "internalType": "uint256",
883 | "name": "_maxExitFeeMantissa",
884 | "type": "uint256"
885 | },
886 | {
887 | "internalType": "uint256",
888 | "name": "_maxTimelockDuration",
889 | "type": "uint256"
890 | }
891 | ],
892 | "name": "initialize",
893 | "outputs": [],
894 | "stateMutability": "nonpayable",
895 | "type": "function"
896 | },
897 | {
898 | "inputs": [],
899 | "name": "isShutdown",
900 | "outputs": [
901 | {
902 | "internalType": "bool",
903 | "name": "",
904 | "type": "bool"
905 | }
906 | ],
907 | "stateMutability": "view",
908 | "type": "function"
909 | },
910 | {
911 | "inputs": [
912 | {
913 | "internalType": "address",
914 | "name": "forwarder",
915 | "type": "address"
916 | }
917 | ],
918 | "name": "isTrustedForwarder",
919 | "outputs": [
920 | {
921 | "internalType": "bool",
922 | "name": "",
923 | "type": "bool"
924 | }
925 | ],
926 | "stateMutability": "view",
927 | "type": "function"
928 | },
929 | {
930 | "inputs": [],
931 | "name": "liquidityCap",
932 | "outputs": [
933 | {
934 | "internalType": "uint256",
935 | "name": "",
936 | "type": "uint256"
937 | }
938 | ],
939 | "stateMutability": "view",
940 | "type": "function"
941 | },
942 | {
943 | "inputs": [],
944 | "name": "maxExitFeeMantissa",
945 | "outputs": [
946 | {
947 | "internalType": "uint256",
948 | "name": "",
949 | "type": "uint256"
950 | }
951 | ],
952 | "stateMutability": "view",
953 | "type": "function"
954 | },
955 | {
956 | "inputs": [],
957 | "name": "maxTimelockDuration",
958 | "outputs": [
959 | {
960 | "internalType": "uint256",
961 | "name": "",
962 | "type": "uint256"
963 | }
964 | ],
965 | "stateMutability": "view",
966 | "type": "function"
967 | },
968 | {
969 | "inputs": [],
970 | "name": "owner",
971 | "outputs": [
972 | {
973 | "internalType": "address",
974 | "name": "",
975 | "type": "address"
976 | }
977 | ],
978 | "stateMutability": "view",
979 | "type": "function"
980 | },
981 | {
982 | "inputs": [],
983 | "name": "prizeStrategy",
984 | "outputs": [
985 | {
986 | "internalType": "contract TokenListenerInterface",
987 | "name": "",
988 | "type": "address"
989 | }
990 | ],
991 | "stateMutability": "view",
992 | "type": "function"
993 | },
994 | {
995 | "inputs": [],
996 | "name": "renounceOwnership",
997 | "outputs": [],
998 | "stateMutability": "nonpayable",
999 | "type": "function"
1000 | },
1001 | {
1002 | "inputs": [],
1003 | "name": "reserve",
1004 | "outputs": [
1005 | {
1006 | "internalType": "contract ReserveInterface",
1007 | "name": "",
1008 | "type": "address"
1009 | }
1010 | ],
1011 | "stateMutability": "view",
1012 | "type": "function"
1013 | },
1014 | {
1015 | "inputs": [],
1016 | "name": "reserveFeeControlledToken",
1017 | "outputs": [
1018 | {
1019 | "internalType": "address",
1020 | "name": "",
1021 | "type": "address"
1022 | }
1023 | ],
1024 | "stateMutability": "view",
1025 | "type": "function"
1026 | },
1027 | {
1028 | "inputs": [
1029 | {
1030 | "internalType": "address",
1031 | "name": "_controlledToken",
1032 | "type": "address"
1033 | },
1034 | {
1035 | "internalType": "uint128",
1036 | "name": "_creditRateMantissa",
1037 | "type": "uint128"
1038 | },
1039 | {
1040 | "internalType": "uint128",
1041 | "name": "_creditLimitMantissa",
1042 | "type": "uint128"
1043 | }
1044 | ],
1045 | "name": "setCreditPlanOf",
1046 | "outputs": [],
1047 | "stateMutability": "nonpayable",
1048 | "type": "function"
1049 | },
1050 | {
1051 | "inputs": [
1052 | {
1053 | "internalType": "uint256",
1054 | "name": "_liquidityCap",
1055 | "type": "uint256"
1056 | }
1057 | ],
1058 | "name": "setLiquidityCap",
1059 | "outputs": [],
1060 | "stateMutability": "nonpayable",
1061 | "type": "function"
1062 | },
1063 | {
1064 | "inputs": [
1065 | {
1066 | "internalType": "contract TokenListenerInterface",
1067 | "name": "_prizeStrategy",
1068 | "type": "address"
1069 | }
1070 | ],
1071 | "name": "setPrizeStrategy",
1072 | "outputs": [],
1073 | "stateMutability": "nonpayable",
1074 | "type": "function"
1075 | },
1076 | {
1077 | "inputs": [
1078 | {
1079 | "internalType": "address",
1080 | "name": "controlledToken",
1081 | "type": "address"
1082 | }
1083 | ],
1084 | "name": "setReserveFeeControlledToken",
1085 | "outputs": [],
1086 | "stateMutability": "nonpayable",
1087 | "type": "function"
1088 | },
1089 | {
1090 | "inputs": [
1091 | {
1092 | "internalType": "address[]",
1093 | "name": "users",
1094 | "type": "address[]"
1095 | }
1096 | ],
1097 | "name": "sweepTimelockBalances",
1098 | "outputs": [
1099 | {
1100 | "internalType": "uint256",
1101 | "name": "",
1102 | "type": "uint256"
1103 | }
1104 | ],
1105 | "stateMutability": "nonpayable",
1106 | "type": "function"
1107 | },
1108 | {
1109 | "inputs": [
1110 | {
1111 | "internalType": "address",
1112 | "name": "user",
1113 | "type": "address"
1114 | }
1115 | ],
1116 | "name": "timelockBalanceAvailableAt",
1117 | "outputs": [
1118 | {
1119 | "internalType": "uint256",
1120 | "name": "",
1121 | "type": "uint256"
1122 | }
1123 | ],
1124 | "stateMutability": "view",
1125 | "type": "function"
1126 | },
1127 | {
1128 | "inputs": [
1129 | {
1130 | "internalType": "address",
1131 | "name": "user",
1132 | "type": "address"
1133 | }
1134 | ],
1135 | "name": "timelockBalanceOf",
1136 | "outputs": [
1137 | {
1138 | "internalType": "uint256",
1139 | "name": "",
1140 | "type": "uint256"
1141 | }
1142 | ],
1143 | "stateMutability": "view",
1144 | "type": "function"
1145 | },
1146 | {
1147 | "inputs": [
1148 | {
1149 | "internalType": "address",
1150 | "name": "to",
1151 | "type": "address"
1152 | },
1153 | {
1154 | "internalType": "uint256",
1155 | "name": "amount",
1156 | "type": "uint256"
1157 | },
1158 | {
1159 | "internalType": "address",
1160 | "name": "controlledToken",
1161 | "type": "address"
1162 | }
1163 | ],
1164 | "name": "timelockDepositTo",
1165 | "outputs": [],
1166 | "stateMutability": "nonpayable",
1167 | "type": "function"
1168 | },
1169 | {
1170 | "inputs": [],
1171 | "name": "timelockTotalSupply",
1172 | "outputs": [
1173 | {
1174 | "internalType": "uint256",
1175 | "name": "",
1176 | "type": "uint256"
1177 | }
1178 | ],
1179 | "stateMutability": "view",
1180 | "type": "function"
1181 | },
1182 | {
1183 | "inputs": [],
1184 | "name": "token",
1185 | "outputs": [
1186 | {
1187 | "internalType": "contract IERC20",
1188 | "name": "",
1189 | "type": "address"
1190 | }
1191 | ],
1192 | "stateMutability": "view",
1193 | "type": "function"
1194 | },
1195 | {
1196 | "inputs": [],
1197 | "name": "tokens",
1198 | "outputs": [
1199 | {
1200 | "internalType": "address[]",
1201 | "name": "",
1202 | "type": "address[]"
1203 | }
1204 | ],
1205 | "stateMutability": "view",
1206 | "type": "function"
1207 | },
1208 | {
1209 | "inputs": [
1210 | {
1211 | "internalType": "address",
1212 | "name": "to",
1213 | "type": "address"
1214 | },
1215 | {
1216 | "internalType": "address",
1217 | "name": "externalToken",
1218 | "type": "address"
1219 | },
1220 | {
1221 | "internalType": "uint256",
1222 | "name": "amount",
1223 | "type": "uint256"
1224 | }
1225 | ],
1226 | "name": "transferExternalERC20",
1227 | "outputs": [],
1228 | "stateMutability": "nonpayable",
1229 | "type": "function"
1230 | },
1231 | {
1232 | "inputs": [
1233 | {
1234 | "internalType": "address",
1235 | "name": "newOwner",
1236 | "type": "address"
1237 | }
1238 | ],
1239 | "name": "transferOwnership",
1240 | "outputs": [],
1241 | "stateMutability": "nonpayable",
1242 | "type": "function"
1243 | },
1244 | {
1245 | "inputs": [],
1246 | "name": "trustedForwarder",
1247 | "outputs": [
1248 | {
1249 | "internalType": "address",
1250 | "name": "",
1251 | "type": "address"
1252 | }
1253 | ],
1254 | "stateMutability": "view",
1255 | "type": "function"
1256 | },
1257 | {
1258 | "inputs": [],
1259 | "name": "versionRecipient",
1260 | "outputs": [
1261 | {
1262 | "internalType": "string",
1263 | "name": "",
1264 | "type": "string"
1265 | }
1266 | ],
1267 | "stateMutability": "view",
1268 | "type": "function"
1269 | },
1270 | {
1271 | "inputs": [
1272 | {
1273 | "internalType": "address",
1274 | "name": "from",
1275 | "type": "address"
1276 | },
1277 | {
1278 | "internalType": "uint256",
1279 | "name": "amount",
1280 | "type": "uint256"
1281 | },
1282 | {
1283 | "internalType": "address",
1284 | "name": "controlledToken",
1285 | "type": "address"
1286 | },
1287 | {
1288 | "internalType": "uint256",
1289 | "name": "maximumExitFee",
1290 | "type": "uint256"
1291 | }
1292 | ],
1293 | "name": "withdrawInstantlyFrom",
1294 | "outputs": [
1295 | {
1296 | "internalType": "uint256",
1297 | "name": "",
1298 | "type": "uint256"
1299 | }
1300 | ],
1301 | "stateMutability": "nonpayable",
1302 | "type": "function"
1303 | },
1304 | {
1305 | "inputs": [
1306 | {
1307 | "internalType": "address",
1308 | "name": "from",
1309 | "type": "address"
1310 | },
1311 | {
1312 | "internalType": "uint256",
1313 | "name": "amount",
1314 | "type": "uint256"
1315 | },
1316 | {
1317 | "internalType": "address",
1318 | "name": "controlledToken",
1319 | "type": "address"
1320 | }
1321 | ],
1322 | "name": "withdrawWithTimelockFrom",
1323 | "outputs": [
1324 | {
1325 | "internalType": "uint256",
1326 | "name": "",
1327 | "type": "uint256"
1328 | }
1329 | ],
1330 | "stateMutability": "nonpayable",
1331 | "type": "function"
1332 | }
1333 | ]
--------------------------------------------------------------------------------