diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS deleted file mode 100644 index 94529b88..00000000 --- a/.github/CODEOWNERS +++ /dev/null @@ -1 +0,0 @@ -* @emptysetsquad diff --git a/README.md b/README.md index 661af2a3..8edb9078 100644 --- a/README.md +++ b/README.md @@ -1,43 +1,41 @@ -# døllar -fully decentralized self-stabilizing dollar. +# Universal Dollar ## stablecoin -- shorthand name: `døllar` -- full name: `Empty Set Dollar` -- symbol: `ESD` +- full name: `Universal Dollar` +- symbol: `U8D` - decimals: `18` -- character: `∅ [U+2205], ∅100` -- icons: +- icon: -![mfGW7wXg_400x400](https://raw.githubusercontent.com/emptysetsquad/dollar-dashboard/master/public/logo/esd_logo_circle.png) -![mfGW7wXg_400x400](https://raw.githubusercontent.com/emptysetsquad/dollar-dashboard/master/public/logo/esd_logo_square.png) - -## dashboard - -simple [dashboard](https://github.com/emptysetsquad/dollar-dashboard) for interacting with the døllar protocol. - -## whitepaper - -is available [here](https://github.com/emptysetsquad/dollar/blob/master/d%C3%B8llar.pdf). +![U8D Logo](./icon/u8d.png) ## contracts ### mainnet -- `0x443D2f2755DB5942601fa062Cc248aAA153313D3` **DAO** -- `0x36F3FD68E7325a35EB768F1AedaAe9EA0689d723` **Døllar** -- `0xea9f8bb8B5e8BA3D38628f0E18Ee82300eddBa0E` **Oracle** -- `0x88ff79eB2Bc5850F27315415da8685282C7610F9` **UniswapV2 USDC:ESD Pair** -- `0x4082d11e506e3250009a991061acd2176077c88f` **LP Incentivation Pool** +- `0x2137fFbbB279218E1a61d4483DeD9C9a017e9257` **DAO (U8DS)** +- `0x888888877A18532b78d259577d00057054C50Dd8` **U8D** +- `0x8cb7c5422672F5432363C628358A5e7eA6938DC2` **Oracle** +- `0x78c54b20CC4C2db6E7A9758aE16579D866BA6FFD` **UniswapV2 USDC:U8D Pair** +- `0x111eB123d0CEeEa59A3736ae1767F9E756bE8160` **LP Incentivisation Pool** ## audit -is available [here](https://github.com/emptysetsquad/dollar/blob/master/audit/REP-Dollar-06-11-20.pdf). +Universal Dollar (u8d-protocol) audit is available [here](audit/Universal-CertiK-Final-Report-For-Universal-Dollar-Protocol.pdf). +
audit of ESD is available [here](audit/REP-Dollar-06-11-20.pdf). + +## u8d links + +- [Website](https://u8d.finance) +- [Github](https://github.com/8quad) +- [Medium](https://8quad.medium.com/) +- [Twitter](https://twitter.com/u_8_d) +- [Telegram](https://t.me/UniversalDollar) +- [Discord](https://discord.gg/3uTPBqkyvc) ## disclaimer this project is an experiment - the protocol is audited, and we've put a significant amount of work into testing as well as generally de-risking the design of its core mechanism, however participants should take great caution as bugs resulting in loss of funds are always a possibility. ``` -Copyright 2020 Empty Set Squad +Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use the included code except in compliance with the License. @@ -53,4 +51,4 @@ limitations under the License. ```
-made with 💔️ by the {ess}. \ No newline at end of file +made with passion by the 8quad. diff --git a/audit/Universal-CertiK-Final-Report-For-Universal-Dollar-Protocol.pdf b/audit/Universal-CertiK-Final-Report-For-Universal-Dollar-Protocol.pdf new file mode 100644 index 00000000..ee76b0d0 Binary files /dev/null and b/audit/Universal-CertiK-Final-Report-For-Universal-Dollar-Protocol.pdf differ diff --git "a/d\303\270llar.pdf" "b/d\303\270llar.pdf" deleted file mode 100644 index ff0367b5..00000000 Binary files "a/d\303\270llar.pdf" and /dev/null differ diff --git a/icon/u8d.png b/icon/u8d.png new file mode 100644 index 00000000..3f6f2d10 Binary files /dev/null and b/icon/u8d.png differ diff --git a/protocol/abi/Deployer1.json b/protocol/abi/Deployer1.json deleted file mode 100644 index 761addf9..00000000 --- a/protocol/abi/Deployer1.json +++ /dev/null @@ -1 +0,0 @@ -[{"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "implementation", "type": "address"}], "name": "Upgraded", "type": "event"}, {"constant": true, "inputs": [{"internalType": "address", "name": "owner", "type": "address"}, {"internalType": "address", "name": "spender", "type": "address"}], "name": "allowance", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "owner", "type": "address"}, {"internalType": "address", "name": "spender", "type": "address"}], "name": "allowanceCoupons", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": false, "inputs": [{"internalType": "address", "name": "spender", "type": "address"}, {"internalType": "uint256", "name": "amount", "type": "uint256"}], "name": "approve", "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "candidate", "type": "address"}], "name": "approveFor", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "account", "type": "address"}], "name": "balanceOf", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "account", "type": "address"}], "name": "balanceOfBonded", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "account", "type": "address"}, {"internalType": "uint256", "name": "epoch", "type": "uint256"}], "name": "balanceOfCoupons", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "account", "type": "address"}], "name": "balanceOfStaged", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "uint256", "name": "epoch", "type": "uint256"}], "name": "bootstrappingAt", "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "uint256", "name": "epoch", "type": "uint256"}], "name": "couponsExpiration", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "decimals", "outputs": [{"internalType": "uint8", "name": "", "type": "uint8"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "dollar", "outputs": [{"internalType": "contract IDollar", "name": "", "type": "address"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "epoch", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "epochPeriod", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "epochStart", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "epochTime", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "uint256", "name": "epoch", "type": "uint256"}], "name": "expiringCoupons", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "uint256", "name": "epoch", "type": "uint256"}, {"internalType": "uint256", "name": "i", "type": "uint256"}], "name": "expiringCouponsAtIndex", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "implementation", "outputs": [{"internalType": "address", "name": "impl", "type": "address"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "candidate", "type": "address"}], "name": "isInitialized", "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "candidate", "type": "address"}], "name": "isNominated", "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "name", "outputs": [{"internalType": "string", "name": "", "type": "string"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "oracle", "outputs": [{"internalType": "contract IOracle", "name": "", "type": "address"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "uint256", "name": "epoch", "type": "uint256"}], "name": "outstandingCoupons", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "candidate", "type": "address"}], "name": "periodFor", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "pool", "outputs": [{"internalType": "address", "name": "", "type": "address"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "account", "type": "address"}, {"internalType": "address", "name": "candidate", "type": "address"}], "name": "recordedVote", "outputs": [{"internalType": "enum Candidate.Vote", "name": "", "type": "uint8"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "candidate", "type": "address"}], "name": "rejectFor", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "candidate", "type": "address"}], "name": "startFor", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "account", "type": "address"}], "name": "statusOf", "outputs": [{"internalType": "enum Account.Status", "name": "", "type": "uint8"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "symbol", "outputs": [{"internalType": "string", "name": "", "type": "string"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "totalBonded", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "uint256", "name": "epoch", "type": "uint256"}], "name": "totalBondedAt", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "totalCoupons", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "totalDebt", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "totalNet", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "totalRedeemable", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "totalStaged", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "totalSupply", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": false, "inputs": [{"internalType": "address", "name": "recipient", "type": "address"}, {"internalType": "uint256", "name": "amount", "type": "uint256"}], "name": "transfer", "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": false, "inputs": [{"internalType": "address", "name": "sender", "type": "address"}, {"internalType": "address", "name": "recipient", "type": "address"}, {"internalType": "uint256", "name": "amount", "type": "uint256"}], "name": "transferFrom", "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "candidate", "type": "address"}], "name": "votesFor", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": false, "inputs": [], "name": "initialize", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": false, "inputs": [{"internalType": "address", "name": "implementation", "type": "address"}], "name": "implement", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function"}] \ No newline at end of file diff --git a/protocol/abi/Deployer2.json b/protocol/abi/Deployer2.json deleted file mode 100644 index 761addf9..00000000 --- a/protocol/abi/Deployer2.json +++ /dev/null @@ -1 +0,0 @@ -[{"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "implementation", "type": "address"}], "name": "Upgraded", "type": "event"}, {"constant": true, "inputs": [{"internalType": "address", "name": "owner", "type": "address"}, {"internalType": "address", "name": "spender", "type": "address"}], "name": "allowance", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "owner", "type": "address"}, {"internalType": "address", "name": "spender", "type": "address"}], "name": "allowanceCoupons", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": false, "inputs": [{"internalType": "address", "name": "spender", "type": "address"}, {"internalType": "uint256", "name": "amount", "type": "uint256"}], "name": "approve", "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "candidate", "type": "address"}], "name": "approveFor", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "account", "type": "address"}], "name": "balanceOf", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "account", "type": "address"}], "name": "balanceOfBonded", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "account", "type": "address"}, {"internalType": "uint256", "name": "epoch", "type": "uint256"}], "name": "balanceOfCoupons", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "account", "type": "address"}], "name": "balanceOfStaged", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "uint256", "name": "epoch", "type": "uint256"}], "name": "bootstrappingAt", "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "uint256", "name": "epoch", "type": "uint256"}], "name": "couponsExpiration", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "decimals", "outputs": [{"internalType": "uint8", "name": "", "type": "uint8"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "dollar", "outputs": [{"internalType": "contract IDollar", "name": "", "type": "address"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "epoch", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "epochPeriod", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "epochStart", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "epochTime", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "uint256", "name": "epoch", "type": "uint256"}], "name": "expiringCoupons", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "uint256", "name": "epoch", "type": "uint256"}, {"internalType": "uint256", "name": "i", "type": "uint256"}], "name": "expiringCouponsAtIndex", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "implementation", "outputs": [{"internalType": "address", "name": "impl", "type": "address"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "candidate", "type": "address"}], "name": "isInitialized", "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "candidate", "type": "address"}], "name": "isNominated", "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "name", "outputs": [{"internalType": "string", "name": "", "type": "string"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "oracle", "outputs": [{"internalType": "contract IOracle", "name": "", "type": "address"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "uint256", "name": "epoch", "type": "uint256"}], "name": "outstandingCoupons", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "candidate", "type": "address"}], "name": "periodFor", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "pool", "outputs": [{"internalType": "address", "name": "", "type": "address"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "account", "type": "address"}, {"internalType": "address", "name": "candidate", "type": "address"}], "name": "recordedVote", "outputs": [{"internalType": "enum Candidate.Vote", "name": "", "type": "uint8"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "candidate", "type": "address"}], "name": "rejectFor", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "candidate", "type": "address"}], "name": "startFor", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "account", "type": "address"}], "name": "statusOf", "outputs": [{"internalType": "enum Account.Status", "name": "", "type": "uint8"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "symbol", "outputs": [{"internalType": "string", "name": "", "type": "string"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "totalBonded", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "uint256", "name": "epoch", "type": "uint256"}], "name": "totalBondedAt", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "totalCoupons", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "totalDebt", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "totalNet", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "totalRedeemable", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "totalStaged", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "totalSupply", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": false, "inputs": [{"internalType": "address", "name": "recipient", "type": "address"}, {"internalType": "uint256", "name": "amount", "type": "uint256"}], "name": "transfer", "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": false, "inputs": [{"internalType": "address", "name": "sender", "type": "address"}, {"internalType": "address", "name": "recipient", "type": "address"}, {"internalType": "uint256", "name": "amount", "type": "uint256"}], "name": "transferFrom", "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "candidate", "type": "address"}], "name": "votesFor", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": false, "inputs": [], "name": "initialize", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": false, "inputs": [{"internalType": "address", "name": "implementation", "type": "address"}], "name": "implement", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function"}] \ No newline at end of file diff --git a/protocol/abi/Deployer3.json b/protocol/abi/Deployer3.json deleted file mode 100644 index 761addf9..00000000 --- a/protocol/abi/Deployer3.json +++ /dev/null @@ -1 +0,0 @@ -[{"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "implementation", "type": "address"}], "name": "Upgraded", "type": "event"}, {"constant": true, "inputs": [{"internalType": "address", "name": "owner", "type": "address"}, {"internalType": "address", "name": "spender", "type": "address"}], "name": "allowance", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "owner", "type": "address"}, {"internalType": "address", "name": "spender", "type": "address"}], "name": "allowanceCoupons", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": false, "inputs": [{"internalType": "address", "name": "spender", "type": "address"}, {"internalType": "uint256", "name": "amount", "type": "uint256"}], "name": "approve", "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "candidate", "type": "address"}], "name": "approveFor", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "account", "type": "address"}], "name": "balanceOf", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "account", "type": "address"}], "name": "balanceOfBonded", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "account", "type": "address"}, {"internalType": "uint256", "name": "epoch", "type": "uint256"}], "name": "balanceOfCoupons", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "account", "type": "address"}], "name": "balanceOfStaged", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "uint256", "name": "epoch", "type": "uint256"}], "name": "bootstrappingAt", "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "uint256", "name": "epoch", "type": "uint256"}], "name": "couponsExpiration", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "decimals", "outputs": [{"internalType": "uint8", "name": "", "type": "uint8"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "dollar", "outputs": [{"internalType": "contract IDollar", "name": "", "type": "address"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "epoch", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "epochPeriod", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "epochStart", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "epochTime", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "uint256", "name": "epoch", "type": "uint256"}], "name": "expiringCoupons", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "uint256", "name": "epoch", "type": "uint256"}, {"internalType": "uint256", "name": "i", "type": "uint256"}], "name": "expiringCouponsAtIndex", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "implementation", "outputs": [{"internalType": "address", "name": "impl", "type": "address"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "candidate", "type": "address"}], "name": "isInitialized", "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "candidate", "type": "address"}], "name": "isNominated", "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "name", "outputs": [{"internalType": "string", "name": "", "type": "string"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "oracle", "outputs": [{"internalType": "contract IOracle", "name": "", "type": "address"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "uint256", "name": "epoch", "type": "uint256"}], "name": "outstandingCoupons", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "candidate", "type": "address"}], "name": "periodFor", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "pool", "outputs": [{"internalType": "address", "name": "", "type": "address"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "account", "type": "address"}, {"internalType": "address", "name": "candidate", "type": "address"}], "name": "recordedVote", "outputs": [{"internalType": "enum Candidate.Vote", "name": "", "type": "uint8"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "candidate", "type": "address"}], "name": "rejectFor", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "candidate", "type": "address"}], "name": "startFor", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "account", "type": "address"}], "name": "statusOf", "outputs": [{"internalType": "enum Account.Status", "name": "", "type": "uint8"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "symbol", "outputs": [{"internalType": "string", "name": "", "type": "string"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "totalBonded", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "uint256", "name": "epoch", "type": "uint256"}], "name": "totalBondedAt", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "totalCoupons", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "totalDebt", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "totalNet", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "totalRedeemable", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "totalStaged", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "totalSupply", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": false, "inputs": [{"internalType": "address", "name": "recipient", "type": "address"}, {"internalType": "uint256", "name": "amount", "type": "uint256"}], "name": "transfer", "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": false, "inputs": [{"internalType": "address", "name": "sender", "type": "address"}, {"internalType": "address", "name": "recipient", "type": "address"}, {"internalType": "uint256", "name": "amount", "type": "uint256"}], "name": "transferFrom", "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "candidate", "type": "address"}], "name": "votesFor", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": false, "inputs": [], "name": "initialize", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": false, "inputs": [{"internalType": "address", "name": "implementation", "type": "address"}], "name": "implement", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function"}] \ No newline at end of file diff --git a/protocol/abi/Dollar.json b/protocol/abi/Dollar.json deleted file mode 100644 index 4095a270..00000000 --- a/protocol/abi/Dollar.json +++ /dev/null @@ -1 +0,0 @@ -[{"inputs": [], "payable": false, "stateMutability": "nonpayable", "type": "constructor"}, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "owner", "type": "address"}, {"indexed": true, "internalType": "address", "name": "spender", "type": "address"}, {"indexed": false, "internalType": "uint256", "name": "value", "type": "uint256"}], "name": "Approval", "type": "event"}, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "account", "type": "address"}], "name": "MinterAdded", "type": "event"}, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "account", "type": "address"}], "name": "MinterRemoved", "type": "event"}, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "from", "type": "address"}, {"indexed": true, "internalType": "address", "name": "to", "type": "address"}, {"indexed": false, "internalType": "uint256", "name": "value", "type": "uint256"}], "name": "Transfer", "type": "event"}, {"constant": true, "inputs": [], "name": "EIP712_DOMAIN_SEPARATOR", "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "EIP712_PERMIT_TYPEHASH", "outputs": [{"internalType": "bytes32", "name": "", "type": "bytes32"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": false, "inputs": [{"internalType": "address", "name": "account", "type": "address"}], "name": "addMinter", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "owner", "type": "address"}, {"internalType": "address", "name": "spender", "type": "address"}], "name": "allowance", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": false, "inputs": [{"internalType": "address", "name": "spender", "type": "address"}, {"internalType": "uint256", "name": "amount", "type": "uint256"}], "name": "approve", "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "account", "type": "address"}], "name": "balanceOf", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": false, "inputs": [{"internalType": "uint256", "name": "amount", "type": "uint256"}], "name": "burn", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": false, "inputs": [{"internalType": "address", "name": "account", "type": "address"}, {"internalType": "uint256", "name": "amount", "type": "uint256"}], "name": "burnFrom", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": true, "inputs": [], "name": "decimals", "outputs": [{"internalType": "uint8", "name": "", "type": "uint8"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": false, "inputs": [{"internalType": "address", "name": "spender", "type": "address"}, {"internalType": "uint256", "name": "subtractedValue", "type": "uint256"}], "name": "decreaseAllowance", "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": false, "inputs": [{"internalType": "address", "name": "spender", "type": "address"}, {"internalType": "uint256", "name": "addedValue", "type": "uint256"}], "name": "increaseAllowance", "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "account", "type": "address"}], "name": "isMinter", "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "name", "outputs": [{"internalType": "string", "name": "", "type": "string"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": false, "inputs": [{"internalType": "address", "name": "owner", "type": "address"}, {"internalType": "address", "name": "spender", "type": "address"}, {"internalType": "uint256", "name": "value", "type": "uint256"}, {"internalType": "uint256", "name": "deadline", "type": "uint256"}, {"internalType": "uint8", "name": "v", "type": "uint8"}, {"internalType": "bytes32", "name": "r", "type": "bytes32"}, {"internalType": "bytes32", "name": "s", "type": "bytes32"}], "name": "permit", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": false, "inputs": [], "name": "renounceMinter", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": true, "inputs": [], "name": "symbol", "outputs": [{"internalType": "string", "name": "", "type": "string"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "totalSupply", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": false, "inputs": [{"internalType": "address", "name": "recipient", "type": "address"}, {"internalType": "uint256", "name": "amount", "type": "uint256"}], "name": "transfer", "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": false, "inputs": [{"internalType": "address", "name": "account", "type": "address"}, {"internalType": "uint256", "name": "amount", "type": "uint256"}], "name": "mint", "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": false, "inputs": [{"internalType": "address", "name": "sender", "type": "address"}, {"internalType": "address", "name": "recipient", "type": "address"}, {"internalType": "uint256", "name": "amount", "type": "uint256"}], "name": "transferFrom", "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "payable": false, "stateMutability": "nonpayable", "type": "function"}] \ No newline at end of file diff --git a/protocol/abi/Implementation.json b/protocol/abi/Implementation.json deleted file mode 100644 index 891b2acf..00000000 --- a/protocol/abi/Implementation.json +++ /dev/null @@ -1 +0,0 @@ -[{"anonymous": false, "inputs": [{"indexed": true, "internalType": "uint256", "name": "epoch", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "block", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "timestamp", "type": "uint256"}], "name": "Advance", "type": "event"}, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "account", "type": "address"}, {"indexed": false, "internalType": "uint256", "name": "start", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "value", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "valueUnderlying", "type": "uint256"}], "name": "Bond", "type": "event"}, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "account", "type": "address"}, {"indexed": true, "internalType": "address", "name": "candidate", "type": "address"}], "name": "Commit", "type": "event"}, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "owner", "type": "address"}, {"indexed": true, "internalType": "address", "name": "spender", "type": "address"}, {"indexed": false, "internalType": "uint256", "name": "value", "type": "uint256"}], "name": "CouponApproval", "type": "event"}, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "uint256", "name": "epoch", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "couponsExpired", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "lessRedeemable", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "lessDebt", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "newBonded", "type": "uint256"}], "name": "CouponExpiration", "type": "event"}, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "account", "type": "address"}, {"indexed": true, "internalType": "uint256", "name": "epoch", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "dollarAmount", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "couponAmount", "type": "uint256"}], "name": "CouponPurchase", "type": "event"}, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "account", "type": "address"}, {"indexed": true, "internalType": "uint256", "name": "epoch", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "couponAmount", "type": "uint256"}], "name": "CouponRedemption", "type": "event"}, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "from", "type": "address"}, {"indexed": true, "internalType": "address", "name": "to", "type": "address"}, {"indexed": true, "internalType": "uint256", "name": "epoch", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "value", "type": "uint256"}], "name": "CouponTransfer", "type": "event"}, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "account", "type": "address"}, {"indexed": false, "internalType": "uint256", "name": "value", "type": "uint256"}], "name": "Deposit", "type": "event"}, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "account", "type": "address"}, {"indexed": false, "internalType": "uint256", "name": "amount", "type": "uint256"}], "name": "Incentivization", "type": "event"}, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "candidate", "type": "address"}, {"indexed": true, "internalType": "address", "name": "account", "type": "address"}, {"indexed": true, "internalType": "uint256", "name": "start", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "period", "type": "uint256"}], "name": "Proposal", "type": "event"}, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "uint256", "name": "epoch", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "price", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "newDebt", "type": "uint256"}], "name": "SupplyDecrease", "type": "event"}, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "uint256", "name": "epoch", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "price", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "newRedeemable", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "lessDebt", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "newBonded", "type": "uint256"}], "name": "SupplyIncrease", "type": "event"}, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "uint256", "name": "epoch", "type": "uint256"}], "name": "SupplyNeutral", "type": "event"}, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "account", "type": "address"}, {"indexed": false, "internalType": "uint256", "name": "start", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "value", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "valueUnderlying", "type": "uint256"}], "name": "Unbond", "type": "event"}, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "implementation", "type": "address"}], "name": "Upgraded", "type": "event"}, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "account", "type": "address"}, {"indexed": true, "internalType": "address", "name": "candidate", "type": "address"}, {"indexed": false, "internalType": "enum Candidate.Vote", "name": "vote", "type": "uint8"}, {"indexed": false, "internalType": "uint256", "name": "bonded", "type": "uint256"}], "name": "Vote", "type": "event"}, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "account", "type": "address"}, {"indexed": false, "internalType": "uint256", "name": "value", "type": "uint256"}], "name": "Withdraw", "type": "event"}, {"constant": true, "inputs": [{"internalType": "address", "name": "owner", "type": "address"}, {"internalType": "address", "name": "spender", "type": "address"}], "name": "allowance", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "owner", "type": "address"}, {"internalType": "address", "name": "spender", "type": "address"}], "name": "allowanceCoupons", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": false, "inputs": [{"internalType": "address", "name": "spender", "type": "address"}, {"internalType": "uint256", "name": "amount", "type": "uint256"}], "name": "approve", "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": false, "inputs": [{"internalType": "address", "name": "spender", "type": "address"}, {"internalType": "uint256", "name": "amount", "type": "uint256"}], "name": "approveCoupons", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "candidate", "type": "address"}], "name": "approveFor", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "account", "type": "address"}], "name": "balanceOf", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "account", "type": "address"}], "name": "balanceOfBonded", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "account", "type": "address"}, {"internalType": "uint256", "name": "epoch", "type": "uint256"}], "name": "balanceOfCoupons", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "account", "type": "address"}], "name": "balanceOfStaged", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": false, "inputs": [{"internalType": "uint256", "name": "value", "type": "uint256"}], "name": "bond", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": true, "inputs": [{"internalType": "uint256", "name": "epoch", "type": "uint256"}], "name": "bootstrappingAt", "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": false, "inputs": [{"internalType": "address", "name": "candidate", "type": "address"}], "name": "commit", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": true, "inputs": [{"internalType": "uint256", "name": "amount", "type": "uint256"}], "name": "couponPremium", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "uint256", "name": "epoch", "type": "uint256"}], "name": "couponsExpiration", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "decimals", "outputs": [{"internalType": "uint8", "name": "", "type": "uint8"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": false, "inputs": [{"internalType": "uint256", "name": "value", "type": "uint256"}], "name": "deposit", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": true, "inputs": [], "name": "dollar", "outputs": [{"internalType": "contract IDollar", "name": "", "type": "address"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "epoch", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "epochPeriod", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "epochStart", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "epochTime", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "uint256", "name": "epoch", "type": "uint256"}], "name": "expiringCoupons", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "uint256", "name": "epoch", "type": "uint256"}, {"internalType": "uint256", "name": "i", "type": "uint256"}], "name": "expiringCouponsAtIndex", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "implementation", "outputs": [{"internalType": "address", "name": "impl", "type": "address"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "candidate", "type": "address"}], "name": "isInitialized", "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "candidate", "type": "address"}], "name": "isNominated", "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "name", "outputs": [{"internalType": "string", "name": "", "type": "string"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "oracle", "outputs": [{"internalType": "contract IOracle", "name": "", "type": "address"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "uint256", "name": "epoch", "type": "uint256"}], "name": "outstandingCoupons", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "candidate", "type": "address"}], "name": "periodFor", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "pool", "outputs": [{"internalType": "address", "name": "", "type": "address"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": false, "inputs": [{"internalType": "uint256", "name": "dollarAmount", "type": "uint256"}], "name": "purchaseCoupons", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "account", "type": "address"}, {"internalType": "address", "name": "candidate", "type": "address"}], "name": "recordedVote", "outputs": [{"internalType": "enum Candidate.Vote", "name": "", "type": "uint8"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": false, "inputs": [{"internalType": "uint256", "name": "epoch", "type": "uint256"}, {"internalType": "uint256", "name": "couponAmount", "type": "uint256"}], "name": "redeemCoupons", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "candidate", "type": "address"}], "name": "rejectFor", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "candidate", "type": "address"}], "name": "startFor", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "account", "type": "address"}], "name": "statusOf", "outputs": [{"internalType": "enum Account.Status", "name": "", "type": "uint8"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "symbol", "outputs": [{"internalType": "string", "name": "", "type": "string"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "totalBonded", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "uint256", "name": "epoch", "type": "uint256"}], "name": "totalBondedAt", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "totalCoupons", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "totalDebt", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "totalNet", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "totalRedeemable", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "totalStaged", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "totalSupply", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": false, "inputs": [{"internalType": "address", "name": "recipient", "type": "address"}, {"internalType": "uint256", "name": "amount", "type": "uint256"}], "name": "transfer", "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": false, "inputs": [{"internalType": "address", "name": "sender", "type": "address"}, {"internalType": "address", "name": "recipient", "type": "address"}, {"internalType": "uint256", "name": "epoch", "type": "uint256"}, {"internalType": "uint256", "name": "amount", "type": "uint256"}], "name": "transferCoupons", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": false, "inputs": [{"internalType": "address", "name": "sender", "type": "address"}, {"internalType": "address", "name": "recipient", "type": "address"}, {"internalType": "uint256", "name": "amount", "type": "uint256"}], "name": "transferFrom", "outputs": [{"internalType": "bool", "name": "", "type": "bool"}], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": false, "inputs": [{"internalType": "uint256", "name": "value", "type": "uint256"}], "name": "unbond", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": false, "inputs": [{"internalType": "uint256", "name": "value", "type": "uint256"}], "name": "unbondUnderlying", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": false, "inputs": [{"internalType": "address", "name": "candidate", "type": "address"}, {"internalType": "enum Candidate.Vote", "name": "vote", "type": "uint8"}], "name": "vote", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "candidate", "type": "address"}], "name": "votesFor", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": false, "inputs": [{"internalType": "uint256", "name": "value", "type": "uint256"}], "name": "withdraw", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": false, "inputs": [], "name": "initialize", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": false, "inputs": [], "name": "advance", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function"}] \ No newline at end of file diff --git a/protocol/abi/Pool.json b/protocol/abi/Pool.json deleted file mode 100644 index 14b1f3b7..00000000 --- a/protocol/abi/Pool.json +++ /dev/null @@ -1 +0,0 @@ -[{"inputs": [{"internalType": "address", "name": "dollar", "type": "address"}, {"internalType": "address", "name": "univ2", "type": "address"}], "payable": false, "stateMutability": "nonpayable", "type": "constructor"}, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "account", "type": "address"}, {"indexed": false, "internalType": "uint256", "name": "start", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "value", "type": "uint256"}], "name": "Bond", "type": "event"}, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "account", "type": "address"}, {"indexed": false, "internalType": "uint256", "name": "value", "type": "uint256"}], "name": "Claim", "type": "event"}, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "account", "type": "address"}, {"indexed": false, "internalType": "uint256", "name": "value", "type": "uint256"}], "name": "Deposit", "type": "event"}, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "account", "type": "address"}, {"indexed": false, "internalType": "uint256", "name": "value", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "lessUsdc", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "newUniv2", "type": "uint256"}], "name": "Provide", "type": "event"}, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "account", "type": "address"}, {"indexed": false, "internalType": "uint256", "name": "start", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "value", "type": "uint256"}, {"indexed": false, "internalType": "uint256", "name": "newClaimable", "type": "uint256"}], "name": "Unbond", "type": "event"}, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "account", "type": "address"}, {"indexed": false, "internalType": "uint256", "name": "value", "type": "uint256"}], "name": "Withdraw", "type": "event"}, {"constant": true, "inputs": [{"internalType": "address", "name": "account", "type": "address"}], "name": "balanceOfBonded", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "account", "type": "address"}], "name": "balanceOfClaimable", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "account", "type": "address"}], "name": "balanceOfPhantom", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "account", "type": "address"}], "name": "balanceOfRewarded", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "account", "type": "address"}], "name": "balanceOfStaged", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "dao", "outputs": [{"internalType": "contract IDAO", "name": "", "type": "address"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "dollar", "outputs": [{"internalType": "contract IDollar", "name": "", "type": "address"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [{"internalType": "address", "name": "account", "type": "address"}], "name": "statusOf", "outputs": [{"internalType": "enum PoolAccount.Status", "name": "", "type": "uint8"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "totalBonded", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "totalClaimable", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "totalPhantom", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "totalRewarded", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "totalStaged", "outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": true, "inputs": [], "name": "univ2", "outputs": [{"internalType": "contract IERC20", "name": "", "type": "address"}], "payable": false, "stateMutability": "view", "type": "function"}, {"constant": false, "inputs": [{"internalType": "uint256", "name": "value", "type": "uint256"}], "name": "deposit", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": false, "inputs": [{"internalType": "uint256", "name": "value", "type": "uint256"}], "name": "withdraw", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": false, "inputs": [{"internalType": "uint256", "name": "value", "type": "uint256"}], "name": "claim", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": false, "inputs": [{"internalType": "uint256", "name": "value", "type": "uint256"}], "name": "bond", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": false, "inputs": [{"internalType": "uint256", "name": "value", "type": "uint256"}], "name": "unbond", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function"}, {"constant": false, "inputs": [{"internalType": "uint256", "name": "value", "type": "uint256"}], "name": "provide", "outputs": [], "payable": false, "stateMutability": "nonpayable", "type": "function"}] \ No newline at end of file diff --git a/protocol/abi/Root.json b/protocol/abi/Root.json deleted file mode 100644 index ffc59ec9..00000000 --- a/protocol/abi/Root.json +++ /dev/null @@ -1 +0,0 @@ -[{"inputs": [{"internalType": "address", "name": "implementation", "type": "address"}], "payable": false, "stateMutability": "nonpayable", "type": "constructor"}, {"anonymous": false, "inputs": [{"indexed": true, "internalType": "address", "name": "implementation", "type": "address"}], "name": "Upgraded", "type": "event"}, {"payable": true, "stateMutability": "payable", "type": "fallback"}] \ No newline at end of file diff --git a/protocol/contracts/Constants.sol b/protocol/contracts/Constants.sol index 26ef83a4..71ee1bb6 100644 --- a/protocol/contracts/Constants.sol +++ b/protocol/contracts/Constants.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,16 +24,15 @@ library Constants { uint256 private constant CHAIN_ID = 1; // Mainnet /* Bootstrapping */ - uint256 private constant BOOTSTRAPPING_PERIOD = 90; - uint256 private constant BOOTSTRAPPING_PRICE = 11e17; // 1.10 USDC - uint256 private constant BOOTSTRAPPING_SPEEDUP_FACTOR = 3; // 30 days @ 8 hours + uint256 private constant BOOTSTRAPPING_PERIOD = 240; // 10 days with 1h per epoch + uint256 private constant BOOTSTRAPPING_PRICE = 148e16; // 1.48 USDC /* Oracle */ address private constant USDC = address(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48); uint256 private constant ORACLE_RESERVE_MINIMUM = 1e10; // 10,000 USDC /* Bonding */ - uint256 private constant INITIAL_STAKE_MULTIPLE = 1e6; // 100 ESD -> 100M ESDS + uint256 private constant INITIAL_STAKE_MULTIPLE = 1e6; // 100 U8D -> 100M U8DS /* Epoch */ struct EpochStrategy { @@ -42,45 +41,49 @@ library Constants { uint256 period; } - uint256 private constant PREVIOUS_EPOCH_OFFSET = 91; - uint256 private constant PREVIOUS_EPOCH_START = 1600905600; - uint256 private constant PREVIOUS_EPOCH_PERIOD = 86400; - - uint256 private constant CURRENT_EPOCH_OFFSET = 106; - uint256 private constant CURRENT_EPOCH_START = 1602201600; - uint256 private constant CURRENT_EPOCH_PERIOD = 28800; + uint256 private constant EPOCH_OFFSET = 0; + uint256 private constant EPOCH_START = 1611360000; // 01/23/2021 @ 12:00am (UTC) + uint256 private constant EPOCH_PERIOD = 1 hours; /* Governance */ - uint256 private constant GOVERNANCE_PERIOD = 9; // 9 epochs - uint256 private constant GOVERNANCE_EXPIRATION = 2; // 2 + 1 epochs + uint256 private constant GOVERNANCE_PERIOD = 24; // 24 epochs + uint256 private constant GOVERNANCE_EXPIRATION = 16; // 16 + 1 epochs uint256 private constant GOVERNANCE_QUORUM = 20e16; // 20% - uint256 private constant GOVERNANCE_PROPOSAL_THRESHOLD = 5e15; // 0.5% - uint256 private constant GOVERNANCE_SUPER_MAJORITY = 40e16; // 40% - uint256 private constant GOVERNANCE_EMERGENCY_DELAY = 6; // 6 epochs + uint256 private constant GOVERNANCE_PROPOSAL_THRESHOLD = 1e16; // 1% + uint256 private constant GOVERNANCE_SUPER_MAJORITY = 66e16; // 66% + uint256 private constant GOVERNANCE_EMERGENCY_DELAY = 12; // 12 epochs /* DAO */ - uint256 private constant ADVANCE_INCENTIVE = 1e21; // 1000 ESD - uint256 private constant DAO_EXIT_LOCKUP_EPOCHS = 15; // 15 epochs fluid + uint256 private constant ADVANCE_INCENTIVE_USD = 70e18; // 70 USD + uint256 private constant ADVANCE_MAX_INCENTIVE = 200e18; // 200 U8D + uint256 private constant DAO_EXIT_STREAM_PERIOD = 120 hours; // 5 days of DAO streaming + + uint256 private constant DAO_EXIT_MAX_BOOST = uint256(-1); // infinity - without max boost + uint256 private constant DAO_EXIT_BOOST_COEFFICIENT = 200e16; // 200% (x2) – DAO boosting coefficient for fast streaming + uint256 private constant DAO_EXIT_BOOST_PENALTY = 25e16; // 25% – penalty for DAO stream boosting /* Pool */ - uint256 private constant POOL_EXIT_LOCKUP_EPOCHS = 5; // 5 epochs fluid + uint256 private constant POOL_LP_EXIT_STREAM_PERIOD = 72 hours; // 3 days of Pool LP streaming + uint256 private constant POOL_REWARD_EXIT_STREAM_PERIOD = 72 hours; // 3 days of Pool Reward streaming + + uint256 private constant POOL_EXIT_MAX_BOOST = uint256(-1); // infinity - without max boost + uint256 private constant POOL_EXIT_BOOST_COEFFICIENT = 200e16; // 200% (x2) – Pool boosting coefficient for fast streaming + uint256 private constant POOL_EXIT_BOOST_PENALTY = 25e16; // 25% – penalty for Pool stream boosting /* Market */ - uint256 private constant COUPON_EXPIRATION = 90; + uint256 private constant COUPON_EXPIRATION = 720; uint256 private constant DEBT_RATIO_CAP = 20e16; // 20% - uint256 private constant COUPON_PRORATED_START = 420; // epoch 420 /* Regulator */ uint256 private constant SUPPLY_CHANGE_LIMIT = 3e16; // 3% + uint256 private constant SUPPLY_CHANGE_DIVISOR = 48e18; // 48 uint256 private constant COUPON_SUPPLY_CHANGE_LIMIT = 6e16; // 6% - uint256 private constant ORACLE_POOL_RATIO = 20; // 20% - uint256 private constant TREASURY_RATIO = 250; // 2.5% + uint256 private constant NEGATIVE_SUPPLY_CHANGE_DIVISOR = 12e18; // 12 + uint256 private constant ORACLE_POOL_RATIO = 30; // 30% + uint256 private constant TREASURY_RATIO = 0; // 0% - /* Deployed */ - address private constant DAO_ADDRESS = address(0x443D2f2755DB5942601fa062Cc248aAA153313D3); - address private constant DOLLAR_ADDRESS = address(0x36F3FD68E7325a35EB768F1AedaAe9EA0689d723); - address private constant PAIR_ADDRESS = address(0x88ff79eB2Bc5850F27315415da8685282C7610F9); - address private constant TREASURY_ADDRESS = address(0x460661bd4A5364A3ABCc9cfc4a8cE7038d05Ea22); + /* Not used */ + address private constant TREASURY_ADDRESS = address(0); // no treasury address /** * Getters @@ -94,19 +97,11 @@ library Constants { return ORACLE_RESERVE_MINIMUM; } - function getPreviousEpochStrategy() internal pure returns (EpochStrategy memory) { + function getEpochStrategy() internal pure returns (EpochStrategy memory) { return EpochStrategy({ - offset: PREVIOUS_EPOCH_OFFSET, - start: PREVIOUS_EPOCH_START, - period: PREVIOUS_EPOCH_PERIOD - }); - } - - function getCurrentEpochStrategy() internal pure returns (EpochStrategy memory) { - return EpochStrategy({ - offset: CURRENT_EPOCH_OFFSET, - start: CURRENT_EPOCH_START, - period: CURRENT_EPOCH_PERIOD + offset: EPOCH_OFFSET, + start: EPOCH_START, + period: EPOCH_PERIOD }); } @@ -122,10 +117,6 @@ library Constants { return Decimal.D256({value: BOOTSTRAPPING_PRICE}); } - function getBootstrappingSpeedupFactor() internal pure returns (uint256) { - return BOOTSTRAPPING_SPEEDUP_FACTOR; - } - function getGovernancePeriod() internal pure returns (uint256) { return GOVERNANCE_PERIOD; } @@ -150,16 +141,52 @@ library Constants { return GOVERNANCE_EMERGENCY_DELAY; } - function getAdvanceIncentive() internal pure returns (uint256) { - return ADVANCE_INCENTIVE; + function getAdvanceIncentiveUsd() internal pure returns (uint256) { + return ADVANCE_INCENTIVE_USD; } - function getDAOExitLockupEpochs() internal pure returns (uint256) { - return DAO_EXIT_LOCKUP_EPOCHS; + function getAdvanceMaxIncentive() internal pure returns (uint256) { + return ADVANCE_MAX_INCENTIVE; } - function getPoolExitLockupEpochs() internal pure returns (uint256) { - return POOL_EXIT_LOCKUP_EPOCHS; + /* DAO */ + + function getDAOExitStreamPeriod() internal pure returns (uint256) { + return DAO_EXIT_STREAM_PERIOD; + } + + function getDAOExitMaxBoost() internal pure returns (uint256) { + return DAO_EXIT_MAX_BOOST; + } + + function getDAOExitBoostCoefficient() internal pure returns (Decimal.D256 memory) { + return Decimal.D256({value: DAO_EXIT_BOOST_COEFFICIENT}); + } + + function getDAOExitBoostPenalty() internal pure returns (Decimal.D256 memory) { + return Decimal.D256({value: DAO_EXIT_BOOST_PENALTY}); + } + + /* Pool */ + + function getPoolLpExitStreamPeriod() internal pure returns (uint256) { + return POOL_LP_EXIT_STREAM_PERIOD; + } + + function getPoolRewardExitStreamPeriod() internal pure returns (uint256) { + return POOL_REWARD_EXIT_STREAM_PERIOD; + } + + function getPoolExitMaxBoost() internal pure returns (uint256) { + return POOL_EXIT_MAX_BOOST; + } + + function getPoolExitBoostCoefficient() internal pure returns (Decimal.D256 memory) { + return Decimal.D256({value: POOL_EXIT_BOOST_COEFFICIENT}); + } + + function getPoolExitBoostPenalty() internal pure returns (Decimal.D256 memory) { + return Decimal.D256({value: POOL_EXIT_BOOST_PENALTY}); } function getCouponExpiration() internal pure returns (uint256) { @@ -170,18 +197,22 @@ library Constants { return Decimal.D256({value: DEBT_RATIO_CAP}); } - function getCouponProratedStart() internal pure returns (uint256) { - return COUPON_PRORATED_START; - } - function getSupplyChangeLimit() internal pure returns (Decimal.D256 memory) { return Decimal.D256({value: SUPPLY_CHANGE_LIMIT}); } + function getSupplyChangeDivisor() internal pure returns (Decimal.D256 memory) { + return Decimal.D256({value: SUPPLY_CHANGE_DIVISOR}); + } + function getCouponSupplyChangeLimit() internal pure returns (Decimal.D256 memory) { return Decimal.D256({value: COUPON_SUPPLY_CHANGE_LIMIT}); } + function getNegativeSupplyChangeDivisor() internal pure returns (Decimal.D256 memory) { + return Decimal.D256({value: NEGATIVE_SUPPLY_CHANGE_DIVISOR}); + } + function getOraclePoolRatio() internal pure returns (uint256) { return ORACLE_POOL_RATIO; } @@ -194,18 +225,6 @@ library Constants { return CHAIN_ID; } - function getDaoAddress() internal pure returns (address) { - return DAO_ADDRESS; - } - - function getDollarAddress() internal pure returns (address) { - return DOLLAR_ADDRESS; - } - - function getPairAddress() internal pure returns (address) { - return PAIR_ADDRESS; - } - function getTreasuryAddress() internal pure returns (address) { return TREASURY_ADDRESS; } diff --git a/protocol/contracts/dao/Bonding.sol b/protocol/contracts/dao/Bonding.sol index e154741c..45bafa0b 100644 --- a/protocol/contracts/dao/Bonding.sol +++ b/protocol/contracts/dao/Bonding.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -29,9 +29,15 @@ contract Bonding is Setters, Permission { bytes32 private constant FILE = "Bonding"; event Deposit(address indexed account, uint256 value); - event Withdraw(address indexed account, uint256 value); - event Bond(address indexed account, uint256 start, uint256 value, uint256 valueUnderlying); - event Unbond(address indexed account, uint256 start, uint256 value, uint256 valueUnderlying); + event Release(address indexed account, uint256 value); + event Bond(address indexed account, uint256 value, uint256 valueUnderlying); + event Unbond(address indexed account, uint256 value, uint256 valueUnderlying); + + // Streaming + event StreamStart(address indexed account, uint256 value, uint256 streamedUntil); + event StreamCancel(address indexed account, uint256 valueToStaged); + event StreamBoost(address indexed account, uint256 penalty); + event UnstreamToStaged(address indexed account, uint256 value); function step() internal { Require.that( @@ -44,22 +50,106 @@ contract Bonding is Setters, Permission { incrementEpoch(); } - function deposit(uint256 value) external onlyFrozenOrLocked(msg.sender) { + function deposit(uint256 value) public { dollar().transferFrom(msg.sender, address(this), value); incrementBalanceOfStaged(msg.sender, value); emit Deposit(msg.sender, value); } - function withdraw(uint256 value) external onlyFrozenOrLocked(msg.sender) { - dollar().transfer(msg.sender, value); + // ** NEW LOGIC ** + + function depositAndBond(uint256 value) external { + deposit(value); + bond(value); + } + + function startStream(uint256 value) external { + require(value > 0, "Bonding: must stream non-zero amount"); + + cancelStream(); decrementBalanceOfStaged(msg.sender, value, "Bonding: insufficient staged balance"); + setStream(stream(msg.sender), value, Constants.getDAOExitStreamPeriod()); + + emit StreamStart(msg.sender, value, streamedUntil(msg.sender)); + } + + function cancelStream() public { + // already canceled or not exist + if (streamReserved(msg.sender) == 0) { + return; + } + + release(); + uint256 amountToStaged = unreleasedAmount(msg.sender); + incrementBalanceOfStaged(msg.sender, amountToStaged); + resetStream(stream(msg.sender)); + + emit StreamCancel(msg.sender, amountToStaged); + } + + // Virtual – overridable for the distribution of penalty + function boostStream() public returns (uint256) { + require(streamBoosted(msg.sender) < Constants.getDAOExitMaxBoost(), "Bonding: max boost reached"); + + release(); + + uint256 unreleased = unreleasedAmount(msg.sender); + uint256 penalty = Decimal.from(unreleased) + .mul(Constants.getDAOExitBoostPenalty()) + .asUint256(); + uint256 timeleft = Decimal.from(streamedUntil(msg.sender).sub(blockTimestamp())) + .div(Constants.getDAOExitBoostCoefficient()) + .asUint256(); - emit Withdraw(msg.sender, value); + setStream( + stream(msg.sender), + unreleased.sub(penalty), + timeleft + ); + incrementBoostCounter(stream(msg.sender)); + + dollar().burn(penalty); + + emit StreamBoost(msg.sender, penalty); + + return penalty; + } + + function release() public { + uint256 unreleased = releasableAmount(msg.sender); + + if (unreleased == 0) { + return; + } + + incrementReleased(stream(msg.sender), unreleased); + dollar().transfer(msg.sender, unreleased); + + emit Release(msg.sender, unreleased); } - function bond(uint256 value) external onlyFrozenOrFluid(msg.sender) { - unfreeze(msg.sender); + // ** END NEW LOGIC ** + + function bond(uint256 value) public onlyUnlocked(msg.sender) { + // partially unstream and bond + uint256 staged = balanceOfStaged(msg.sender); + if (value > staged) { + release(); + + uint256 amountToUnstream = value.sub(staged); + uint256 newReserved = unreleasedAmount(msg.sender).sub(amountToUnstream, "Bonding: insufficient balance"); + if (newReserved > 0) { + setStream( + stream(msg.sender), + newReserved, + streamTimeleft(msg.sender) + ); + incrementBalanceOfStaged(msg.sender, amountToUnstream); + + emit UnstreamToStaged(msg.sender, amountToUnstream); + } + } uint256 balance = totalBonded() == 0 ? value.mul(Constants.getInitialStakeMultiple()) : @@ -68,28 +158,24 @@ contract Bonding is Setters, Permission { incrementTotalBonded(value); decrementBalanceOfStaged(msg.sender, value, "Bonding: insufficient staged balance"); - emit Bond(msg.sender, epoch().add(1), balance, value); + emit Bond(msg.sender, balance, value); } - function unbond(uint256 value) external onlyFrozenOrFluid(msg.sender) { - unfreeze(msg.sender); - + function unbond(uint256 value) external onlyUnlocked(msg.sender) { uint256 staged = value.mul(balanceOfBonded(msg.sender)).div(balanceOf(msg.sender)); incrementBalanceOfStaged(msg.sender, staged); decrementTotalBonded(staged, "Bonding: insufficient total bonded"); decrementBalanceOf(msg.sender, value, "Bonding: insufficient balance"); - emit Unbond(msg.sender, epoch().add(1), value, staged); + emit Unbond(msg.sender, value, staged); } - function unbondUnderlying(uint256 value) external onlyFrozenOrFluid(msg.sender) { - unfreeze(msg.sender); - + function unbondUnderlying(uint256 value) external onlyUnlocked(msg.sender) { uint256 balance = value.mul(totalSupply()).div(totalBonded()); incrementBalanceOfStaged(msg.sender, value); decrementTotalBonded(value, "Bonding: insufficient total bonded"); decrementBalanceOf(msg.sender, balance, "Bonding: insufficient balance"); - emit Unbond(msg.sender, epoch().add(1), balance, value); + emit Unbond(msg.sender, balance, value); } } diff --git a/protocol/contracts/dao/Comptroller.sol b/protocol/contracts/dao/Comptroller.sol index 27899ccb..f6a05df6 100644 --- a/protocol/contracts/dao/Comptroller.sol +++ b/protocol/contracts/dao/Comptroller.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -43,12 +43,9 @@ contract Comptroller is Setters { balanceCheck(); } - function redeemToAccount(address account, uint256 amount, uint256 couponAmount) internal { - dollar().mint(account, amount); - if (couponAmount != 0) { - dollar().transfer(account, couponAmount); - decrementTotalRedeemable(couponAmount, "Comptroller: not enough redeemable balance"); - } + function redeemToAccount(address account, uint256 amount) internal { + dollar().transfer(account, amount); + decrementTotalRedeemable(amount, "Comptroller: not enough redeemable balance"); balanceCheck(); } diff --git a/protocol/contracts/dao/Curve.sol b/protocol/contracts/dao/Curve.sol index b853e137..39e2acf8 100644 --- a/protocol/contracts/dao/Curve.sol +++ b/protocol/contracts/dao/Curve.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/protocol/contracts/dao/Getters.sol b/protocol/contracts/dao/Getters.sol index ff1f29fe..b7c2eef6 100644 --- a/protocol/contracts/dao/Getters.sol +++ b/protocol/contracts/dao/Getters.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -20,8 +20,9 @@ pragma experimental ABIEncoderV2; import "@openzeppelin/contracts/math/SafeMath.sol"; import "./State.sol"; import "../Constants.sol"; +import "../streaming/StreamingGetters.sol"; -contract Getters is State { +contract Getters is State, StreamingGetters { using SafeMath for uint256; using Decimal for Decimal.D256; @@ -32,11 +33,11 @@ contract Getters is State { */ function name() public view returns (string memory) { - return "Empty Set Dollar Stake"; + return "Universal Dollar Stake"; } function symbol() public view returns (string memory) { - return "ESDS"; + return "U8DS"; } function decimals() public view returns (uint8) { @@ -87,10 +88,6 @@ contract Getters is State { return _state.balance.redeemable; } - function totalCouponUnderlying() public view returns (uint256) { - return _state16.couponUnderlying; - } - function totalCoupons() public view returns (uint256) { return _state.balance.coupons; } @@ -99,14 +96,6 @@ contract Getters is State { return dollar().totalSupply().sub(totalDebt()); } - function eraStatus() public view returns (Era.Status) { - return _state18.era.status; - } - - function eraStart() public view returns (uint256) { - return _state18.era.start; - } - /** * Account */ @@ -130,28 +119,57 @@ contract Getters is State { return _state.accounts[account].coupons[epoch]; } - function balanceOfCouponUnderlying(address account, uint256 epoch) public view returns (uint256) { - return _state16.couponUnderlyingByAccount[account][epoch]; + function statusOf(address account) public view returns (Account.Status) { + return _state.accounts[account].lockedUntil > epoch() ? Account.Status.Locked : Account.Status.Unlocked; } - function statusOf(address account) public view returns (Account.Status) { - if (_state.accounts[account].lockedUntil > epoch()) { - return Account.Status.Locked; - } + function allowanceCoupons(address owner, address spender) public view returns (uint256) { + return _state.accounts[owner].couponAllowances[spender]; + } + + /** + * Streaming + */ - return epoch() >= _state.accounts[account].fluidUntil ? Account.Status.Frozen : Account.Status.Fluid; + // internal getter + function stream(address account) internal view returns (Stream storage) { + return _state.accounts[account].stream; } - function fluidUntil(address account) public view returns (uint256) { - return _state.accounts[account].fluidUntil; + function streamedFrom(address account) public view returns (uint256) { + return streamedFrom(stream(account)); } - function lockedUntil(address account) public view returns (uint256) { - return _state.accounts[account].lockedUntil; + function streamedUntil(address account) public view returns (uint256) { + return streamedUntil(stream(account)); } - function allowanceCoupons(address owner, address spender) public view returns (uint256) { - return _state.accounts[owner].couponAllowances[spender]; + function streamDuration(address account) public view returns (uint256) { + return streamDuration(stream(account)); + } + + function streamTimeleft(address account) public view returns (uint256) { + return streamTimeleft(stream(account)); + } + + function streamReserved(address account) public view returns (uint256) { + return streamReserved(stream(account)); + } + + function streamReleased(address account) public view returns (uint256) { + return streamReleased(stream(account)); + } + + function streamBoosted(address account) public view returns (uint256) { + return streamBoosted(stream(account)); + } + + function releasableAmount(address account) public view returns (uint256) { + return releasableAmount(stream(account)); + } + + function unreleasedAmount(address account) public view returns (uint256) { + return unreleasedAmount(stream(account)); } /** @@ -163,12 +181,8 @@ contract Getters is State { } function epochTime() public view returns (uint256) { - Constants.EpochStrategy memory current = Constants.getCurrentEpochStrategy(); - Constants.EpochStrategy memory previous = Constants.getPreviousEpochStrategy(); - - return blockTimestamp() < current.start ? - epochTimeWithStrategy(previous) : - epochTimeWithStrategy(current); + Constants.EpochStrategy memory current = Constants.getEpochStrategy(); + return epochTimeWithStrategy(current); } function epochTimeWithStrategy(Constants.EpochStrategy memory strategy) private view returns (uint256) { diff --git a/protocol/contracts/dao/Govern.sol b/protocol/contracts/dao/Govern.sol index 67656a7f..2252658d 100644 --- a/protocol/contracts/dao/Govern.sol +++ b/protocol/contracts/dao/Govern.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -35,7 +35,7 @@ contract Govern is Setters, Permission, Upgradeable { event Vote(address indexed account, address indexed candidate, Candidate.Vote vote, uint256 bonded); event Commit(address indexed account, address indexed candidate); - function vote(address candidate, Candidate.Vote vote) external onlyFrozenOrLocked(msg.sender) { + function vote(address candidate, Candidate.Vote vote) external { Require.that( balanceOf(msg.sender) > 0, FILE, diff --git a/protocol/contracts/dao/Implementation.sol b/protocol/contracts/dao/Implementation.sol index e812a9ba..37feb3dc 100644 --- a/protocol/contracts/dao/Implementation.sol +++ b/protocol/contracts/dao/Implementation.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,6 +23,7 @@ import "./Regulator.sol"; import "./Bonding.sol"; import "./Govern.sol"; import "../Constants.sol"; +import "../oracle/IPool.sol"; contract Implementation is State, Bonding, Market, Regulator, Govern { using SafeMath for uint256; @@ -31,22 +32,44 @@ contract Implementation is State, Bonding, Market, Regulator, Govern { event Incentivization(address indexed account, uint256 amount); function initialize() initializer public { - // Reward committer - incentivize(msg.sender, Constants.getAdvanceIncentive()); - // Dev rewards - + // upgrade pool + IPool(pool()).upgrade(0x64c8A67Da288C1332F3eFA672c3588D9905218B2); } function advance() external { - incentivize(msg.sender, Constants.getAdvanceIncentive()); + Decimal.D256 memory price = oracleCapture(); + + uint256 incentive = Decimal.from(Constants.getAdvanceIncentiveUsd()) + .div(price) + .asUint256(); + uint256 maxIncentive = Constants.getAdvanceMaxIncentive(); + incentive = (incentive < maxIncentive) ? incentive : maxIncentive; + + incentivize(msg.sender, incentive); Bonding.step(); - Regulator.step(); + Regulator.step(price); Market.step(); emit Advance(epoch(), block.number, block.timestamp); } + // Override for the distribution of penalty + function boostStream() public returns (uint256) { + uint256 penalty = Bonding.boostStream(); + + // distribute penalty if more than one dollar + distribute(penalty); + + return penalty; + } + + // Distribution of penalty from Pool contract + function distributePenalty(uint256 penalty) external onlyPool { + // distribute penalty if more than one dollar + distribute(penalty); + } + function incentivize(address account, uint256 amount) private { mintToAccount(account, amount); emit Incentivization(account, amount); diff --git a/protocol/contracts/dao/Market.sol b/protocol/contracts/dao/Market.sol index e4330aff..15b79a4a 100644 --- a/protocol/contracts/dao/Market.sol +++ b/protocol/contracts/dao/Market.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -29,7 +29,7 @@ contract Market is Comptroller, Curve { event CouponExpiration(uint256 indexed epoch, uint256 couponsExpired, uint256 lessRedeemable, uint256 lessDebt, uint256 newBonded); event CouponPurchase(address indexed account, uint256 indexed epoch, uint256 dollarAmount, uint256 couponAmount); - event CouponRedemption(address indexed account, uint256 indexed epoch, uint256 amount, uint256 couponAmount); + event CouponRedemption(address indexed account, uint256 indexed epoch, uint256 couponAmount); event CouponTransfer(address indexed from, address indexed to, uint256 indexed epoch, uint256 value); event CouponApproval(address indexed owner, address indexed spender, uint256 value); @@ -52,7 +52,6 @@ contract Market is Comptroller, Curve { uint256 totalRedeemable = totalRedeemable(); uint256 totalCoupons = totalCoupons(); - if (totalRedeemable > totalCoupons) { lessRedeemable = totalRedeemable.sub(totalCoupons); burnRedeemable(lessRedeemable); @@ -66,84 +65,35 @@ contract Market is Comptroller, Curve { return calculateCouponPremium(dollar().totalSupply(), totalDebt(), amount); } - function migrateCoupons(uint256 couponEpoch) external { - uint256 balanceOfCoupons = balanceOfCoupons(msg.sender, couponEpoch); - require(balanceOfCoupons > 0, "Market: No coupons"); - require(balanceOfCouponUnderlying(msg.sender, couponEpoch) == 0, "Market: Already migrated"); - - uint256 couponUnderlying = balanceOfCoupons.div(2); - - incrementBalanceOfCouponUnderlying(msg.sender, couponEpoch, couponUnderlying); - decrementBalanceOfCoupons(msg.sender, couponEpoch, couponUnderlying, "Market: Insufficient coupon balance"); - - emit CouponRedemption(msg.sender, couponEpoch, 0, couponUnderlying); - emit CouponPurchase(msg.sender, couponEpoch, couponUnderlying, 0); - } - - function purchaseCoupons(uint256 amount) external returns (uint256) { + function purchaseCoupons(uint256 dollarAmount) external returns (uint256) { Require.that( - amount > 0, + dollarAmount > 0, FILE, "Must purchase non-zero amount" ); Require.that( - totalDebt() >= amount, + totalDebt() >= dollarAmount, FILE, "Not enough debt" ); uint256 epoch = epoch(); - uint256 couponAmount = couponPremium(amount); + uint256 couponAmount = dollarAmount.add(couponPremium(dollarAmount)); + burnFromAccount(msg.sender, dollarAmount); incrementBalanceOfCoupons(msg.sender, epoch, couponAmount); - incrementBalanceOfCouponUnderlying(msg.sender, epoch, amount); - - burnFromAccount(msg.sender, amount); - emit CouponPurchase(msg.sender, epoch, amount, couponAmount); + emit CouponPurchase(msg.sender, epoch, dollarAmount, couponAmount); return couponAmount; } - // @notice: logic overview - // 1) Coupons just purchased will fail at 2 epoch check. - // 2) Valid coupons without sufficient redeemable will fail at redeemToAccount. - // 3) Expired coupons will result in zero couponAmount, passing decrementBalanceOfCoupons - // and redeemToAccount to return underlying only. - // 4) Expired coupons with future redeemable will still result in zero couponAmount, - // allowing only underlying to be redeemed. - function redeemCoupons(uint256 couponEpoch, uint256 amount) external { + function redeemCoupons(uint256 couponEpoch, uint256 couponAmount) external { require(epoch().sub(couponEpoch) >= 2, "Market: Too early to redeem"); - require(amount != 0, "Market: Amount too low"); - - uint256 couponAmount = balanceOfCoupons(msg.sender, couponEpoch) - .mul(amount).div(balanceOfCouponUnderlying(msg.sender, couponEpoch), "Market: No underlying"); - uint256 redeemableAmount = computeRedeemable(couponEpoch, couponAmount); - - decrementBalanceOfCouponUnderlying(msg.sender, couponEpoch, amount, "Market: Insufficient coupon underlying balance"); - if (couponAmount != 0) decrementBalanceOfCoupons(msg.sender, couponEpoch, couponAmount, "Market: Insufficient coupon balance"); - redeemToAccount(msg.sender, amount, redeemableAmount); - - emit CouponRedemption(msg.sender, couponEpoch, amount, couponAmount); - } - - function computeRedeemable(uint256 couponEpoch, uint256 couponAmount) private view returns (uint256) { - if (couponEpoch < couponProratedStart()) { - return couponAmount; - } - - uint256 lastContractionEpoch = computeLastContractionEpoch(); - uint256 lockedTime = lastContractionEpoch > couponEpoch ? lastContractionEpoch.sub(couponEpoch) : 0; - lockedTime = lockedTime > Constants.getCouponExpiration() ? Constants.getCouponExpiration() : lockedTime; - return couponAmount.mul(lockedTime).div(Constants.getCouponExpiration()); - } + decrementBalanceOfCoupons(msg.sender, couponEpoch, couponAmount, "Market: Insufficient coupon balance"); + redeemToAccount(msg.sender, couponAmount); - function computeLastContractionEpoch() private view returns (uint256) { - if (eraStatus() == Era.Status.EXPANSION) { - uint256 eraStart = eraStart(); - return eraStart == 0 ? 0 : eraStart.sub(1); - } - return epoch().sub(1); + emit CouponRedemption(msg.sender, couponEpoch, couponAmount); } function approveCoupons(address spender, uint256 amount) external { @@ -158,14 +108,8 @@ contract Market is Comptroller, Curve { require(sender != address(0), "Market: Coupon transfer from the zero address"); require(recipient != address(0), "Market: Coupon transfer to the zero address"); - uint256 couponAmount = balanceOfCoupons(sender, epoch) - .mul(amount).div(balanceOfCouponUnderlying(sender, epoch), "Market: No underlying"); - - decrementBalanceOfCouponUnderlying(sender, epoch, amount, "Market: Insufficient coupon underlying balance"); - incrementBalanceOfCouponUnderlying(recipient, epoch, amount); - - decrementBalanceOfCoupons(sender, epoch, couponAmount, "Market: Insufficient coupon balance"); - incrementBalanceOfCoupons(recipient, epoch, couponAmount); + decrementBalanceOfCoupons(sender, epoch, amount, "Market: Insufficient coupon balance"); + incrementBalanceOfCoupons(recipient, epoch, amount); if (msg.sender != sender && allowanceCoupons(sender, msg.sender) != uint256(-1)) { decrementAllowanceCoupons(sender, msg.sender, amount, "Market: Insufficient coupon approval"); @@ -173,9 +117,4 @@ contract Market is Comptroller, Curve { emit CouponTransfer(sender, recipient, epoch, amount); } - - // overridable for testing - function couponProratedStart() internal view returns (uint256) { - return Constants.getCouponProratedStart(); - } } diff --git a/protocol/contracts/dao/Permission.sol b/protocol/contracts/dao/Permission.sol index c1dd6fd5..18ba2bdc 100644 --- a/protocol/contracts/dao/Permission.sol +++ b/protocol/contracts/dao/Permission.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,23 +24,22 @@ contract Permission is Setters { bytes32 private constant FILE = "Permission"; - // Can modify account state - modifier onlyFrozenOrFluid(address account) { + modifier onlyPool() { Require.that( - statusOf(account) != Account.Status.Locked, + msg.sender == address(pool()), FILE, - "Not frozen or fluid" + "Not pool" ); _; } - // Can participate in balance-dependant activities - modifier onlyFrozenOrLocked(address account) { + // Can modify account state + modifier onlyUnlocked(address account) { Require.that( - statusOf(account) != Account.Status.Fluid, + statusOf(account) != Account.Status.Locked, FILE, - "Not frozen or locked" + "Not unlocked" ); _; diff --git a/protocol/contracts/dao/Regulator.sol b/protocol/contracts/dao/Regulator.sol index 97671cf8..3a234c1a 100644 --- a/protocol/contracts/dao/Regulator.sol +++ b/protocol/contracts/dao/Regulator.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -30,17 +30,18 @@ contract Regulator is Comptroller { event SupplyDecrease(uint256 indexed epoch, uint256 price, uint256 newDebt); event SupplyNeutral(uint256 indexed epoch); - function step() internal { - Decimal.D256 memory price = oracleCapture(); + event PenaltyDistribute(uint256 indexed epoch, uint256 price, uint256 newRedeemable, uint256 lessDebt, uint256 newBonded); + + function step(Decimal.D256 memory price) internal { + // logic moved to advance() + // Decimal.D256 memory price = oracleCapture(); if (price.greaterThan(Decimal.one())) { - if (eraStatus() == Era.Status.CONTRACTION) updateEra(Era.Status.EXPANSION); growSupply(price); return; } if (price.lessThan(Decimal.one())) { - if (eraStatus() == Era.Status.EXPANSION) updateEra(Era.Status.CONTRACTION); shrinkSupply(price); return; } @@ -48,8 +49,30 @@ contract Regulator is Comptroller { emit SupplyNeutral(epoch()); } + function oracleCapture() internal returns (Decimal.D256 memory) { + (Decimal.D256 memory price, bool valid) = oracle().capture(); + + if (bootstrappingAt(epoch().sub(1))) { + return Constants.getBootstrappingPrice(); + } + if (!valid) { + return Decimal.one(); + } + + return price; + } + + function distribute(uint256 amount) internal { + Decimal.D256 memory price = oracleCapture(); + if (price.greaterThan(Decimal.one())) { + uint256 lessDebt = resetDebt(Decimal.zero()); + (uint256 newRedeemable, uint256 newBonded) = increaseSupply(amount); + emit PenaltyDistribute(epoch(), price.value, newRedeemable, lessDebt, newBonded); + } + } + function shrinkSupply(Decimal.D256 memory price) private { - Decimal.D256 memory delta = limit(Decimal.one().sub(price), price); + Decimal.D256 memory delta = limit(Decimal.one().sub(price).div(Constants.getNegativeSupplyChangeDivisor()), price); uint256 newDebt = delta.mul(totalNet()).asUint256(); uint256 cappedNewDebt = increaseDebt(newDebt); @@ -60,14 +83,13 @@ contract Regulator is Comptroller { function growSupply(Decimal.D256 memory price) private { uint256 lessDebt = resetDebt(Decimal.zero()); - Decimal.D256 memory delta = limit(price.sub(Decimal.one()), price); + Decimal.D256 memory delta = limit(price.sub(Decimal.one()).div(Constants.getSupplyChangeDivisor()), price); uint256 newSupply = delta.mul(totalNet()).asUint256(); (uint256 newRedeemable, uint256 newBonded) = increaseSupply(newSupply); emit SupplyIncrease(epoch(), price.value, newRedeemable, lessDebt, newBonded); } function limit(Decimal.D256 memory delta, Decimal.D256 memory price) private view returns (Decimal.D256 memory) { - Decimal.D256 memory supplyChangeLimit = Constants.getSupplyChangeLimit(); uint256 totalRedeemable = totalRedeemable(); @@ -77,19 +99,5 @@ contract Regulator is Comptroller { } return delta.greaterThan(supplyChangeLimit) ? supplyChangeLimit : delta; - - } - - function oracleCapture() private returns (Decimal.D256 memory) { - (Decimal.D256 memory price, bool valid) = oracle().capture(); - - if (bootstrappingAt(epoch().sub(1))) { - return Constants.getBootstrappingPrice(); - } - if (!valid) { - return Decimal.one(); - } - - return price; } } diff --git a/protocol/contracts/dao/Root.sol b/protocol/contracts/dao/Root.sol index 69edc2cc..ee725a4d 100644 --- a/protocol/contracts/dao/Root.sol +++ b/protocol/contracts/dao/Root.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/protocol/contracts/dao/Setters.sol b/protocol/contracts/dao/Setters.sol index 176c8cda..0bc1abf0 100644 --- a/protocol/contracts/dao/Setters.sol +++ b/protocol/contracts/dao/Setters.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -20,8 +20,9 @@ pragma experimental ABIEncoderV2; import "@openzeppelin/contracts/math/SafeMath.sol"; import "./State.sol"; import "./Getters.sol"; +import "../streaming/StreamingSetters.sol"; -contract Setters is State, Getters { +contract Setters is State, Getters, StreamingSetters { using SafeMath for uint256; event Transfer(address indexed from, address indexed to, uint256 value); @@ -70,11 +71,6 @@ contract Setters is State, Getters { _state.balance.redeemable = _state.balance.redeemable.sub(amount, reason); } - function updateEra(Era.Status status) internal { - _state18.era.status = status; - _state18.era.start = epoch(); - } - /** * Account */ @@ -109,26 +105,12 @@ contract Setters is State, Getters { _state.balance.coupons = _state.balance.coupons.add(amount); } - function incrementBalanceOfCouponUnderlying(address account, uint256 epoch, uint256 amount) internal { - _state16.couponUnderlyingByAccount[account][epoch] = _state16.couponUnderlyingByAccount[account][epoch].add(amount); - _state16.couponUnderlying = _state16.couponUnderlying.add(amount); - } - function decrementBalanceOfCoupons(address account, uint256 epoch, uint256 amount, string memory reason) internal { _state.accounts[account].coupons[epoch] = _state.accounts[account].coupons[epoch].sub(amount, reason); _state.epochs[epoch].coupons.outstanding = _state.epochs[epoch].coupons.outstanding.sub(amount, reason); _state.balance.coupons = _state.balance.coupons.sub(amount, reason); } - function decrementBalanceOfCouponUnderlying(address account, uint256 epoch, uint256 amount, string memory reason) internal { - _state16.couponUnderlyingByAccount[account][epoch] = _state16.couponUnderlyingByAccount[account][epoch].sub(amount, reason); - _state16.couponUnderlying = _state16.couponUnderlying.sub(amount, reason); - } - - function unfreeze(address account) internal { - _state.accounts[account].fluidUntil = epoch().add(Constants.getDAOExitLockupEpochs()); - } - function updateAllowanceCoupons(address owner, address spender, uint256 amount) internal { _state.accounts[owner].couponAllowances[spender] = amount; } diff --git a/protocol/contracts/dao/State.sol b/protocol/contracts/dao/State.sol index 1a91d34f..6a5c1b94 100644 --- a/protocol/contracts/dao/State.sol +++ b/protocol/contracts/dao/State.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -21,11 +21,11 @@ import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol'; import "../token/IDollar.sol"; import "../oracle/IOracle.sol"; import "../external/Decimal.sol"; +import "../streaming/Stream.sol"; contract Account { enum Status { - Frozen, - Fluid, + Unlocked, Locked } @@ -34,8 +34,8 @@ contract Account { uint256 balance; mapping(uint256 => uint256) coupons; mapping(address => uint256) couponAllowances; - uint256 fluidUntil; uint256 lockedUntil; + Stream.Stream stream; } } @@ -75,18 +75,6 @@ contract Candidate { } } -contract Era { - enum Status { - EXPANSION, - CONTRACTION - } - - struct State { - Status status; - uint256 start; - } -} - contract Storage { struct Provider { IDollar dollar; @@ -112,23 +100,8 @@ contract Storage { mapping(uint256 => Epoch.State) epochs; mapping(address => Candidate.State) candidates; } - - struct State16 { - mapping(address => mapping(uint256 => uint256)) couponUnderlyingByAccount; - uint256 couponUnderlying; - } - - struct State18 { - Era.State era; - } } contract State { Storage.State _state; - - // EIP-16 - Storage.State16 _state16; - - // EIP-18 - Storage.State18 _state18; } diff --git a/protocol/contracts/dao/Upgradeable.sol b/protocol/contracts/dao/Upgradeable.sol index 5b981ae9..144ba3cf 100644 --- a/protocol/contracts/dao/Upgradeable.sol +++ b/protocol/contracts/dao/Upgradeable.sol @@ -1,6 +1,6 @@ /* Copyright 2018-2019 zOS Global Limited - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/protocol/contracts/deployment/Deployer.sol b/protocol/contracts/deployment/Deployer.sol new file mode 100644 index 00000000..5b512524 --- /dev/null +++ b/protocol/contracts/deployment/Deployer.sol @@ -0,0 +1,88 @@ +/* + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +pragma solidity ^0.5.17; +pragma experimental ABIEncoderV2; + +import "../external/Decimal.sol"; +import "../token/Dollar.sol"; +import "../oracle/Oracle.sol"; +import "../oracle/Pool.sol"; +import "../dao/Upgradeable.sol"; +import "../dao/Permission.sol"; +import "../dao/Root.sol"; + + +contract DollarFactory { + function getCreationBytecode() private pure returns (bytes memory) { + bytes memory bytecode = type(Dollar).creationCode; + return abi.encodePacked(bytecode); + } + + function deployDollar(bytes32 salt) internal returns (address) { + bytes memory bytecode = getCreationBytecode(); + address addr; + assembly { + addr := create2(0, add(bytecode, 0x20), mload(bytecode), salt) + + if iszero(extcodesize(addr)) { + revert(0, 0) + } + } + + return addr; + } +} + +contract Deployer1 is State, Permission, Upgradeable, DollarFactory { + function initialize() initializer public { + bytes32 salt = 0x0000000000000000000000000000000000000000000000000000000000b9c7be; + _state.provider.dollar = Dollar(deployDollar(salt)); + } + + function implement(address implementation) external { + upgradeTo(implementation); + } +} + +contract Deployer2 is State, Permission, Upgradeable { + function initialize() initializer public { + _state.provider.oracle = new Oracle(address(dollar())); + oracle().setup(); + } + + function implement(address implementation) external { + upgradeTo(implementation); + } +} + +contract Deployer3 is State, Permission, Upgradeable { + event PoolDeployed(address proxy, address implementation); + + function initialize() initializer public { + address poolImplementation = address(new Pool()); + address pool = address(new Root(poolImplementation)); + Pool(pool).initialize(address(this), address(dollar()), address(oracle().pair())); + + _state.provider.pool = pool; + + emit PoolDeployed(pool, poolImplementation); + } + + function implement(address implementation) external { + upgradeTo(implementation); + } +} \ No newline at end of file diff --git a/protocol/contracts/external/Decimal.sol b/protocol/contracts/external/Decimal.sol index 5046beb5..60fde57a 100644 --- a/protocol/contracts/external/Decimal.sol +++ b/protocol/contracts/external/Decimal.sol @@ -1,6 +1,6 @@ /* Copyright 2019 dYdX Trading Inc. - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/protocol/contracts/external/UniswapV2Library.sol b/protocol/contracts/external/UniswapV2Library.sol index 1c8a7626..d8e51dc8 100644 --- a/protocol/contracts/external/UniswapV2Library.sol +++ b/protocol/contracts/external/UniswapV2Library.sol @@ -37,4 +37,14 @@ library UniswapV2Library { require(reserveA > 0 && reserveB > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY'); amountB = amountA.mul(reserveB) / reserveA; } + + // given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset + function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) internal pure returns (uint amountOut) { + require(amountIn > 0, 'UniswapV2Library: INSUFFICIENT_INPUT_AMOUNT'); + require(reserveIn > 0 && reserveOut > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY'); + uint amountInWithFee = amountIn.mul(997); + uint numerator = amountInWithFee.mul(reserveOut); + uint denominator = reserveIn.mul(1000).add(amountInWithFee); + amountOut = numerator / denominator; + } } \ No newline at end of file diff --git a/protocol/contracts/mock/MockBonding.sol b/protocol/contracts/mock/MockBonding.sol index 4ed82d0a..4508e7f2 100644 --- a/protocol/contracts/mock/MockBonding.sol +++ b/protocol/contracts/mock/MockBonding.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/protocol/contracts/mock/MockComptroller.sol b/protocol/contracts/mock/MockComptroller.sol index 336050c1..5174d6f7 100644 --- a/protocol/contracts/mock/MockComptroller.sol +++ b/protocol/contracts/mock/MockComptroller.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -35,8 +35,8 @@ contract MockComptroller is Comptroller, MockState { super.burnFromAccount(account, amount); } - function redeemToAccountE(address account, uint256 amount, uint256 couponAmount) external { - super.redeemToAccount(account, amount, couponAmount); + function redeemToAccountE(address account, uint256 amount) external { + super.redeemToAccount(account, amount); } function burnRedeemableE(uint256 amount) external { diff --git a/protocol/contracts/mock/MockCurve.sol b/protocol/contracts/mock/MockCurve.sol index af757bb3..e387177a 100644 --- a/protocol/contracts/mock/MockCurve.sol +++ b/protocol/contracts/mock/MockCurve.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/protocol/contracts/mock/MockGovern.sol b/protocol/contracts/mock/MockGovern.sol index d48c70fd..d795f56d 100644 --- a/protocol/contracts/mock/MockGovern.sol +++ b/protocol/contracts/mock/MockGovern.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/protocol/contracts/mock/MockImplA.sol b/protocol/contracts/mock/MockImplA.sol index f0b6a7ca..fdc1c824 100644 --- a/protocol/contracts/mock/MockImplA.sol +++ b/protocol/contracts/mock/MockImplA.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/protocol/contracts/mock/MockImplB.sol b/protocol/contracts/mock/MockImplB.sol index bdd3cc7c..3731e50c 100644 --- a/protocol/contracts/mock/MockImplB.sol +++ b/protocol/contracts/mock/MockImplB.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/protocol/contracts/mock/MockMarket.sol b/protocol/contracts/mock/MockMarket.sol index 3d450506..0790ad8c 100644 --- a/protocol/contracts/mock/MockMarket.sol +++ b/protocol/contracts/mock/MockMarket.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,19 +22,9 @@ import "./MockState.sol"; import "./MockComptroller.sol"; contract MockMarket is MockState, MockComptroller, Market { - uint256 private _couponProratedStart; - constructor(address pool) MockComptroller(pool) public { } function stepE() external { Market.step(); } - - function set(uint256 newCouponProratedStart) external { - _couponProratedStart = newCouponProratedStart; - } - - function couponProratedStart() internal view returns (uint256) { - return _couponProratedStart; - } } diff --git a/protocol/contracts/mock/MockOracle.sol b/protocol/contracts/mock/MockOracle.sol index f8f47fdd..829ef4e8 100644 --- a/protocol/contracts/mock/MockOracle.sol +++ b/protocol/contracts/mock/MockOracle.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/protocol/contracts/mock/MockPool.sol b/protocol/contracts/mock/MockPool.sol index 56f76501..6760c733 100644 --- a/protocol/contracts/mock/MockPool.sol +++ b/protocol/contracts/mock/MockPool.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -25,7 +25,8 @@ contract MockPool is Pool { address private _dollar; address private _univ2; - constructor(address usdc) Pool() public { + constructor(address dollar, address usdc, address univ2) public { + initialize(msg.sender, dollar, univ2); _usdc = usdc; } diff --git a/protocol/contracts/mock/MockPoolState.sol b/protocol/contracts/mock/MockPoolState.sol index 7077a68d..56baf92c 100644 --- a/protocol/contracts/mock/MockPoolState.sol +++ b/protocol/contracts/mock/MockPoolState.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -72,7 +72,7 @@ contract MockPoolState is PoolSetters { super.decrementBalanceOfPhantom(account, amount, reason); } - function unfreezeE(address account) external { - super.unfreeze(account); - } + // function unfreezeE(address account) external { + // super.unfreeze(account); + // } } diff --git a/protocol/contracts/mock/MockRegulator.sol b/protocol/contracts/mock/MockRegulator.sol index d8787664..d02db5d7 100644 --- a/protocol/contracts/mock/MockRegulator.sol +++ b/protocol/contracts/mock/MockRegulator.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -28,7 +28,8 @@ contract MockRegulator is MockComptroller, Regulator { } function stepE() external { - super.step(); + Decimal.D256 memory price = oracleCapture(); + super.step(price); } function bootstrappingAt(uint256 epoch) public view returns (bool) { diff --git a/protocol/contracts/mock/MockSettableDAO.sol b/protocol/contracts/mock/MockSettableDAO.sol index c31473ce..3ecf6af7 100644 --- a/protocol/contracts/mock/MockSettableDAO.sol +++ b/protocol/contracts/mock/MockSettableDAO.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/protocol/contracts/mock/MockSettableOracle.sol b/protocol/contracts/mock/MockSettableOracle.sol index 916372d0..b31d40b4 100644 --- a/protocol/contracts/mock/MockSettableOracle.sol +++ b/protocol/contracts/mock/MockSettableOracle.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/protocol/contracts/mock/MockState.sol b/protocol/contracts/mock/MockState.sol index e7a8d9f7..3682ee2f 100644 --- a/protocol/contracts/mock/MockState.sol +++ b/protocol/contracts/mock/MockState.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -54,10 +54,6 @@ contract MockState is Setters { super.decrementTotalRedeemable(amount, reason); } - function updateEraE(Era.Status status) external { - super.updateEra(status); - } - /** * Account */ @@ -82,21 +78,13 @@ contract MockState is Setters { super.incrementBalanceOfCoupons(account, epoch, amount); } - function incrementBalanceOfCouponUnderlyingE(address account, uint256 epoch, uint256 amount) external { - super.incrementBalanceOfCouponUnderlying(account, epoch, amount); - } - function decrementBalanceOfCouponsE(address account, uint256 epoch, uint256 amount, string calldata reason) external { super.decrementBalanceOfCoupons(account, epoch, amount, reason); } - function decrementBalanceOfCouponUnderlyingE(address account, uint256 epoch, uint256 amount, string calldata reason) external { - super.decrementBalanceOfCouponUnderlying(account, epoch, amount, reason); - } - - function unfreezeE(address account) external { - super.unfreeze(account); - } + // function unfreezeE(address account) external { + // super.unfreeze(account); + // } function updateAllowanceCouponsE(address owner, address spender, uint256 amount) external { super.updateAllowanceCoupons(owner, spender, amount); diff --git a/protocol/contracts/mock/MockToken.sol b/protocol/contracts/mock/MockToken.sol index a2926dda..66ea8f6a 100644 --- a/protocol/contracts/mock/MockToken.sol +++ b/protocol/contracts/mock/MockToken.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/protocol/contracts/mock/MockUSDC.sol b/protocol/contracts/mock/MockUSDC.sol index b97571f4..2a4dd32a 100644 --- a/protocol/contracts/mock/MockUSDC.sol +++ b/protocol/contracts/mock/MockUSDC.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/protocol/contracts/mock/MockUniswapV2PairLiquidity.sol b/protocol/contracts/mock/MockUniswapV2PairLiquidity.sol index 61ceaf81..7ac23923 100644 --- a/protocol/contracts/mock/MockUniswapV2PairLiquidity.sol +++ b/protocol/contracts/mock/MockUniswapV2PairLiquidity.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/protocol/contracts/mock/MockUniswapV2PairTrade.sol b/protocol/contracts/mock/MockUniswapV2PairTrade.sol index 226b28f7..dece6530 100644 --- a/protocol/contracts/mock/MockUniswapV2PairTrade.sol +++ b/protocol/contracts/mock/MockUniswapV2PairTrade.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/protocol/contracts/mock/MockUpgradeable.sol b/protocol/contracts/mock/MockUpgradeable.sol index 2881d542..58902f4a 100644 --- a/protocol/contracts/mock/MockUpgradeable.sol +++ b/protocol/contracts/mock/MockUpgradeable.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/protocol/contracts/mock/TestnetUSDC.sol b/protocol/contracts/mock/TestnetUSDC.sol index 82f949ae..09e0833f 100644 --- a/protocol/contracts/mock/TestnetUSDC.sol +++ b/protocol/contracts/mock/TestnetUSDC.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/protocol/contracts/oracle/IDAO.sol b/protocol/contracts/oracle/IDAO.sol index b2f51133..345bace5 100644 --- a/protocol/contracts/oracle/IDAO.sol +++ b/protocol/contracts/oracle/IDAO.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,5 +17,6 @@ pragma solidity ^0.5.17; contract IDAO { + function distributePenalty(uint256 penalty) external; function epoch() external view returns (uint256); } \ No newline at end of file diff --git a/protocol/contracts/oracle/IOracle.sol b/protocol/contracts/oracle/IOracle.sol index 0703457b..a20df795 100644 --- a/protocol/contracts/oracle/IOracle.sol +++ b/protocol/contracts/oracle/IOracle.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/protocol/contracts/oracle/IPool.sol b/protocol/contracts/oracle/IPool.sol new file mode 100644 index 00000000..a1451912 --- /dev/null +++ b/protocol/contracts/oracle/IPool.sol @@ -0,0 +1,21 @@ +/* + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +pragma solidity ^0.5.17; + +contract IPool { + function upgrade(address newPoolImplementation) external; +} \ No newline at end of file diff --git a/protocol/contracts/oracle/IUSDC.sol b/protocol/contracts/oracle/IUSDC.sol index 9ab31e71..da08cf11 100644 --- a/protocol/contracts/oracle/IUSDC.sol +++ b/protocol/contracts/oracle/IUSDC.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/protocol/contracts/oracle/Liquidity.sol b/protocol/contracts/oracle/Liquidity.sol index ee6400f4..f9b57ea5 100644 --- a/protocol/contracts/oracle/Liquidity.sol +++ b/protocol/contracts/oracle/Liquidity.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -40,6 +40,36 @@ contract Liquidity is PoolGetters { return (usdcAmount, IUniswapV2Pair(pair).mint(address(this))); } + function convertLpToDollar(uint256 liquidity) internal returns (uint256) { + (uint256 dollarAmount, uint256 usdcAmount) = removeLiquidity(liquidity); + return dollarAmount.add(swap(usdcAmount, usdc(), address(dollar()))); + } + + function removeLiquidity(uint256 liquidity) internal returns (uint256 dollarAmount, uint256 usdcAmount) { + address pair = address(univ2()); + + univ2().transfer(pair, liquidity); // send liquidity to pair + (uint256 amount0, uint256 amount1) = IUniswapV2Pair(pair).burn(address(this)); + + (address dollar, address usdc) = (address(dollar()), usdc()); + (address token0,) = UniswapV2Library.sortTokens(dollar, usdc); + (dollarAmount, usdcAmount) = dollar == token0 ? (amount0, amount1) : (amount1, amount0); + } + + function swap(uint256 amountIn, address tokenIn, address tokenOut) internal returns (uint256 amountOut) { + (uint256 reserveIn, uint256 reserveOut) = getReserves(tokenIn, tokenOut); + amountOut = UniswapV2Library.getAmountOut(amountIn, reserveIn, reserveOut); + + (address token0,) = UniswapV2Library.sortTokens(tokenIn, tokenOut); + (uint amount0Out, uint amount1Out) = tokenIn == token0 ? (uint(0), amountOut) : (amountOut, uint(0)); + + address pair = UniswapV2Library.pairFor(UNISWAP_FACTORY, tokenIn, tokenOut); + IERC20(tokenIn).transfer(pair, amountIn); + IUniswapV2Pair(pair).swap( + amount0Out, amount1Out, address(this), new bytes(0) + ); + } + // overridable for testing function getReserves(address tokenA, address tokenB) internal view returns (uint reserveA, uint reserveB) { (address token0,) = UniswapV2Library.sortTokens(tokenA, tokenB); diff --git a/protocol/contracts/oracle/Oracle.sol b/protocol/contracts/oracle/Oracle.sol index 1dd624ed..b3936bbf 100644 --- a/protocol/contracts/oracle/Oracle.sol +++ b/protocol/contracts/oracle/Oracle.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/protocol/contracts/oracle/Pool.sol b/protocol/contracts/oracle/Pool.sol index 01a5a242..50d0e5b3 100644 --- a/protocol/contracts/oracle/Pool.sol +++ b/protocol/contracts/oracle/Pool.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -23,22 +23,41 @@ import "../external/Require.sol"; import "../Constants.sol"; import "./PoolSetters.sol"; import "./Liquidity.sol"; +import "./PoolUpgradable.sol"; -contract Pool is PoolSetters, Liquidity { +contract Pool is PoolSetters, Liquidity, PoolUpgradable { using SafeMath for uint256; - constructor() public { } + function initialize(address dao, address dollar, address univ2) public { + require(!_state.isInitialized, "Pool: already initialized"); + _state.isInitialized = true; + + _state.provider.dao = IDAO(dao); + _state.provider.dollar = IDollar(dollar); + _state.provider.univ2 = IERC20(univ2); + } bytes32 private constant FILE = "Pool"; event Deposit(address indexed account, uint256 value); - event Withdraw(address indexed account, uint256 value); - event Claim(address indexed account, uint256 value); - event Bond(address indexed account, uint256 start, uint256 value); - event Unbond(address indexed account, uint256 start, uint256 value, uint256 newClaimable); + event ReleaseLp(address indexed account, uint256 value); + event ReleaseReward(address indexed account, uint256 value); + event Bond(address indexed account, uint256 value); + event Unbond(address indexed account, uint256 value, uint256 newClaimable); event Provide(address indexed account, uint256 value, uint256 lessUsdc, uint256 newUniv2); - function deposit(uint256 value) external onlyFrozen(msg.sender) notPaused { + // Streaming LP + event StreamStartLp(address indexed account, uint256 value, uint256 streamedUntil); + event StreamCancelLp(address indexed account, uint256 valueToStaged); + event StreamBoostLp(address indexed account, uint256 penalty); + event UnstreamToStagedLp(address indexed account, uint256 value); + + // Streaming Reward + event StreamStartReward(address indexed account, uint256 value, uint256 streamedUntil); + event StreamCancelReward(address indexed account, uint256 valueToStaged); + event StreamBoostReward(address indexed account, uint256 penalty); + + function deposit(uint256 value) public notPaused { univ2().transferFrom(msg.sender, address(this), value); incrementBalanceOfStaged(msg.sender, value); @@ -47,26 +66,220 @@ contract Pool is PoolSetters, Liquidity { emit Deposit(msg.sender, value); } - function withdraw(uint256 value) external onlyFrozen(msg.sender) { - univ2().transfer(msg.sender, value); + // ** NEW LOGIC ** + + function depositAndBond(uint256 value) external { + deposit(value); + bond(value); + } + + function release() external { + releaseLp(); + releaseReward(); + } + + /** + * Streaming LP + */ + + function startLpStream(uint256 value) external { + require(value > 0, "Pool: must stream non-zero amount"); + + cancelLpStream(); decrementBalanceOfStaged(msg.sender, value, "Pool: insufficient staged balance"); + setStream(streamLp(msg.sender), value, Constants.getPoolLpExitStreamPeriod()); + + balanceCheck(); + + emit StreamStartLp(msg.sender, value, streamedLpUntil(msg.sender)); + } + + function cancelLpStream() public { + // already canceled or not exist + if (streamLpReserved(msg.sender) == 0) { + return; + } + + releaseLp(); + uint256 amountToStaged = unreleasedLpAmount(msg.sender); + incrementBalanceOfStaged(msg.sender, amountToStaged); + resetStream(streamLp(msg.sender)); + + balanceCheck(); + + emit StreamCancelLp(msg.sender, amountToStaged); + } + + function boostLpStream() external returns (uint256) { + require(streamLpBoosted(msg.sender) < Constants.getPoolExitMaxBoost(), "Pool: max boost reached"); + + releaseLp(); + + uint256 unreleasedLp = unreleasedLpAmount(msg.sender); + uint256 penaltyLp = Decimal.from(unreleasedLp) + .mul(Constants.getPoolExitBoostPenalty()) + .asUint256(); + uint256 timeleft = Decimal.from(streamedLpUntil(msg.sender).sub(blockTimestamp())) + .div(Constants.getPoolExitBoostCoefficient()) + .asUint256(); + + setStream( + streamLp(msg.sender), + unreleasedLp.sub(penaltyLp), + timeleft + ); + incrementBoostCounter(streamLp(msg.sender)); + + uint256 penalty = convertLpToDollar(penaltyLp); // remove liquidity and swap to dollar + dollar().burn(penalty); + + // distribute penalty if more than one dollar + dao().distributePenalty(penalty); + + balanceCheck(); + + emit StreamBoostLp(msg.sender, penaltyLp); + + return penaltyLp; + } + + function releaseLp() public { + uint256 unreleasedLp = releasableLpAmount(msg.sender); + + if (unreleasedLp == 0) { + return; + } + + incrementReleased(streamLp(msg.sender), unreleasedLp); + univ2().transfer(msg.sender, unreleasedLp); balanceCheck(); - emit Withdraw(msg.sender, value); + emit ReleaseLp(msg.sender, unreleasedLp); } - function claim(uint256 value) external onlyFrozen(msg.sender) { - dollar().transfer(msg.sender, value); + /** + * Streaming Reward + */ + + function startRewardStream(uint256 value) external { + require(value > 0, "Pool: must stream non-zero amount"); + + cancelRewardStream(); + decrementBalanceOfClaimable(msg.sender, value, "Pool: insufficient claimable balance"); + incrementTotalRewardStreamable(value); + + setStream(streamReward(msg.sender), value, Constants.getPoolRewardExitStreamPeriod()); balanceCheck(); - emit Claim(msg.sender, value); + emit StreamStartReward(msg.sender, value, streamedRewardUntil(msg.sender)); } - function bond(uint256 value) external notPaused { - unfreeze(msg.sender); + function cancelRewardStream() public { + // already canceled or not exist + if (streamRewardReserved(msg.sender) == 0) { + return; + } + + releaseReward(); + + uint256 amountToClaimable = unreleasedRewardAmount(msg.sender); + + // UIP-3 fix + if (streamedRewardFrom(msg.sender) >= upgradeTimestamp()) { + decrementTotalRewardStreamable(amountToClaimable, "Pool: insufficient total streamable reward"); + } + + incrementBalanceOfClaimable(msg.sender, amountToClaimable); + resetStream(streamReward(msg.sender)); + + balanceCheck(); + + emit StreamCancelReward(msg.sender, amountToClaimable); + } + + function boostRewardStream() external returns (uint256) { + require(streamRewardBoosted(msg.sender) < Constants.getPoolExitMaxBoost(), "Pool: max boost reached"); + + releaseReward(); + + uint256 unreleased = unreleasedRewardAmount(msg.sender); + uint256 penalty = Decimal.from(unreleased) + .mul(Constants.getPoolExitBoostPenalty()) + .asUint256(); + uint256 timeleft = Decimal.from(streamedRewardUntil(msg.sender).sub(blockTimestamp())) + .div(Constants.getPoolExitBoostCoefficient()) + .asUint256(); + + // UIP-3 fix + if (streamedRewardFrom(msg.sender) >= upgradeTimestamp()) { + decrementTotalRewardStreamable(penalty, "Pool: insufficient total streamable reward"); + } else { + incrementTotalRewardStreamable(unreleased.sub(penalty)); + } + + setStream( + streamReward(msg.sender), + unreleased.sub(penalty), + timeleft + ); + incrementBoostCounter(streamReward(msg.sender)); + + dollar().burn(penalty); + + // distribute penalty if more than one dollar + dao().distributePenalty(penalty); + + balanceCheck(); + + emit StreamBoostReward(msg.sender, penalty); + + return penalty; + } + + function releaseReward() public { + uint256 unreleasedReward = releasableRewardAmount(msg.sender); + + if (unreleasedReward == 0) { + return; + } + + // UIP-3 fix + if (streamedRewardFrom(msg.sender) >= upgradeTimestamp()) { + decrementTotalRewardStreamable(unreleasedReward, "Pool: insufficient total streamable reward"); + } + + incrementReleased(streamReward(msg.sender), unreleasedReward); + dollar().transfer(msg.sender, unreleasedReward); + + balanceCheck(); + + emit ReleaseReward(msg.sender, unreleasedReward); + } + + // ** END NEW LOGIC ** + + function bond(uint256 value) public notPaused { + // partially unstream LP and bond + uint256 staged = balanceOfStaged(msg.sender); + if (value > staged) { + releaseLp(); + + uint256 amountToUnstream = value.sub(staged); + uint256 newLpReserved = unreleasedLpAmount(msg.sender).sub(amountToUnstream, "Pool: insufficient balance"); + if (newLpReserved > 0) { + setStream( + streamLp(msg.sender), + newLpReserved, + streamLpTimeleft(msg.sender) + ); + incrementBalanceOfStaged(msg.sender, amountToUnstream); + + emit UnstreamToStagedLp(msg.sender, amountToUnstream); + } + } uint256 totalRewardedWithPhantom = totalRewarded().add(totalPhantom()); uint256 newPhantom = totalBonded() == 0 ? @@ -79,12 +292,10 @@ contract Pool is PoolSetters, Liquidity { balanceCheck(); - emit Bond(msg.sender, epoch().add(1), value); + emit Bond(msg.sender, value); } function unbond(uint256 value) external { - unfreeze(msg.sender); - uint256 balanceOfBonded = balanceOfBonded(msg.sender); Require.that( balanceOfBonded > 0, @@ -102,10 +313,10 @@ contract Pool is PoolSetters, Liquidity { balanceCheck(); - emit Unbond(msg.sender, epoch().add(1), value, newClaimable); + emit Unbond(msg.sender, value, newClaimable); } - function provide(uint256 value) external onlyFrozen(msg.sender) notPaused { + function provide(uint256 value) external notPaused { Require.that( totalBonded() > 0, FILE, @@ -146,6 +357,10 @@ contract Pool is PoolSetters, Liquidity { pause(); } + function upgrade(address newPoolImplementation) external onlyDao { + upgradeTo(newPoolImplementation); + } + function balanceCheck() private { Require.that( univ2().balanceOf(address(this)) >= totalStaged().add(totalBonded()), @@ -154,16 +369,6 @@ contract Pool is PoolSetters, Liquidity { ); } - modifier onlyFrozen(address account) { - Require.that( - statusOf(account) == PoolAccount.Status.Frozen, - FILE, - "Not frozen" - ); - - _; - } - modifier onlyDao() { Require.that( msg.sender == address(dao()), diff --git a/protocol/contracts/oracle/PoolGetters.sol b/protocol/contracts/oracle/PoolGetters.sol index 7fe73d86..4d2bb0ab 100644 --- a/protocol/contracts/oracle/PoolGetters.sol +++ b/protocol/contracts/oracle/PoolGetters.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -20,9 +20,11 @@ pragma experimental ABIEncoderV2; import "@openzeppelin/contracts/math/SafeMath.sol"; import "./PoolState.sol"; import "../Constants.sol"; +import "../streaming/StreamingGetters.sol"; -contract PoolGetters is PoolState { +contract PoolGetters is PoolState, StreamingGetters { using SafeMath for uint256; + using Decimal for Decimal.D256; /** * Global @@ -33,15 +35,15 @@ contract PoolGetters is PoolState { } function dao() public view returns (IDAO) { - return IDAO(Constants.getDaoAddress()); + return _state.provider.dao; } function dollar() public view returns (IDollar) { - return IDollar(Constants.getDollarAddress()); + return _state.provider.dollar; } function univ2() public view returns (IERC20) { - return IERC20(Constants.getPairAddress()); + return _state.provider.univ2; } function totalBonded() public view returns (uint256) { @@ -60,14 +62,23 @@ contract PoolGetters is PoolState { return _state.balance.phantom; } + function totalRewardStreamable() public view returns (uint256) { + return _totalRewardStreamable; + } + function totalRewarded() public view returns (uint256) { - return dollar().balanceOf(address(this)).sub(totalClaimable()); + return dollar().balanceOf(address(this)).sub(totalClaimable()).sub(totalRewardStreamable()); } function paused() public view returns (bool) { return _state.paused; } + // internal getter + function upgradeTimestamp() internal view returns (uint256) { + return _upgradeTimestamp; + } + /** * Account */ @@ -106,10 +117,94 @@ contract PoolGetters is PoolState { return 0; } - function statusOf(address account) public view returns (PoolAccount.Status) { - return epoch() >= _state.accounts[account].fluidUntil ? - PoolAccount.Status.Frozen : - PoolAccount.Status.Fluid; + /** + * Streaming LP + */ + + // internal getter + function streamLp(address account) internal view returns (Stream storage) { + return _state.accounts[account].lpStream; + } + + function streamedLpFrom(address account) public view returns (uint256) { + return streamedFrom(streamLp(account)); + } + + function streamedLpUntil(address account) public view returns (uint256) { + return streamedUntil(streamLp(account)); + } + + function streamLpDuration(address account) public view returns (uint256) { + return streamDuration(streamLp(account)); + } + + function streamLpTimeleft(address account) public view returns (uint256) { + return streamTimeleft(streamLp(account)); + } + + function streamLpReserved(address account) public view returns (uint256) { + return streamReserved(streamLp(account)); + } + + function streamLpReleased(address account) public view returns (uint256) { + return streamReleased(streamLp(account)); + } + + function streamLpBoosted(address account) public view returns (uint256) { + return streamBoosted(streamLp(account)); + } + + function releasableLpAmount(address account) public view returns (uint256) { + return releasableAmount(streamLp(account)); + } + + function unreleasedLpAmount(address account) public view returns (uint256) { + return unreleasedAmount(streamLp(account)); + } + + /** + * Streaming Reward + */ + + // internal getter + function streamReward(address account) internal view returns (Stream storage) { + return _state.accounts[account].rewardStream; + } + + function streamedRewardFrom(address account) public view returns (uint256) { + return streamedFrom(streamReward(account)); + } + + function streamedRewardUntil(address account) public view returns (uint256) { + return streamedUntil(streamReward(account)); + } + + function streamRewardDuration(address account) public view returns (uint256) { + return streamDuration(streamReward(account)); + } + + function streamRewardTimeleft(address account) public view returns (uint256) { + return streamTimeleft(streamReward(account)); + } + + function streamRewardReserved(address account) public view returns (uint256) { + return streamReserved(streamReward(account)); + } + + function streamRewardReleased(address account) public view returns (uint256) { + return streamReleased(streamReward(account)); + } + + function streamRewardBoosted(address account) public view returns (uint256) { + return streamBoosted(streamReward(account)); + } + + function releasableRewardAmount(address account) public view returns (uint256) { + return releasableAmount(streamReward(account)); + } + + function unreleasedRewardAmount(address account) public view returns (uint256) { + return unreleasedAmount(streamReward(account)); } /** @@ -119,4 +214,8 @@ contract PoolGetters is PoolState { function epoch() internal view returns (uint256) { return dao().epoch(); } + + function blockTimestamp() internal view returns (uint256) { + return block.timestamp; + } } diff --git a/protocol/contracts/oracle/PoolSetters.sol b/protocol/contracts/oracle/PoolSetters.sol index 5a66d732..cc1dc0cd 100644 --- a/protocol/contracts/oracle/PoolSetters.sol +++ b/protocol/contracts/oracle/PoolSetters.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -20,8 +20,9 @@ pragma experimental ABIEncoderV2; import "@openzeppelin/contracts/math/SafeMath.sol"; import "./PoolState.sol"; import "./PoolGetters.sol"; +import "../streaming/StreamingSetters.sol"; -contract PoolSetters is PoolState, PoolGetters { +contract PoolSetters is PoolState, PoolGetters, StreamingSetters { using SafeMath for uint256; /** @@ -32,6 +33,18 @@ contract PoolSetters is PoolState, PoolGetters { _state.paused = true; } + function setUpgradeTimestamp() internal { + _upgradeTimestamp = blockTimestamp(); + } + + function incrementTotalRewardStreamable(uint256 amount) internal { + _totalRewardStreamable = _totalRewardStreamable.add(amount); + } + + function decrementTotalRewardStreamable(uint256 amount, string memory reason) internal { + _totalRewardStreamable = _totalRewardStreamable.sub(amount, reason); + } + /** * Account */ @@ -75,8 +88,4 @@ contract PoolSetters is PoolState, PoolGetters { _state.accounts[account].phantom = _state.accounts[account].phantom.sub(amount, reason); _state.balance.phantom = _state.balance.phantom.sub(amount, reason); } - - function unfreeze(address account) internal { - _state.accounts[account].fluidUntil = epoch().add(Constants.getPoolExitLockupEpochs()); - } } diff --git a/protocol/contracts/oracle/PoolState.sol b/protocol/contracts/oracle/PoolState.sol index 3ecf2a03..8e5681c8 100644 --- a/protocol/contracts/oracle/PoolState.sol +++ b/protocol/contracts/oracle/PoolState.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -21,24 +21,26 @@ import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "../token/IDollar.sol"; import "./IDAO.sol"; import "./IUSDC.sol"; +import "../streaming/Stream.sol"; contract PoolAccount { - enum Status { - Frozen, - Fluid, - Locked - } - struct State { uint256 staged; uint256 claimable; uint256 bonded; uint256 phantom; - uint256 fluidUntil; + Stream.Stream lpStream; + Stream.Stream rewardStream; } } contract PoolStorage { + struct Provider { + IDAO dao; + IDollar dollar; + IERC20 univ2; + } + struct Balance { uint256 staged; uint256 claimable; @@ -48,7 +50,10 @@ contract PoolStorage { struct State { Balance balance; + Provider provider; + bool paused; + bool isInitialized; mapping(address => PoolAccount.State) accounts; } @@ -56,4 +61,7 @@ contract PoolStorage { contract PoolState { PoolStorage.State _state; + + uint256 _totalRewardStreamable; + uint256 _upgradeTimestamp; } diff --git a/protocol/contracts/oracle/PoolUpgradable.sol b/protocol/contracts/oracle/PoolUpgradable.sol new file mode 100644 index 00000000..605cc99d --- /dev/null +++ b/protocol/contracts/oracle/PoolUpgradable.sol @@ -0,0 +1,68 @@ +/* + Copyright 2018-2019 zOS Global Limited + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +pragma solidity ^0.5.17; +pragma experimental ABIEncoderV2; + +import "@openzeppelin/upgrades/contracts/utils/Address.sol"; +import "./PoolState.sol"; + +/** + * Based off of, and designed to interface with, openzeppelin/upgrades package + */ +contract PoolUpgradable is PoolState { + /** + * @dev Storage slot with the address of the current implementation. + * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is + * validated in the constructor. + */ + bytes32 private constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; + + /** + * @dev Emitted when the implementation is upgraded. + * @param implementation Address of the new implementation. + */ + event Upgraded(address indexed implementation); + + function initialize() public { + require(!_state.isInitialized, "already initialized"); + } + + /** + * @dev Upgrades the proxy to a new implementation. + * @param newImplementation Address of the new implementation. + */ + function upgradeTo(address newImplementation) internal { + setImplementation(newImplementation); + + emit Upgraded(newImplementation); + } + + /** + * @dev Sets the implementation address of the proxy. + * @param newImplementation Address of the new implementation. + */ + function setImplementation(address newImplementation) private { + require(OpenZeppelinUpgradesAddress.isContract(newImplementation), "Cannot set a proxy implementation to a non-contract address"); + + bytes32 slot = IMPLEMENTATION_SLOT; + + assembly { + sstore(slot, newImplementation) + } + } +} diff --git a/protocol/contracts/streaming/Stream.sol b/protocol/contracts/streaming/Stream.sol new file mode 100644 index 00000000..319e8707 --- /dev/null +++ b/protocol/contracts/streaming/Stream.sol @@ -0,0 +1,28 @@ +/* + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +pragma solidity ^0.5.17; +pragma experimental ABIEncoderV2; + +contract Stream { + struct Stream { + uint256 reserved; + uint256 released; + uint64 timestampFrom; + uint64 timestampTo; + uint64 boostCounter; + } +} \ No newline at end of file diff --git a/protocol/contracts/streaming/StreamingGetters.sol b/protocol/contracts/streaming/StreamingGetters.sol new file mode 100644 index 00000000..89477827 --- /dev/null +++ b/protocol/contracts/streaming/StreamingGetters.sol @@ -0,0 +1,86 @@ +/* + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +pragma solidity ^0.5.17; +pragma experimental ABIEncoderV2; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "./Stream.sol"; + +contract StreamingGetters is Stream { + using SafeMath for uint256; + + function streamedFrom(Stream memory currentStream) internal pure returns (uint256) { + return currentStream.timestampFrom; + } + + function streamedUntil(Stream memory currentStream) internal pure returns (uint256) { + return currentStream.timestampTo; + } + + function streamDuration(Stream memory currentStream) internal pure returns (uint256) { + return streamedUntil(currentStream).sub(streamedFrom(currentStream)); + } + + function streamTimeleft(Stream memory currentStream) internal view returns (uint256) { + uint256 curTime = blockTimestamp(); + uint256 untilTime = streamedUntil(currentStream); + + if (curTime >= untilTime) { + return 0; + } + + return untilTime.sub(curTime); + } + + function streamReserved(Stream memory currentStream) internal pure returns (uint256) { + return currentStream.reserved; + } + + function streamReleased(Stream memory currentStream) internal pure returns (uint256) { + return currentStream.released; + } + + function streamBoosted(Stream memory currentStream) internal pure returns (uint256) { + return currentStream.boostCounter; + } + + function releasableAmount(Stream memory currentStream) internal view returns (uint256) { + uint256 curTime = blockTimestamp(); + uint256 untilTime = streamedUntil(currentStream); + + uint256 releasedAmount; + if (untilTime == 0) { + return 0; + } else if (curTime >= untilTime) { + releasedAmount = streamReserved(currentStream); + } else { + releasedAmount = streamReserved(currentStream) + .mul(curTime.sub(streamedFrom(currentStream))) + .div(streamDuration(currentStream)); + } + + return releasedAmount.sub(streamReleased(currentStream)); + } + + function unreleasedAmount(Stream memory currentStream) internal pure returns (uint256) { + return streamReserved(currentStream).sub(streamReleased(currentStream)); + } + + function blockTimestamp() internal view returns (uint256) { + return block.timestamp; + } +} \ No newline at end of file diff --git a/protocol/contracts/streaming/StreamingSetters.sol b/protocol/contracts/streaming/StreamingSetters.sol new file mode 100644 index 00000000..56c63bcb --- /dev/null +++ b/protocol/contracts/streaming/StreamingSetters.sol @@ -0,0 +1,49 @@ +/* + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +pragma solidity ^0.5.17; +pragma experimental ABIEncoderV2; + +import "@openzeppelin/contracts/math/SafeMath.sol"; +import "./Stream.sol"; +import "./StreamingGetters.sol"; + +contract StreamingSetters is Stream, StreamingGetters { + using SafeMath for uint256; + + function setStream(Stream storage currentStream, uint256 amount, uint256 streamPeriod) internal { + currentStream.reserved = amount; + currentStream.released = 0; + currentStream.timestampFrom = uint64(blockTimestamp()); + currentStream.timestampTo = uint64(blockTimestamp().add(streamPeriod)); // safe + } + + function resetStream(Stream storage currentStream) internal { + currentStream.reserved = 0; + currentStream.released = 0; + currentStream.timestampFrom = 0; + currentStream.timestampTo = 0; + currentStream.boostCounter = 0; + } + + function incrementBoostCounter(Stream storage currentStream) internal { + currentStream.boostCounter++; // safe + } + + function incrementReleased(Stream storage currentStream, uint256 amount) internal { + currentStream.released = currentStream.released.add(amount); + } +} \ No newline at end of file diff --git a/protocol/contracts/token/Dollar.sol b/protocol/contracts/token/Dollar.sol index 22b16dba..895e233e 100644 --- a/protocol/contracts/token/Dollar.sol +++ b/protocol/contracts/token/Dollar.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -27,7 +27,7 @@ import "./IDollar.sol"; contract Dollar is IDollar, MinterRole, ERC20Detailed, Permittable, ERC20Burnable { constructor() - ERC20Detailed("Empty Set Dollar", "ESD", 18) + ERC20Detailed("Universal Dollar", "U8D", 18) Permittable() public { } diff --git a/protocol/contracts/token/IDollar.sol b/protocol/contracts/token/IDollar.sol index 3ac501ec..2935ca19 100644 --- a/protocol/contracts/token/IDollar.sol +++ b/protocol/contracts/token/IDollar.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/protocol/contracts/token/Permittable.sol b/protocol/contracts/token/Permittable.sol index 78985a20..e996114d 100644 --- a/protocol/contracts/token/Permittable.sol +++ b/protocol/contracts/token/Permittable.sol @@ -1,5 +1,5 @@ /* - Copyright 2020 Empty Set Squad + Copyright 2021 Universal Dollar Devs, based on the works of the Empty Set Squad Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/protocol/migrations/2_deploy.js b/protocol/migrations/2_deploy.js index 8c58d6a3..3af7a5ec 100644 --- a/protocol/migrations/2_deploy.js +++ b/protocol/migrations/2_deploy.js @@ -1,21 +1,47 @@ +const Deployer1 = artifacts.require("Deployer1"); +const Deployer2 = artifacts.require("Deployer2"); +const Deployer3 = artifacts.require("Deployer3"); const Implementation = artifacts.require("Implementation"); +const Root = artifacts.require("Root"); +const TestnetUSDC = artifacts.require("TestnetUSDC"); -async function deployImplementation(deployer) { - await deployer.deploy(Implementation); +async function deployTestnetUSDC(deployer) { + await deployer.deploy(TestnetUSDC); +} + +async function deployTestnet(deployer) { + const d1 = await deployer.deploy(Deployer1); + const root = await deployer.deploy(Root, d1.address); + const rootAsD1 = await Deployer1.at(root.address); + + const d2 = await deployer.deploy(Deployer2); + await rootAsD1.implement(d2.address); + const rootAsD2 = await Deployer2.at(root.address); + + const d3 = await deployer.deploy(Deployer3); + await rootAsD2.implement(d3.address); + const rootAsD3 = await Deployer3.at(root.address); + + const implementation = await deployer.deploy(Implementation); + await rootAsD3.implement(implementation.address); } module.exports = function(deployer) { deployer.then(async() => { console.log(deployer.network); switch (deployer.network) { + case 'mainnet': + await deployTestnet(deployer); + break; case 'development': + // await deployTestnetUSDC(deployer); + await deployTestnet(deployer); + break; + case 'kovan': case 'rinkeby': case 'ropsten': - await deployImplementation(deployer); - break; - case 'mainnet': - case 'mainnet-fork': - await deployImplementation(deployer); + // await deployTestnetUSDC(deployer); + await deployTestnet(deployer); break; default: throw("Unsupported network"); diff --git a/protocol/package-lock.json b/protocol/package-lock.json index 434ae3e3..2fb6f48a 100644 --- a/protocol/package-lock.json +++ b/protocol/package-lock.json @@ -1,5 +1,5 @@ { - "name": "@emptysetsquad/dollar", + "name": "@8quad/u8d-protocol", "version": "0.0.0", "lockfileVersion": 1, "requires": true, @@ -13,6 +13,21 @@ "@babel/highlight": "^7.8.3" } }, + "@babel/helper-module-imports": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz", + "integrity": "sha512-SR713Ogqg6++uexFRORf/+nPXMmWIn80TALu0uaFb+iQIUoR7bOC7zBWyzBs5b3tBBJXuyD0cRu1F15GyzjOWA==", + "dev": true, + "requires": { + "@babel/types": "^7.12.5" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + }, "@babel/helper-validator-identifier": { "version": "7.9.5", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz", @@ -67,6 +82,25 @@ } } }, + "@babel/plugin-transform-runtime": { + "version": "7.12.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.12.10.tgz", + "integrity": "sha512-xOrUfzPxw7+WDm9igMgQCbO3cJKymX7dFdsgRr1eu9n3KjjyU4pptIXbXPseQDquw+W+RuJEJMHKHNsPNNm3CA==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.12.5", + "@babel/helper-plugin-utils": "^7.10.4", + "semver": "^5.5.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, "@babel/runtime": { "version": "7.9.6", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.9.6.tgz", @@ -84,6 +118,37 @@ } } }, + "@babel/types": { + "version": "7.12.12", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.12.tgz", + "integrity": "sha512-lnIX7piTxOH22xE7fDXDbSHg9MM1/6ORnafpJmov5rs0kX5g4BZxeXNJLXsMRiO0U5Rb8/FvMS6xlTnTHvxonQ==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.12.11", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + }, + "dependencies": { + "@babel/helper-validator-identifier": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", + "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", + "dev": true + }, + "lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + } + } + }, "@openzeppelin/contract-loader": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/@openzeppelin/contract-loader/-/contract-loader-0.6.1.tgz", @@ -722,6 +787,24 @@ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", "dev": true }, + "@types/pbkdf2": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.0.tgz", + "integrity": "sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/secp256k1": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.1.tgz", + "integrity": "sha512-+ZjSA8ELlOp8SlKi0YLB2tz9d5iPNEmOBd+8Rz21wTMdaXQIa9b6TEnD6l5qKOCypE7FSyPyck12qZJxSDNoog==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/underscore": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/@types/underscore/-/underscore-1.10.0.tgz", @@ -800,12 +883,6 @@ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", "dev": true }, - "antlr4ts": { - "version": "0.5.0-alpha.3", - "resolved": "https://registry.npmjs.org/antlr4ts/-/antlr4ts-0.5.0-alpha.3.tgz", - "integrity": "sha512-La89tKkGcHFIVuruv4Bm1esc3zLmES2NOTEwwNS1pudz+zx/0FNqQeUu9p48i9/QHKPVqjN87LB+q3buTg7oDQ==", - "dev": true - }, "any-promise": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", @@ -892,6 +969,12 @@ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, + "await-semaphore": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/await-semaphore/-/await-semaphore-0.1.3.tgz", + "integrity": "sha512-d1W2aNSYcz/sxYO4pMGX9vq65qOTu0P800epMud+6cYYX0QcT7zyqcxec3VWzpgvdXo57UWmVbZpLMjX2m1I7Q==", + "dev": true + }, "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", @@ -1656,6 +1739,12 @@ "safe-buffer": "^5.1.1" } }, + "blakejs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.1.0.tgz", + "integrity": "sha1-ad+S75U6qIylGjLfarHFShVfx6U=", + "dev": true + }, "bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", @@ -1832,6 +1921,12 @@ "safe-buffer": "^5.1.2" } }, + "btoa": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz", + "integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==", + "dev": true + }, "buffer": { "version": "5.4.3", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.4.3.tgz", @@ -2051,20 +2146,6 @@ "integrity": "sha1-fad6+Yu96c5LWzWM1Va13e0tMUk=", "dev": true }, - "cli-color": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-1.4.0.tgz", - "integrity": "sha512-xu6RvQqqrWEo6MPR1eixqGPywhYBHRs653F9jfXB2Hx4jdM/3WxiNE1vppRmxtMIfl16SFYTpYlrnqH/HsK/2w==", - "dev": true, - "requires": { - "ansi-regex": "^2.1.1", - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "memoizee": "^0.4.14", - "timers-ext": "^0.1.5" - } - }, "cli-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", @@ -2786,18 +2867,6 @@ "ext": "^1.1.2" } }, - "es6-weak-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", - "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", - "dev": true, - "requires": { - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.1" - } - }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -2825,69 +2894,132 @@ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" }, - "eth-block-tracker": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/eth-block-tracker/-/eth-block-tracker-3.0.1.tgz", - "integrity": "sha512-WUVxWLuhMmsfenfZvFO5sbl1qFY2IqUlw/FPVmjjdElpqLsZtSG+wPe9Dz7W/sB6e80HgFKknOmKk2eNlznHug==", + "eth-ens-namehash": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/eth-ens-namehash/-/eth-ens-namehash-2.0.8.tgz", + "integrity": "sha1-IprEbsqG1S4MmR58sq74P/D2i88=", + "requires": { + "idna-uts46-hx": "^2.3.1", + "js-sha3": "^0.5.7" + } + }, + "eth-json-rpc-errors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/eth-json-rpc-errors/-/eth-json-rpc-errors-1.1.1.tgz", + "integrity": "sha512-WT5shJ5KfNqHi9jOZD+ID8I1kuYWNrigtZat7GOQkvwo99f8SzAVaEcWhJUv656WiZOAg3P1RiJQANtUmDmbIg==", "dev": true, "requires": { - "eth-query": "^2.1.0", - "ethereumjs-tx": "^1.3.3", - "ethereumjs-util": "^5.1.3", - "ethjs-util": "^0.1.3", - "json-rpc-engine": "^3.6.0", - "pify": "^2.3.0", - "tape": "^4.6.3" + "fast-safe-stringify": "^2.0.6" + } + }, + "eth-json-rpc-filters": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eth-json-rpc-filters/-/eth-json-rpc-filters-4.2.1.tgz", + "integrity": "sha512-tPfohezq8mSmwa47xvq6PGzBDLZ0njWJMB1J+OPuv+n+1WkWDlf3l3tqJXpq96RxhrzK2q7wiweRS5aGIzpq4Q==", + "dev": true, + "requires": { + "await-semaphore": "^0.1.3", + "eth-json-rpc-middleware": "^6.0.0", + "eth-query": "^2.1.2", + "json-rpc-engine": "^5.3.0", + "lodash.flatmap": "^4.5.0", + "safe-event-emitter": "^1.0.1" }, "dependencies": { - "ethereumjs-tx": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/ethereumjs-tx/-/ethereumjs-tx-1.3.7.tgz", - "integrity": "sha512-wvLMxzt1RPhAQ9Yi3/HKZTn0FZYpnsmQdbKYfUUpi4j1SEIcbkd9tndVjcPrufY3V7j2IebOpC00Zp2P/Ay2kA==", + "eth-json-rpc-middleware": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-6.0.0.tgz", + "integrity": "sha512-qqBfLU2Uq1Ou15Wox1s+NX05S9OcAEL4JZ04VZox2NS0U+RtCMjSxzXhLFWekdShUPZ+P8ax3zCO2xcPrp6XJQ==", "dev": true, "requires": { - "ethereum-common": "^0.0.18", - "ethereumjs-util": "^5.0.0" + "btoa": "^1.2.1", + "clone": "^2.1.1", + "eth-query": "^2.1.2", + "eth-rpc-errors": "^3.0.0", + "eth-sig-util": "^1.4.2", + "ethereumjs-util": "^5.1.2", + "json-rpc-engine": "^5.3.0", + "json-stable-stringify": "^1.0.1", + "node-fetch": "^2.6.1", + "pify": "^3.0.0", + "safe-event-emitter": "^1.0.1" + } + }, + "eth-sig-util": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", + "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", + "dev": true, + "requires": { + "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "ethereumjs-util": "^5.1.1" + } + }, + "ethereumjs-abi": { + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#1ce6a1d64235fabe2aaf827fd606def55693508f", + "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "dev": true, + "requires": { + "bn.js": "^4.11.8", + "ethereumjs-util": "^6.0.0" + }, + "dependencies": { + "ethereumjs-util": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", + "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", + "dev": true, + "requires": { + "@types/bn.js": "^4.11.3", + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "0.1.6", + "rlp": "^2.2.3" + } + } } }, "ethereumjs-util": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", - "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.1.tgz", + "integrity": "sha512-v3kT+7zdyCm1HIqWlLNrHGqHGLpGYIhjeHxQjnDXjLT2FyGJDsd3LWMYUo7pAFRrk86CR3nUJfhC81CCoJNNGQ==", "dev": true, "requires": { "bn.js": "^4.11.0", "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", "ethjs-util": "^0.1.3", - "keccak": "^1.0.2", "rlp": "^2.0.0", - "safe-buffer": "^5.1.1", - "secp256k1": "^3.0.1" + "safe-buffer": "^5.1.1" } }, - "keccak": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/keccak/-/keccak-1.4.0.tgz", - "integrity": "sha512-eZVaCpblK5formjPjeTBik7TAg+pqnDrMHIffSvi9Lh7PQgM1+hSzakUeZFCk9DVVG0dacZJuaz2ntwlzZUIBw==", + "json-rpc-engine": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/json-rpc-engine/-/json-rpc-engine-5.4.0.tgz", + "integrity": "sha512-rAffKbPoNDjuRnXkecTjnsE3xLLrb00rEkdgalINhaYVYIxDwWtvYBr9UFbhTvPB1B2qUOLoFd/cV6f4Q7mh7g==", "dev": true, "requires": { - "bindings": "^1.2.1", - "inherits": "^2.0.3", - "nan": "^2.2.1", - "safe-buffer": "^5.1.0" + "eth-rpc-errors": "^3.0.0", + "safe-event-emitter": "^1.0.1" } + }, + "node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", + "dev": true + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true } } }, - "eth-ens-namehash": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/eth-ens-namehash/-/eth-ens-namehash-2.0.8.tgz", - "integrity": "sha1-IprEbsqG1S4MmR58sq74P/D2i88=", - "requires": { - "idna-uts46-hx": "^2.3.1", - "js-sha3": "^0.5.7" - } - }, "eth-json-rpc-infura": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/eth-json-rpc-infura/-/eth-json-rpc-infura-3.2.1.tgz", @@ -2983,6 +3115,15 @@ "xtend": "^4.0.1" } }, + "eth-rpc-errors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eth-rpc-errors/-/eth-rpc-errors-3.0.0.tgz", + "integrity": "sha512-iPPNHPrLwUlR9xCSYm7HHQjWBasor3+KZfRvwEWxMz3ca0yqnlBeJrnyphkGIXZ4J7AMAaOLmwy4AWhnxOiLxg==", + "dev": true, + "requires": { + "fast-safe-stringify": "^2.0.6" + } + }, "eth-sig-util": { "version": "2.5.3", "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-2.5.3.tgz", @@ -3110,6 +3251,74 @@ "integrity": "sha1-L9w1dvIykDNYl26znaeDIT/5Uj8=", "dev": true }, + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + }, + "dependencies": { + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "keccak": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.1.tgz", + "integrity": "sha512-epq90L9jlFWCW7+pQa6JOnKn2Xgl2mtI664seYR6MHskvI9agt7AnDqmAlp9TqU4/caMYbA08Hi5DMZAl5zdkA==", + "dev": true, + "requires": { + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0" + } + }, + "scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", + "dev": true + }, + "secp256k1": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.2.tgz", + "integrity": "sha512-UDar4sKvWAksIlfX3xIaQReADn+WFnHvbVujpcbr+9Sf/69odMwy2MUsz5CKLQgX9nsIyrjuxL2imVyoNHa3fg==", + "dev": true, + "requires": { + "elliptic": "^6.5.2", + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0" + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "dev": true + } + } + }, "ethereum-ens": { "version": "0.7.8", "resolved": "https://registry.npmjs.org/ethereum-ens/-/ethereum-ens-0.7.8.tgz", @@ -3443,16 +3652,6 @@ "strip-hex-prefix": "1.0.0" } }, - "event-emitter": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", - "dev": true, - "requires": { - "d": "1", - "es5-ext": "~0.10.14" - } - }, "eventemitter3": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", @@ -3574,6 +3773,12 @@ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, + "fast-safe-stringify": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", + "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==", + "dev": true + }, "fd-slicer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", @@ -18715,12 +18920,6 @@ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=" }, - "is-promise": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", - "dev": true - }, "is-regex": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", @@ -19090,6 +19289,12 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" }, + "lodash.flatmap": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.flatmap/-/lodash.flatmap-4.5.0.tgz", + "integrity": "sha1-74y/QI9uSCaGYzRTBcaswLd4cC4=", + "dev": true + }, "lodash.flatten": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", @@ -19156,15 +19361,6 @@ "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" }, - "lru-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", - "integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=", - "dev": true, - "requires": { - "es5-ext": "~0.10.2" - } - }, "ltgt": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ltgt/-/ltgt-2.2.1.tgz", @@ -19232,22 +19428,6 @@ } } }, - "memoizee": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.14.tgz", - "integrity": "sha512-/SWFvWegAIYAO4NQMpcX+gcra0yEZu4OntmUdrBaWrJncxOqAziGFlHxc7yjKVK2uu3lpPW27P27wkR82wA8mg==", - "dev": true, - "requires": { - "d": "1", - "es5-ext": "^0.10.45", - "es6-weak-map": "^2.0.2", - "event-emitter": "^0.3.5", - "is-promise": "^2.1", - "lru-queue": "0.1", - "next-tick": "1", - "timers-ext": "^0.1.5" - } - }, "merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -19552,6 +19732,12 @@ "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" }, + "node-addon-api": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", + "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==", + "dev": true + }, "node-environment-flags": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", @@ -19576,6 +19762,12 @@ "integrity": "sha1-q4hOjn5X44qUR1POxwb3iNF2i7U=", "dev": true }, + "node-gyp-build": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.2.3.tgz", + "integrity": "sha512-MN6ZpzmfNCRM+3t57PTJHgHyw/h4OWnZ6mR8P5j/uZtqQr46RRuDE/P+g3n0YR/AiYXeWixZZzaip77gdICfRg==", + "dev": true + }, "nofilter": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-1.0.3.tgz", @@ -20541,35 +20733,6 @@ "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", "dev": true }, - "sol-merger": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/sol-merger/-/sol-merger-3.1.0.tgz", - "integrity": "sha512-4/JELeFlB8bcyqttRZ7pE/EGpevft9Q7IPjMaKLKMrj1exmdyt+1qSfuSXxueFXRZQxSd21u6DjEedDkOtQ5yQ==", - "dev": true, - "requires": { - "antlr4ts": "^0.5.0-alpha.3", - "cli-color": "^1.4.0", - "commander": "^4.0.1", - "debug": "^4.1.1", - "fs-extra": "^8.0.1", - "glob": "^7.1.2", - "strip-json-comments": "^3.0.1" - }, - "dependencies": { - "commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - } - } - }, "solidity-parser-antlr": { "version": "0.4.11", "resolved": "https://registry.npmjs.org/solidity-parser-antlr/-/solidity-parser-antlr-0.4.11.tgz", @@ -20942,16 +21105,6 @@ "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=" }, - "timers-ext": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", - "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", - "dev": true, - "requires": { - "es5-ext": "~0.10.46", - "next-tick": "1" - } - }, "to-buffer": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", @@ -21062,16 +21215,15 @@ } }, "truffle-plugin-verify": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/truffle-plugin-verify/-/truffle-plugin-verify-0.4.0.tgz", - "integrity": "sha512-wI6J8vB6DZYyqTouMCayGWwTqy5VZwLaZ/vGjRjtt1MdXDzfyeGw5UHJujjFQYU1hCDYt/0LmAVmBkWg9MBWmA==", + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/truffle-plugin-verify/-/truffle-plugin-verify-0.5.4.tgz", + "integrity": "sha512-cFqhypLZ3C/71jh9muVWm37pKd+I1AHr/hu+h7Y3GEKaMFu5YoQ97mj/0AnrY4MO8pgoaghSqkCPiIj/xXCaoA==", "dev": true, "requires": { "axios": "0.19.2", "cli-logger": "0.5.40", "delay": "4.3.0", - "querystring": "0.2.0", - "sol-merger": "3.1.0" + "querystring": "0.2.0" }, "dependencies": { "axios": { @@ -21849,8 +22001,10 @@ "backoff": "^2.5.0", "clone": "^2.0.0", "cross-fetch": "^2.1.0", - "eth-block-tracker": "^3.0.0", + "eth-block-tracker": "^4.2.0", + "eth-json-rpc-filters": "^4.0.2", "eth-json-rpc-infura": "^3.1.0", + "eth-json-rpc-middleware": "^4.1.1", "eth-sig-util": "^1.4.2", "ethereumjs-block": "^1.2.2", "ethereumjs-tx": "^1.2.0", @@ -21867,6 +22021,42 @@ "xtend": "^4.0.1" }, "dependencies": { + "eth-block-tracker": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/eth-block-tracker/-/eth-block-tracker-4.4.3.tgz", + "integrity": "sha512-A8tG4Z4iNg4mw5tP1Vung9N9IjgMNqpiMoJ/FouSFwNCGHv2X0mmOYwtQOJzki6XN7r7Tyo01S29p7b224I4jw==", + "dev": true, + "requires": { + "@babel/plugin-transform-runtime": "^7.5.5", + "@babel/runtime": "^7.5.5", + "eth-query": "^2.1.0", + "json-rpc-random-id": "^1.0.1", + "pify": "^3.0.0", + "safe-event-emitter": "^1.0.1" + } + }, + "eth-json-rpc-middleware": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/eth-json-rpc-middleware/-/eth-json-rpc-middleware-4.4.1.tgz", + "integrity": "sha512-yoSuRgEYYGFdVeZg3poWOwAlRI+MoBIltmOB86MtpoZjvLbou9EB/qWMOWSmH2ryCWLW97VYY6NWsmWm3OAA7A==", + "dev": true, + "requires": { + "btoa": "^1.2.1", + "clone": "^2.1.1", + "eth-json-rpc-errors": "^1.0.1", + "eth-query": "^2.1.2", + "eth-sig-util": "^1.4.2", + "ethereumjs-block": "^1.6.0", + "ethereumjs-tx": "^1.3.7", + "ethereumjs-util": "^5.1.2", + "ethereumjs-vm": "^2.6.0", + "fetch-ponyfill": "^4.0.0", + "json-rpc-engine": "^5.1.3", + "json-stable-stringify": "^1.0.1", + "pify": "^3.0.0", + "safe-event-emitter": "^1.0.1" + } + }, "eth-sig-util": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", @@ -21940,6 +22130,16 @@ "secp256k1": "^3.0.1" } }, + "json-rpc-engine": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/json-rpc-engine/-/json-rpc-engine-5.4.0.tgz", + "integrity": "sha512-rAffKbPoNDjuRnXkecTjnsE3xLLrb00rEkdgalINhaYVYIxDwWtvYBr9UFbhTvPB1B2qUOLoFd/cV6f4Q7mh7g==", + "dev": true, + "requires": { + "eth-rpc-errors": "^3.0.0", + "safe-event-emitter": "^1.0.1" + } + }, "keccak": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/keccak/-/keccak-1.4.0.tgz", @@ -21952,6 +22152,12 @@ "safe-buffer": "^5.1.0" } }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, "ws": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", diff --git a/protocol/package.json b/protocol/package.json index 6572317a..8301771f 100644 --- a/protocol/package.json +++ b/protocol/package.json @@ -1,5 +1,5 @@ { - "name": "@emptysetsquad/dollar", + "name": "@8quad/u8d-protocol", "version": "0.0.0", "private": true, "description": "", @@ -27,7 +27,7 @@ "eth-sig-util": "^2.5.3", "husky": "^4.2.5", "mocha": "^7.0.0", - "truffle-privatekey-provider": "^1.3.0", - "truffle-plugin-verify": "^0.4.0" + "truffle-plugin-verify": "^0.5.4", + "truffle-privatekey-provider": "^1.3.0" } } diff --git a/protocol/test/dao/Bonding.test.js b/protocol/test/dao/Bonding.test.js index b85d58df..988f8a88 100644 --- a/protocol/test/dao/Bonding.test.js +++ b/protocol/test/dao/Bonding.test.js @@ -7,7 +7,7 @@ const { expect } = require('chai'); const MockBonding = contract.fromArtifact('MockBonding'); const Dollar = contract.fromArtifact('Dollar'); -const INITIAL_STAKE_MULTIPLE = new BN(10).pow(new BN(6)); // 100 ESD -> 100M ESDS +const INITIAL_STAKE_MULTIPLE = new BN(10).pow(new BN(6)); // 100 U8D -> 100M U8DS const FROZEN = new BN(0); const FLUID = new BN(1); diff --git a/protocol/test/dao/Comptroller.test.js b/protocol/test/dao/Comptroller.test.js index d1905d43..081ec94f 100644 --- a/protocol/test/dao/Comptroller.test.js +++ b/protocol/test/dao/Comptroller.test.js @@ -165,7 +165,7 @@ describe('Comptroller', function () { describe('on single call', function () { beforeEach(async function () { - await this.comptroller.redeemToAccountE(userAddress, new BN(0), new BN(100)); + await this.comptroller.redeemToAccountE(userAddress, new BN(100)); }); it('doesnt mint new Dollar tokens', async function () { @@ -181,8 +181,8 @@ describe('Comptroller', function () { describe('multiple calls', function () { beforeEach(async function () { - await this.comptroller.redeemToAccountE(userAddress, new BN(0), new BN(100)); - await this.comptroller.redeemToAccountE(userAddress, new BN(0), new BN(200)); + await this.comptroller.redeemToAccountE(userAddress, new BN(100)); + await this.comptroller.redeemToAccountE(userAddress, new BN(200)); }); it('doesnt mint new Dollar tokens', async function () { @@ -206,39 +206,7 @@ describe('Comptroller', function () { }); it('reverts', async function () { - await expectRevert(this.comptroller.redeemToAccountE(userAddress, new BN(0), new BN(400)), "not enough redeemable"); - }); - }); - - describe('with base amount', function () { - beforeEach(async function () { - await this.comptroller.redeemToAccountE(userAddress, new BN(1000), new BN(100)); - }); - - it('doesnt mint new Dollar tokens', async function () { - expect(await this.dollar.totalSupply()).to.be.bignumber.equal(new BN(1300)); - expect(await this.dollar.balanceOf(this.comptroller.address)).to.be.bignumber.equal(new BN(200)); - expect(await this.dollar.balanceOf(userAddress)).to.be.bignumber.equal(new BN(1100)); - }); - - it('updates total redeemable', async function () { - expect(await this.comptroller.totalRedeemable()).to.be.bignumber.equal(new BN(200)); - }); - }); - - describe('only base amount', function () { - beforeEach(async function () { - await this.comptroller.redeemToAccountE(userAddress, new BN(1000), new BN(0)); - }); - - it('doesnt mint new Dollar tokens', async function () { - expect(await this.dollar.totalSupply()).to.be.bignumber.equal(new BN(1300)); - expect(await this.dollar.balanceOf(this.comptroller.address)).to.be.bignumber.equal(new BN(300)); - expect(await this.dollar.balanceOf(userAddress)).to.be.bignumber.equal(new BN(1000)); - }); - - it('updates total redeemable', async function () { - expect(await this.comptroller.totalRedeemable()).to.be.bignumber.equal(new BN(300)); + await expectRevert(this.comptroller.redeemToAccountE(userAddress, new BN(400)), "not enough redeemable"); }); }); }); diff --git a/protocol/test/dao/Govern.test.js b/protocol/test/dao/Govern.test.js index e5ae9f88..9ed2ac6b 100644 --- a/protocol/test/dao/Govern.test.js +++ b/protocol/test/dao/Govern.test.js @@ -16,7 +16,7 @@ const UNDECIDED = new BN(0); const APPROVE = new BN(1); const REJECT = new BN(2); -const INITIAL_STAKE_MULTIPLE = new BN(10).pow(new BN(6)); // 100 ESD -> 100M ESDS +const INITIAL_STAKE_MULTIPLE = new BN(10).pow(new BN(6)); // 100 U8D -> 100M U8DS describe('Govern', function () { const [ ownerAddress, userAddress, userAddress2, userAddress3 ] = accounts; @@ -405,9 +405,9 @@ describe('Govern', function () { describe('ended with not enough approve votes', function () { beforeEach(async function () { - await this.govern.vote(this.implB.address, REJECT, {from: userAddress}); - await this.govern.vote(this.implB.address, REJECT, {from: userAddress3}); - await this.govern.vote(this.implB.address, APPROVE, {from: userAddress2}); + await this.govern.vote(this.implB.address, APPROVE, {from: userAddress}); + await this.govern.vote(this.implB.address, APPROVE, {from: userAddress3}); + await this.govern.vote(this.implB.address, REJECT, {from: userAddress2}); const epoch = await this.govern.epoch(); await this.govern.setEpochTime(epoch + EMERGENCY_COMMIT_PERIOD); diff --git a/protocol/test/dao/Market.test.js b/protocol/test/dao/Market.test.js index e2be16e2..2d23b59f 100644 --- a/protocol/test/dao/Market.test.js +++ b/protocol/test/dao/Market.test.js @@ -35,10 +35,6 @@ function premiumMean(start, end) { return 1.0 / ((1.0 - start) * (1.0 - end)) - 1.0 } -function prorated(coupons, epochs) { - return Math.floor(coupons * epochs / 90); -} - describe('Market', function () { const [ ownerAddress, userAddress, poolAddress ] = accounts; @@ -88,20 +84,17 @@ describe('Market', function () { it('updates user balances', async function () { expect(await this.dollar.balanceOf(userAddress)).to.be.bignumber.equal(new BN(900000)); - expect(await this.market.balanceOfCoupons(userAddress, 1)).to.be.bignumber.equal(new BN(premium(1000000, 100000, 100000))); - expect(await this.market.balanceOfCouponUnderlying(userAddress, 1)).to.be.bignumber.equal(new BN(100000)); + expect(await this.market.balanceOfCoupons(userAddress, 1)).to.be.bignumber.equal(new BN(100000 + premium(1000000, 100000, 100000))); }); it('shows correct preimum', async function () { expect(await this.dollar.balanceOf(userAddress)).to.be.bignumber.equal(new BN(900000)); - expect(await this.market.balanceOfCoupons(userAddress, 1)).to.be.bignumber.equal(new BN(premium(1000000, 100000, 100000))); - expect(await this.market.balanceOfCouponUnderlying(userAddress, 1)).to.be.bignumber.equal(new BN(100000)); + expect(await this.market.balanceOfCoupons(userAddress, 1)).to.be.bignumber.equal(new BN(100000 + premium(1000000, 100000, 100000))); }); it('updates dao balances', async function () { expect(await this.dollar.balanceOf(this.market.address)).to.be.bignumber.equal(new BN(0)); - expect(await this.market.totalCoupons()).to.be.bignumber.equal(new BN(premium(1000000, 100000, 100000))); - expect(await this.market.totalCouponUnderlying()).to.be.bignumber.equal(new BN(100000)); + expect(await this.market.totalCoupons()).to.be.bignumber.equal(new BN(100000 + premium(1000000, 100000, 100000))); expect(await this.market.totalDebt()).to.be.bignumber.equal(new BN(0)); expect(await this.market.totalRedeemable()).to.be.bignumber.equal(new BN(0)); }); @@ -113,7 +106,7 @@ describe('Market', function () { expect(event.args.epoch).to.be.bignumber.equal(new BN(1)); expect(event.args.dollarAmount).to.be.bignumber.equal(new BN(100000)); - expect(event.args.couponAmount).to.be.bignumber.equal(new BN(premium(1000000, 100000, 100000))); + expect(event.args.couponAmount).to.be.bignumber.equal(new BN(100000 + premium(1000000, 100000, 100000))); }); }); @@ -127,14 +120,12 @@ describe('Market', function () { it('updates user balances', async function () { expect(await this.dollar.balanceOf(userAddress)).to.be.bignumber.equal(new BN(900000)); - expect(await this.market.balanceOfCoupons(userAddress, 1)).to.be.bignumber.equal(new BN(premium(1000000, 100000, 50000) + premium(950000, 50000, 50000))); - expect(await this.market.balanceOfCouponUnderlying(userAddress, 1)).to.be.bignumber.equal(new BN(100000)); + expect(await this.market.balanceOfCoupons(userAddress, 1)).to.be.bignumber.equal(new BN(100000 + premium(1000000, 100000, 50000) + premium(950000, 50000, 50000))); }); it('updates dao balances', async function () { expect(await this.dollar.balanceOf(this.market.address)).to.be.bignumber.equal(new BN(0)); - expect(await this.market.totalCoupons()).to.be.bignumber.equal(new BN(premium(1000000, 100000, 50000) + premium(950000, 50000, 50000))); - expect(await this.market.totalCouponUnderlying()).to.be.bignumber.equal(new BN(100000)); + expect(await this.market.totalCoupons()).to.be.bignumber.equal(new BN(100000 + premium(1000000, 100000, 50000) + premium(950000, 50000, 50000))); expect(await this.market.totalDebt()).to.be.bignumber.equal(new BN(0)); expect(await this.market.totalRedeemable()).to.be.bignumber.equal(new BN(0)); }); @@ -146,124 +137,30 @@ describe('Market', function () { expect(event.args.epoch).to.be.bignumber.equal(new BN(1)); expect(event.args.dollarAmount).to.be.bignumber.equal(new BN(50000)); - expect(event.args.couponAmount).to.be.bignumber.equal(new BN(premium(950000, 50000, 50000))); - }); - }); - }); - - describe('migrateCoupons', function () { - beforeEach(async function () { - await this.market.incrementBalanceOfCouponsE(userAddress, 1, 100000); - }); - - describe('before call', function () { - it('updates user balances', async function () { - expect(await this.market.balanceOfCoupons(userAddress, 1)).to.be.bignumber.equal(new BN(100000)); - expect(await this.market.balanceOfCouponUnderlying(userAddress, 1)).to.be.bignumber.equal(new BN(0)); - }); - - it('updates dao balances', async function () { - expect(await this.market.totalCoupons()).to.be.bignumber.equal(new BN(100000)); - expect(await this.market.outstandingCoupons(1)).to.be.bignumber.equal(new BN(100000)); - expect(await this.market.totalCouponUnderlying()).to.be.bignumber.equal(new BN(0)); - }); - }); - - describe('no coupons', function () { - it('reverts', async function () { - await expectRevert(this.market.migrateCoupons(0, {from: userAddress}), "Market: No coupons"); - }); - }); - - describe('on single call', function () { - beforeEach(async function () { - this.result = await this.market.migrateCoupons(1, {from: userAddress}); - this.txHash = this.result.tx; - }); - - it('updates user balances', async function () { - expect(await this.market.balanceOfCoupons(userAddress, 1)).to.be.bignumber.equal(new BN(50000)); - expect(await this.market.balanceOfCouponUnderlying(userAddress, 1)).to.be.bignumber.equal(new BN(50000)); - }); - - it('updates dao balances', async function () { - expect(await this.market.totalCoupons()).to.be.bignumber.equal(new BN(50000)); - expect(await this.market.outstandingCoupons(1)).to.be.bignumber.equal(new BN(50000)); - expect(await this.market.totalCouponUnderlying()).to.be.bignumber.equal(new BN(50000)); - }); - - it('emits CouponPurchase event', async function () { - const event = await expectEvent.inTransaction(this.txHash, MockMarket, 'CouponPurchase', { - account: userAddress, - }); - - expect(event.args.epoch).to.be.bignumber.equal(new BN(1)); - expect(event.args.dollarAmount).to.be.bignumber.equal(new BN(50000)); - expect(event.args.couponAmount).to.be.bignumber.equal(new BN(0)); - }); - - it('emits CouponRedemption event', async function () { - const event = await expectEvent.inTransaction(this.txHash, MockMarket, 'CouponRedemption', { - account: userAddress, - }); - - expect(event.args.epoch).to.be.bignumber.equal(new BN(1)); - expect(event.args.amount).to.be.bignumber.equal(new BN(0)); - expect(event.args.couponAmount).to.be.bignumber.equal(new BN(50000)); - }); - }); - - describe('call twice', function () { - beforeEach(async function () { - await this.market.migrateCoupons(1, {from: userAddress}); - }); - - it('reverts', async function () { - await expectRevert(this.market.migrateCoupons(1, {from: userAddress}), "Market: Already migrated"); - }); - }); - - describe('after expired', function () { - this.timeout(30000); - - beforeEach(async function () { - for (let i = 0; i < 90; i++) { - await this.market.incrementEpochE(); - } - await this.market.stepE(); - }); - - it('reverts', async function () { - await expectRevert(this.market.migrateCoupons(1, {from: userAddress}), "Market: No coupons"); + expect(event.args.couponAmount).to.be.bignumber.equal(new BN(50000 + premium(950000, 50000, 50000))); }); }); }); - describe('redeemCoupons - legacy', function () { + describe('redeemCoupons', function () { beforeEach(async function () { - await this.market.set(500); - await this.market.incrementTotalDebtE(100000); await this.market.purchaseCoupons(100000, {from: userAddress}); await this.market.mintToE(this.market.address, 100000); - - this.couponUnderlying = 100000; - this.couponAmount = premium(1000000, 100000, 100000); - - await this.market.incrementTotalRedeemableE(this.couponAmount); + await this.market.incrementTotalRedeemableE(100000); }); describe('before redeemable', function () { describe('same epoch', function () { it('reverts', async function () { - await expectRevert(this.market.redeemCoupons(1, this.couponUnderlying, {from: userAddress}), "Market: Too early to redeem"); + await expectRevert(this.market.redeemCoupons(1, 100000, {from: userAddress}), "Market: Too early to redeem"); }); }); describe('next epoch', function () { it('reverts', async function () { await this.market.incrementEpochE(); - await expectRevert(this.market.redeemCoupons(1, this.couponUnderlying, {from: userAddress}), "Market: Too early to redeem"); + await expectRevert(this.market.redeemCoupons(1, 100000, {from: userAddress}), "Market: Too early to redeem"); }); }); }); @@ -276,26 +173,24 @@ describe('Market', function () { describe('not enough coupon balance', function () { it('reverts', async function () { - await expectRevert(this.market.redeemCoupons(1, this.couponUnderlying + 1, {from: userAddress}), "Market: Insufficient coupon underlying balance"); + await expectRevert(this.market.redeemCoupons(1, 200000, {from: userAddress}), "Market: Insufficient coupon balance"); }); }); describe('on single call', function () { beforeEach(async function () { - this.result = await this.market.redeemCoupons(1, this.couponUnderlying, {from: userAddress}); + this.result = await this.market.redeemCoupons(1, 100000, {from: userAddress}); this.txHash = this.result.tx; }); it('updates user balances', async function () { - expect(await this.dollar.balanceOf(userAddress)).to.be.bignumber.equal(new BN(900000 + this.couponUnderlying + this.couponAmount)); - expect(await this.market.balanceOfCoupons(userAddress, 1)).to.be.bignumber.equal(new BN(0)); - expect(await this.market.balanceOfCouponUnderlying(userAddress, 1)).to.be.bignumber.equal(new BN(0)); + expect(await this.dollar.balanceOf(userAddress)).to.be.bignumber.equal(new BN(1000000)); + expect(await this.market.balanceOfCoupons(userAddress, 1)).to.be.bignumber.equal(new BN(premium(1000000, 100000, 100000))); }); it('updates dao balances', async function () { - expect(await this.dollar.balanceOf(this.market.address)).to.be.bignumber.equal(new BN(100000 - this.couponAmount)); - expect(await this.market.totalCoupons()).to.be.bignumber.equal(new BN(0)); - expect(await this.market.totalCouponUnderlying()).to.be.bignumber.equal(new BN(0)); + expect(await this.dollar.balanceOf(this.market.address)).to.be.bignumber.equal(new BN(0)); + expect(await this.market.totalCoupons()).to.be.bignumber.equal(new BN(premium(1000000, 100000, 100000))); expect(await this.market.totalDebt()).to.be.bignumber.equal(new BN(0)); expect(await this.market.totalRedeemable()).to.be.bignumber.equal(new BN(0)); }); @@ -306,159 +201,7 @@ describe('Market', function () { }); expect(event.args.epoch).to.be.bignumber.equal(new BN(1)); - expect(event.args.amount).to.be.bignumber.equal(new BN(this.couponUnderlying)); - expect(event.args.couponAmount).to.be.bignumber.equal(new BN(this.couponAmount)); - }); - }); - - describe('multiple calls', function () { - beforeEach(async function () { - this.result = await this.market.redeemCoupons(1, 30000, {from: userAddress}); - this.result = await this.market.redeemCoupons(1, 50000, {from: userAddress}); - this.txHash = this.result.tx; - this.redeemedAmount = (this.couponAmount) * 8 / 10; - this.redeemedTotal = (this.couponUnderlying + this.couponAmount) * 8 / 10; - }); - - it('updates user balances', async function () { - expect(await this.dollar.balanceOf(userAddress)).to.be.bignumber.equal(new BN(900000 + this.redeemedTotal)); - expect(await this.market.balanceOfCoupons(userAddress, 1)).to.be.bignumber.closeTo(new BN(this.couponAmount - this.redeemedAmount), new BN(1)); - }); - - it('updates dao balances', async function () { - expect(await this.dollar.balanceOf(this.market.address)).to.be.bignumber.closeTo(new BN(100000 - this.redeemedAmount), new BN(1)); - expect(await this.market.totalCoupons()).to.be.bignumber.closeTo(new BN(this.couponAmount - this.redeemedAmount), new BN(1)); - expect(await this.market.totalDebt()).to.be.bignumber.equal(new BN(0)); - expect(await this.market.totalRedeemable()).to.be.bignumber.closeTo(new BN(this.couponAmount - this.redeemedAmount), new BN(1)); - }); - - it('emits CouponRedemption event', async function () { - const event = await expectEvent.inTransaction(this.txHash, MockMarket, 'CouponRedemption', { - account: userAddress, - }); - - expect(event.args.epoch).to.be.bignumber.equal(new BN(1)); - expect(event.args.amount).to.be.bignumber.equal(new BN(50000)); - expect(event.args.couponAmount).to.be.bignumber.equal(new BN(this.couponAmount / 2)); - }); - }); - }); - - describe('after expired', function () { - this.timeout(30000); - - beforeEach(async function () { - await this.market.mintToE(this.market.address, 100000); - await this.market.incrementTotalBondedE(100000); - - for (let i = 0; i < 90; i++) { - await this.market.incrementEpochE(); - } - await this.market.stepE(); - - this.result = await this.market.redeemCoupons(1, this.couponUnderlying, {from: userAddress}); - this.txHash = this.result.tx; - }); - - it('updates user balances', async function () { - expect(await this.dollar.balanceOf(userAddress)).to.be.bignumber.equal(new BN(900000 + this.couponUnderlying)); - expect(await this.market.balanceOfCoupons(userAddress, 1)).to.be.bignumber.equal(new BN(0)); - expect(await this.market.balanceOfCouponUnderlying(userAddress, 1)).to.be.bignumber.equal(new BN(0)); - }); - - it('updates dao balances', async function () { - let extraBalance = 100000 - this.couponAmount; - let redeemableReturned = Math.floor(this.couponAmount * 0.775); - expect(await this.dollar.balanceOf(this.market.address)).to.be.bignumber.closeTo(new BN(100000 + extraBalance + redeemableReturned), new BN(1)); - expect(await this.market.totalCoupons()).to.be.bignumber.equal(new BN(0)); - expect(await this.market.totalCouponUnderlying()).to.be.bignumber.equal(new BN(0)); - expect(await this.market.totalDebt()).to.be.bignumber.equal(new BN(0)); - expect(await this.market.totalRedeemable()).to.be.bignumber.equal(new BN(0)); - }); - - it('emits CouponRedemption event', async function () { - const event = await expectEvent.inTransaction(this.txHash, MockMarket, 'CouponRedemption', { - account: userAddress, - }); - - expect(event.args.epoch).to.be.bignumber.equal(new BN(1)); - expect(event.args.amount).to.be.bignumber.equal(new BN(this.couponUnderlying)); - expect(event.args.couponAmount).to.be.bignumber.equal(new BN(0)); - }); - }); - }); - - describe('redeemCoupons - prorated', function () { - beforeEach(async function () { - await this.market.incrementTotalDebtE(100000); - await this.market.purchaseCoupons(100000, {from: userAddress}); - await this.market.mintToE(this.market.address, 100000); - - this.couponUnderlying = 100000; - this.couponAmount = premium(1000000, 100000, 100000); - - const coupons = (await this.market.balanceOfCoupons(userAddress, 1)).toString(); - const underlying = (await this.market.balanceOfCouponUnderlying(userAddress, 1)).toString(); - - await this.market.incrementTotalRedeemableE(this.couponAmount); - }); - - describe('before redeemable', function () { - describe('same epoch', function () { - it('reverts', async function () { - await expectRevert(this.market.redeemCoupons(1, this.couponUnderlying, {from: userAddress}), "Market: Too early to redeem"); - }); - }); - - describe('next epoch', function () { - it('reverts', async function () { - await this.market.incrementEpochE(); - await expectRevert(this.market.redeemCoupons(1, this.couponUnderlying, {from: userAddress}), "Market: Too early to redeem"); - }); - }); - }); - - describe('after redeemable', function () { - beforeEach(async function () { - await this.market.incrementEpochE(); - await this.market.incrementEpochE(); - await this.market.updateEraE(0); // expansion - }); - - describe('not enough coupon balance', function () { - it('reverts', async function () { - await expectRevert(this.market.redeemCoupons(1, this.couponUnderlying + 1, {from: userAddress}), "Market: Insufficient coupon underlying balance"); - }); - }); - - describe('on single call', function () { - beforeEach(async function () { - this.result = await this.market.redeemCoupons(1, this.couponUnderlying, {from: userAddress}); - this.txHash = this.result.tx; - }); - - it('updates user balances', async function () { - expect(await this.dollar.balanceOf(userAddress)).to.be.bignumber.equal(new BN(900000 + this.couponUnderlying + prorated(this.couponAmount, 1))); - expect(await this.market.balanceOfCoupons(userAddress, 1)).to.be.bignumber.equal(new BN(0)); - expect(await this.market.balanceOfCouponUnderlying(userAddress, 1)).to.be.bignumber.equal(new BN(0)); - }); - - it('updates dao balances', async function () { - expect(await this.dollar.balanceOf(this.market.address)).to.be.bignumber.equal(new BN(100000 - prorated(this.couponAmount, 1))); - expect(await this.market.totalCoupons()).to.be.bignumber.equal(new BN(0)); - expect(await this.market.totalCouponUnderlying()).to.be.bignumber.equal(new BN(0)); - expect(await this.market.totalDebt()).to.be.bignumber.equal(new BN(0)); - expect(await this.market.totalRedeemable()).to.be.bignumber.equal(new BN(this.couponAmount - prorated(this.couponAmount, 1))); - }); - - it('emits CouponRedemption event', async function () { - const event = await expectEvent.inTransaction(this.txHash, MockMarket, 'CouponRedemption', { - account: userAddress, - }); - - expect(event.args.epoch).to.be.bignumber.equal(new BN(1)); - expect(event.args.amount).to.be.bignumber.equal(new BN(this.couponUnderlying)); - expect(event.args.couponAmount).to.be.bignumber.equal(new BN(this.couponAmount)); + expect(event.args.couponAmount).to.be.bignumber.equal(new BN(100000)); }); }); @@ -467,20 +210,18 @@ describe('Market', function () { this.result = await this.market.redeemCoupons(1, 30000, {from: userAddress}); this.result = await this.market.redeemCoupons(1, 50000, {from: userAddress}); this.txHash = this.result.tx; - this.redeemedAmount = (this.couponAmount) * 8 / 10; - this.redeemedTotal = (this.couponUnderlying + prorated(this.couponAmount, 1)) * 8 / 10; }); it('updates user balances', async function () { - expect(await this.dollar.balanceOf(userAddress)).to.be.bignumber.equal(new BN(900000 + this.redeemedTotal)); - expect(await this.market.balanceOfCoupons(userAddress, 1)).to.be.bignumber.closeTo(new BN(this.couponAmount - this.redeemedAmount), new BN(1)); + expect(await this.dollar.balanceOf(userAddress)).to.be.bignumber.equal(new BN(980000)); + expect(await this.market.balanceOfCoupons(userAddress, 1)).to.be.bignumber.equal(new BN(20000 + premium(1000000, 100000, 100000))); }); it('updates dao balances', async function () { - expect(await this.dollar.balanceOf(this.market.address)).to.be.bignumber.closeTo(new BN(100000 - prorated(this.redeemedAmount, 1)), new BN(1)); - expect(await this.market.totalCoupons()).to.be.bignumber.closeTo(new BN(this.couponAmount - this.redeemedAmount), new BN(1)); + expect(await this.dollar.balanceOf(this.market.address)).to.be.bignumber.equal(new BN(20000)); + expect(await this.market.totalCoupons()).to.be.bignumber.equal(new BN(20000 + premium(1000000, 100000, 100000))); expect(await this.market.totalDebt()).to.be.bignumber.equal(new BN(0)); - expect(await this.market.totalRedeemable()).to.be.bignumber.closeTo(new BN(this.couponAmount - prorated(this.redeemedAmount, 1)), new BN(1)); + expect(await this.market.totalRedeemable()).to.be.bignumber.equal(new BN(20000)); }); it('emits CouponRedemption event', async function () { @@ -489,8 +230,7 @@ describe('Market', function () { }); expect(event.args.epoch).to.be.bignumber.equal(new BN(1)); - expect(event.args.amount).to.be.bignumber.equal(new BN(50000)); - expect(event.args.couponAmount).to.be.bignumber.equal(new BN(this.couponAmount / 2)); + expect(event.args.couponAmount).to.be.bignumber.equal(new BN(50000)); }); }); }); @@ -499,42 +239,14 @@ describe('Market', function () { this.timeout(30000); beforeEach(async function () { - await this.market.mintToE(this.market.address, 100000); - await this.market.incrementTotalBondedE(100000); - for (let i = 0; i < 90; i++) { await this.market.incrementEpochE(); } await this.market.stepE(); - - this.result = await this.market.redeemCoupons(1, this.couponUnderlying, {from: userAddress}); - this.txHash = this.result.tx; }); - it('updates user balances', async function () { - expect(await this.dollar.balanceOf(userAddress)).to.be.bignumber.equal(new BN(900000 + this.couponUnderlying)); - expect(await this.market.balanceOfCoupons(userAddress, 1)).to.be.bignumber.equal(new BN(0)); - expect(await this.market.balanceOfCouponUnderlying(userAddress, 1)).to.be.bignumber.equal(new BN(0)); - }); - - it('updates dao balances', async function () { - let extraBalance = 100000 - this.couponAmount; - let redeemableReturned = Math.floor(this.couponAmount * 0.775); - expect(await this.dollar.balanceOf(this.market.address)).to.be.bignumber.closeTo(new BN(100000 + extraBalance + redeemableReturned), new BN(1)); - expect(await this.market.totalCoupons()).to.be.bignumber.equal(new BN(0)); - expect(await this.market.totalCouponUnderlying()).to.be.bignumber.equal(new BN(0)); - expect(await this.market.totalDebt()).to.be.bignumber.equal(new BN(0)); - expect(await this.market.totalRedeemable()).to.be.bignumber.equal(new BN(0)); - }); - - it('emits CouponRedemption event', async function () { - const event = await expectEvent.inTransaction(this.txHash, MockMarket, 'CouponRedemption', { - account: userAddress, - }); - - expect(event.args.epoch).to.be.bignumber.equal(new BN(1)); - expect(event.args.amount).to.be.bignumber.equal(new BN(this.couponUnderlying)); - expect(event.args.couponAmount).to.be.bignumber.equal(new BN(0)); + it('reverts', async function () { + await expectRevert(this.market.redeemCoupons(1, 100000, {from: userAddress}), "Market: Insufficient coupon balance"); }); }); }); @@ -608,15 +320,13 @@ describe('Market', function () { describe('on call from self', function () { beforeEach(async function () { - this.result = await this.market.transferCoupons(userAddress, ownerAddress, 1, 50000, {from: userAddress}); + this.result = await this.market.transferCoupons(userAddress, ownerAddress, 1, 100000, {from: userAddress}); this.txHash = this.result.tx; }); it('updates balances', async function () { - expect(await this.market.balanceOfCoupons(userAddress, 1)).to.be.bignumber.closeTo(new BN(premium(1000000, 100000, 100000)).divn(2), new BN(1)); - expect(await this.market.balanceOfCouponUnderlying(userAddress, 1)).to.be.bignumber.equal(new BN(50000)); - expect(await this.market.balanceOfCoupons(ownerAddress, 1)).to.be.bignumber.closeTo(new BN(premium(1000000, 100000, 100000)).divn(2), new BN(1)); - expect(await this.market.balanceOfCouponUnderlying(ownerAddress, 1)).to.be.bignumber.equal(new BN(50000)); + expect(await this.market.balanceOfCoupons(userAddress, 1)).to.be.bignumber.equal(new BN(premium(1000000, 100000, 100000))); + expect(await this.market.balanceOfCoupons(ownerAddress, 1)).to.be.bignumber.equal(new BN(100000)); }); it('emits CouponTransfer event', async function () { @@ -626,13 +336,13 @@ describe('Market', function () { }); expect(event.args.epoch).to.be.bignumber.equal(new BN(1)); - expect(event.args.value).to.be.bignumber.equal(new BN(50000)); + expect(event.args.value).to.be.bignumber.equal(new BN(100000)); }); }); describe('on call from self too much', function () { it('reverts', async function () { - await expectRevert(this.market.transferCoupons(userAddress, ownerAddress, 1, 200000, {from: ownerAddress}), "Market: Insufficient coupon underlying balance"); + await expectRevert(this.market.transferCoupons(userAddress, ownerAddress, 1, 200000, {from: ownerAddress}), "Market: Insufficient coupon balance"); }); }); @@ -644,16 +354,14 @@ describe('Market', function () { describe('on approved call from other', function () { beforeEach(async function () { - await this.market.approveCoupons(ownerAddress, 50000, {from: userAddress}); - this.result = await this.market.transferCoupons(userAddress, ownerAddress, 1, 50000, {from: ownerAddress}); + await this.market.approveCoupons(ownerAddress, 100000, {from: userAddress}); + this.result = await this.market.transferCoupons(userAddress, ownerAddress, 1, 100000, {from: ownerAddress}); this.txHash = this.result.tx; }); it('updates balances', async function () { - expect(await this.market.balanceOfCoupons(userAddress, 1)).to.be.bignumber.closeTo(new BN(premium(1000000, 100000, 100000)).divn(2), new BN(1)); - expect(await this.market.balanceOfCouponUnderlying(userAddress, 1)).to.be.bignumber.equal(new BN(50000)); - expect(await this.market.balanceOfCoupons(ownerAddress, 1)).to.be.bignumber.closeTo(new BN(premium(1000000, 100000, 100000)).divn(2), new BN(1)); - expect(await this.market.balanceOfCouponUnderlying(ownerAddress, 1)).to.be.bignumber.equal(new BN(50000)); + expect(await this.market.balanceOfCoupons(userAddress, 1)).to.be.bignumber.equal(new BN(premium(1000000, 100000, 100000))); + expect(await this.market.balanceOfCoupons(ownerAddress, 1)).to.be.bignumber.equal(new BN(100000)); }); it('updates approval', async function () { @@ -667,7 +375,7 @@ describe('Market', function () { }); expect(event.args.epoch).to.be.bignumber.equal(new BN(1)); - expect(event.args.value).to.be.bignumber.equal(new BN(50000)); + expect(event.args.value).to.be.bignumber.equal(new BN(100000)); }); }); @@ -718,8 +426,7 @@ describe('Market', function () { const event = await expectEvent.inTransaction(this.txHash, MockMarket, 'CouponExpiration', { }); expect(event.args.epoch).to.be.bignumber.equal(new BN(2)); - expect(event.args.couponsExpired).to.be.bignumber.equal(new BN(premium(1000000, 100000, 100000))); - expect(event.args.lessRedeemable).to.be.bignumber.equal(new BN(0)); + expect(event.args.couponsExpired).to.be.bignumber.equal(new BN(100000 + premium(1000000, 100000, 100000))); expect(event.args.lessDebt).to.be.bignumber.equal(new BN(0)); expect(event.args.newBonded).to.be.bignumber.equal(new BN(0)); }); @@ -733,7 +440,7 @@ describe('Market', function () { await this.market.purchaseCoupons(100000, {from: userAddress}); await this.market.mintToE(this.market.address, 100000); - await this.market.incrementTotalRedeemableE(premium(1000000, 100000, 100000)); + await this.market.incrementTotalRedeemableE(100000); await this.market.incrementEpochE(); this.result = await this.market.stepE(); @@ -749,10 +456,10 @@ describe('Market', function () { const event = await expectEvent.inTransaction(this.txHash, MockMarket, 'CouponExpiration', { }); expect(event.args.epoch).to.be.bignumber.equal(new BN(2)); - expect(event.args.couponsExpired).to.be.bignumber.equal(new BN(premium(1000000, 100000, 100000))); - expect(event.args.lessRedeemable).to.be.bignumber.equal(new BN(premium(1000000, 100000, 100000))); + expect(event.args.couponsExpired).to.be.bignumber.equal(new BN(100000 + premium(1000000, 100000, 100000))); + expect(event.args.lessRedeemable).to.be.bignumber.equal(new BN(100000)); expect(event.args.lessDebt).to.be.bignumber.equal(new BN(0)); - expect(event.args.newBonded).to.be.bignumber.equal(new BN(premium(1000000, 100000, 100000)).muln(225).divn(1000)); + expect(event.args.newBonded).to.be.bignumber.equal(new BN(22500)); }); }); @@ -770,7 +477,7 @@ describe('Market', function () { await this.market.purchaseCoupons(100000, {from: userAddress}); await this.market.mintToE(this.market.address, 100000); - await this.market.incrementTotalRedeemableE(premium(1100000, 100000, 100000)); + await this.market.incrementTotalRedeemableE(100000); await this.market.incrementEpochE(); this.result = await this.market.stepE(); @@ -786,10 +493,10 @@ describe('Market', function () { const event = await expectEvent.inTransaction(this.txHash, MockMarket, 'CouponExpiration', { }); expect(event.args.epoch).to.be.bignumber.equal(new BN(2)); - expect(event.args.couponsExpired).to.be.bignumber.closeTo(new BN(premium(1100000, 100000, 100000)), new BN(1)); - expect(event.args.lessRedeemable).to.be.bignumber.equal(new BN(premium(1100000, 100000, 100000))); + expect(event.args.couponsExpired).to.be.bignumber.closeTo(new BN(100000 + premium(1100000, 100000, 100000)), new BN(1)); + expect(event.args.lessRedeemable).to.be.bignumber.equal(new BN(100000)); expect(event.args.lessDebt).to.be.bignumber.equal(new BN(0)); - expect(event.args.newBonded).to.be.bignumber.equal(new BN(new BN(premium(1100000, 100000, 100000)))); + expect(event.args.newBonded).to.be.bignumber.equal(new BN(100000)); }); }); @@ -803,11 +510,8 @@ describe('Market', function () { await this.market.incrementEpochE(); await this.market.purchaseCoupons(50000, {from: userAddress}); - this.couponAmount = premium(1100000, 100000, 50000) + premium(1050000, 50000, 50000); - await this.market.mintToE(this.market.address, 100000); - await this.market.incrementTotalRedeemableE(this.couponAmount); - + await this.market.incrementTotalRedeemableE(100000); this.result = await this.market.stepE(); @@ -822,9 +526,9 @@ describe('Market', function () { const event = await expectEvent.inTransaction(this.txHash, MockMarket, 'CouponExpiration', { }); expect(event.args.epoch).to.be.bignumber.equal(new BN(2)); - expect(event.args.couponsExpired).to.be.bignumber.equal(new BN(premium(1100000, 100000, 50000))); + expect(event.args.couponsExpired).to.be.bignumber.equal(new BN(50000 + premium(1100000, 100000, 50000))); expect(event.args.lessDebt).to.be.bignumber.equal(new BN(0)); - expect(event.args.newBonded).to.be.bignumber.closeTo(new BN(this.couponAmount - premium(1050000, 50000, 50000)), new BN(1)); + expect(event.args.newBonded).to.be.bignumber.closeTo(new BN(100000 - 50000 - premium(1050000, 50000, 50000)), new BN(1)); }); }); @@ -838,10 +542,8 @@ describe('Market', function () { await this.market.incrementEpochE(); await this.market.purchaseCoupons(50000, {from: userAddress}); - this.couponAmount = premium(1100000, 150000, 50000) + premium(1050000, 100000, 50000); - await this.market.mintToE(this.market.address, 100000); - await this.market.incrementTotalRedeemableE(this.couponAmount); + await this.market.incrementTotalRedeemableE(100000); this.result = await this.market.stepE(); @@ -856,10 +558,10 @@ describe('Market', function () { const event = await expectEvent.inTransaction(this.txHash, MockMarket, 'CouponExpiration', { }); expect(event.args.epoch).to.be.bignumber.equal(new BN(2)); - expect(event.args.couponsExpired).to.be.bignumber.equal(new BN(premium(1100000, 150000, 50000))); - expect(event.args.lessRedeemable).to.be.bignumber.equal(new BN(this.couponAmount - premium(1050000, 100000, 50000))); + expect(event.args.couponsExpired).to.be.bignumber.equal(new BN(50000 + premium(1100000, 150000, 50000))); + expect(event.args.lessRedeemable).to.be.bignumber.equal(new BN(100000 - 50000 - premium(1050000, 100000, 50000))); expect(event.args.lessDebt).to.be.bignumber.equal(new BN(0)); - expect(event.args.newBonded).to.be.bignumber.equal(new BN(this.couponAmount - premium(1050000, 100000, 50000))); + expect(event.args.newBonded).to.be.bignumber.equal(new BN(100000 - 50000 - premium(1050000, 100000, 50000))); }); }); @@ -873,12 +575,10 @@ describe('Market', function () { await this.market.incrementEpochE(); await this.market.purchaseCoupons(50000, {from: userAddress}); - this.couponAmount = premium(1100000, 120000, 50000) + premium(1050000, 70000, 50000); - await this.market.mintToE(this.market.address, 100000); - await this.market.incrementTotalRedeemableE(this.couponAmount); + await this.market.incrementTotalRedeemableE(100000); - this.result = await this.market.stepE() + this.result = await this.market.stepE(); for (let i = 0; i < 89; i++) { await this.market.incrementEpochE(); @@ -891,10 +591,10 @@ describe('Market', function () { const event = await expectEvent.inTransaction(this.txHash, MockMarket, 'CouponExpiration', { }); expect(event.args.epoch).to.be.bignumber.equal(new BN(2)); - expect(event.args.couponsExpired).to.be.bignumber.equal(new BN(premium(1100000, 120000, 50000))); - expect(event.args.lessRedeemable).to.be.bignumber.equal(new BN(this.couponAmount - premium(1050000, 70000, 50000))); + expect(event.args.couponsExpired).to.be.bignumber.equal(new BN(50000 + premium(1100000, 120000, 50000))); + expect(event.args.lessRedeemable).to.be.bignumber.equal(new BN(100000 - 50000 - premium(1050000, 70000, 50000))); expect(event.args.lessDebt).to.be.bignumber.equal(new BN(0)); - expect(event.args.newBonded).to.be.bignumber.equal(new BN(this.couponAmount - premium(1050000, 70000, 50000))); + expect(event.args.newBonded).to.be.bignumber.equal(new BN(100000 - 50000 - premium(1050000, 70000, 50000))); }); }); }); diff --git a/protocol/test/dao/Regulator.test.js b/protocol/test/dao/Regulator.test.js index 750b347e..670cf683 100644 --- a/protocol/test/dao/Regulator.test.js +++ b/protocol/test/dao/Regulator.test.js @@ -42,10 +42,6 @@ describe('Regulator', function () { }); describe('up regulation', function () { - beforeEach(async function () { - await this.regulator.updateEraE(1); - }); - describe('above limit', function () { beforeEach(async function () { await this.regulator.incrementEpochE(); // 1 @@ -79,11 +75,6 @@ describe('Regulator', function () { expect(await this.regulator.totalRedeemable()).to.be.bignumber.equal(new BN(0)); }); - it('updates era', async function () { - expect(await this.regulator.eraStatus()).to.be.bignumber.equal(new BN(0)); - expect(await this.regulator.eraStart()).to.be.bignumber.equal(new BN(7)); - }); - it('emits SupplyIncrease event', async function () { const event = await expectEvent.inTransaction(this.txHash, MockRegulator, 'SupplyIncrease', {}); @@ -130,11 +121,6 @@ describe('Regulator', function () { expect(await this.regulator.totalRedeemable()).to.be.bignumber.equal(new BN(0)); }); - it('updates era', async function () { - expect(await this.regulator.eraStatus()).to.be.bignumber.equal(new BN(0)); - expect(await this.regulator.eraStart()).to.be.bignumber.equal(new BN(7)); - }); - it('emits SupplyIncrease event', async function () { const event = await expectEvent.inTransaction(this.txHash, MockRegulator, 'SupplyIncrease', {}); @@ -189,11 +175,6 @@ describe('Regulator', function () { expect(await this.regulator.totalRedeemable()).to.be.bignumber.equal(new BN(this.expectedRewardCoupons)); }); - it('updates era', async function () { - expect(await this.regulator.eraStatus()).to.be.bignumber.equal(new BN(0)); - expect(await this.regulator.eraStart()).to.be.bignumber.equal(new BN(7)); - }); - it('emits SupplyIncrease event', async function () { const event = await expectEvent.inTransaction(this.txHash, MockRegulator, 'SupplyIncrease', {}); @@ -205,67 +186,63 @@ describe('Regulator', function () { }); }); }); + }); - describe('(1 + 2) - refresh redeemable then mint to bonded', function () { - beforeEach(async function () { - await this.regulator.incrementEpochE(); // 1 - - await this.regulator.incrementTotalBondedE(1000000); - await this.regulator.mintToE(this.regulator.address, 1000000); + describe('(1 + 2) - refresh redeemable then mint to bonded', function () { + beforeEach(async function () { + await this.regulator.incrementEpochE(); // 1 - await this.regulator.increaseDebtE(new BN(2000)); - await this.regulator.incrementBalanceOfCouponsE(userAddress, 1, new BN(2000)); + await this.regulator.incrementTotalBondedE(1000000); + await this.regulator.mintToE(this.regulator.address, 1000000); - await this.regulator.incrementEpochE(); // 2 + await this.regulator.increaseDebtE(new BN(2000)); + await this.regulator.incrementBalanceOfCouponsE(userAddress, 1, new BN(2000)); - }); + await this.regulator.incrementEpochE(); // 2 - describe('on step', function () { - beforeEach(async function () { - await this.oracle.set(101, 100, true); - this.bondedReward = 5750; - this.newRedeemable = 2000; - this.poolReward = 2000; - this.treasuryReward = 250; + }); - this.result = await this.regulator.stepE(); - this.txHash = this.result.tx; - }); + describe('on step', function () { + beforeEach(async function () { + await this.oracle.set(101, 100, true); + this.bondedReward = 5750; + this.newRedeemable = 2000; + this.poolReward = 2000; + this.treasuryReward = 250; - it('mints new Dollar tokens', async function () { - expect(await this.dollar.totalSupply()).to.be.bignumber.equal(new BN(1010000)); - expect(await this.dollar.balanceOf(this.regulator.address)).to.be.bignumber.equal(new BN(1000000 + this.newRedeemable + this.bondedReward)); - expect(await this.dollar.balanceOf(poolAddress)).to.be.bignumber.equal(new BN(this.poolReward)); - expect(await this.dollar.balanceOf(TREASURY_ADDRESS)).to.be.bignumber.equal(new BN(this.treasuryReward)); - }); + this.result = await this.regulator.stepE(); + this.txHash = this.result.tx; + }); - it('updates totals', async function () { - expect(await this.regulator.totalStaged()).to.be.bignumber.equal(new BN(0)); - expect(await this.regulator.totalBonded()).to.be.bignumber.equal(new BN(1000000 + this.bondedReward)); - expect(await this.regulator.totalDebt()).to.be.bignumber.equal(new BN(0)); - expect(await this.regulator.totalSupply()).to.be.bignumber.equal(new BN(0)); - expect(await this.regulator.totalCoupons()).to.be.bignumber.equal(new BN(2000)); - expect(await this.regulator.totalRedeemable()).to.be.bignumber.equal(new BN(2000)); - }); + it('mints new Dollar tokens', async function () { + expect(await this.dollar.totalSupply()).to.be.bignumber.equal(new BN(1010000)); + expect(await this.dollar.balanceOf(this.regulator.address)).to.be.bignumber.equal(new BN(1000000 + this.newRedeemable + this.bondedReward)); + expect(await this.dollar.balanceOf(poolAddress)).to.be.bignumber.equal(new BN(this.poolReward)); + expect(await this.dollar.balanceOf(TREASURY_ADDRESS)).to.be.bignumber.equal(new BN(this.treasuryReward)); + }); - it('updates era', async function () { - expect(await this.regulator.eraStatus()).to.be.bignumber.equal(new BN(0)); - expect(await this.regulator.eraStart()).to.be.bignumber.equal(new BN(7)); - }); + it('updates totals', async function () { + expect(await this.regulator.totalStaged()).to.be.bignumber.equal(new BN(0)); + expect(await this.regulator.totalBonded()).to.be.bignumber.equal(new BN(1000000 + this.bondedReward)); + expect(await this.regulator.totalDebt()).to.be.bignumber.equal(new BN(0)); + expect(await this.regulator.totalSupply()).to.be.bignumber.equal(new BN(0)); + expect(await this.regulator.totalCoupons()).to.be.bignumber.equal(new BN(2000)); + expect(await this.regulator.totalRedeemable()).to.be.bignumber.equal(new BN(2000)); + }); - it('emits SupplyIncrease event', async function () { - const event = await expectEvent.inTransaction(this.txHash, MockRegulator, 'SupplyIncrease', {}); + it('emits SupplyIncrease event', async function () { + const event = await expectEvent.inTransaction(this.txHash, MockRegulator, 'SupplyIncrease', {}); - expect(event.args.epoch).to.be.bignumber.equal(new BN(7)); - expect(event.args.price).to.be.bignumber.equal(new BN(101).mul(new BN(10).pow(new BN(16)))); - expect(event.args.newRedeemable).to.be.bignumber.equal(new BN(2000)); - expect(event.args.lessDebt).to.be.bignumber.equal(new BN(2000)); - expect(event.args.newBonded).to.be.bignumber.equal(new BN(8000)); - }); + expect(event.args.epoch).to.be.bignumber.equal(new BN(7)); + expect(event.args.price).to.be.bignumber.equal(new BN(101).mul(new BN(10).pow(new BN(16)))); + expect(event.args.newRedeemable).to.be.bignumber.equal(new BN(2000)); + expect(event.args.lessDebt).to.be.bignumber.equal(new BN(2000)); + expect(event.args.newBonded).to.be.bignumber.equal(new BN(8000)); }); }); + }); - describe('(3) - above limit but below coupon limit', function () { + describe('(3) - above limit but below coupon limit', function () { beforeEach(async function () { await this.regulator.incrementEpochE(); // 1 @@ -307,11 +284,6 @@ describe('Regulator', function () { expect(await this.regulator.totalRedeemable()).to.be.bignumber.equal(new BN(this.expectedRewardCoupons)); }); - it('updates era', async function () { - expect(await this.regulator.eraStatus()).to.be.bignumber.equal(new BN(0)); - expect(await this.regulator.eraStart()).to.be.bignumber.equal(new BN(7)); - }); - it('emits SupplyIncrease event', async function () { const event = await expectEvent.inTransaction(this.txHash, MockRegulator, 'SupplyIncrease', {}); @@ -322,13 +294,9 @@ describe('Regulator', function () { expect(event.args.newBonded).to.be.bignumber.equal(new BN(this.expectedRewardLP + this.expectedRewardDAO + this.expectedRewardTreasury)); }); }); - }); }); - describe('down regulation', function () { - beforeEach(async function () { - await this.regulator.updateEraE(0); - }); + describe('down regulation', function () { describe('under limit', function () { beforeEach(async function () { await this.regulator.incrementEpochE(); // 1 @@ -364,11 +332,6 @@ describe('Regulator', function () { expect(await this.regulator.totalRedeemable()).to.be.bignumber.equal(new BN(0)); }); - it('updates era', async function () { - expect(await this.regulator.eraStatus()).to.be.bignumber.equal(new BN(1)); - expect(await this.regulator.eraStart()).to.be.bignumber.equal(new BN(8)); - }); - it('emits SupplyDecrease event', async function () { const event = await expectEvent.inTransaction(this.txHash, MockRegulator, 'SupplyDecrease', {}); @@ -414,11 +377,6 @@ describe('Regulator', function () { expect(await this.regulator.totalRedeemable()).to.be.bignumber.equal(new BN(0)); }); - it('updates era', async function () { - expect(await this.regulator.eraStatus()).to.be.bignumber.equal(new BN(1)); - expect(await this.regulator.eraStart()).to.be.bignumber.equal(new BN(7)); - }); - it('emits SupplyDecrease event', async function () { const event = await expectEvent.inTransaction(this.txHash, MockRegulator, 'SupplyDecrease', {}); @@ -467,11 +425,6 @@ describe('Regulator', function () { }); }); - it('updates era', async function () { - expect(await this.regulator.eraStatus()).to.be.bignumber.equal(new BN(1)); - expect(await this.regulator.eraStart()).to.be.bignumber.equal(new BN(7)); - }); - it('emits SupplyDecrease event', async function () { const event = await expectEvent.inTransaction(this.txHash, MockRegulator, 'SupplyDecrease', {}); @@ -520,11 +473,6 @@ describe('Regulator', function () { }); }); - it('updates era', async function () { - expect(await this.regulator.eraStatus()).to.be.bignumber.equal(new BN(1)); - expect(await this.regulator.eraStart()).to.be.bignumber.equal(new BN(7)); - }); - it('emits SupplyDecrease event', async function () { const event = await expectEvent.inTransaction(this.txHash, MockRegulator, 'SupplyDecrease', {}); @@ -573,11 +521,6 @@ describe('Regulator', function () { }); }); - it('updates era', async function () { - expect(await this.regulator.eraStatus()).to.be.bignumber.equal(new BN(1)); - expect(await this.regulator.eraStart()).to.be.bignumber.equal(new BN(7)); - }); - it('emits SupplyDecrease event', async function () { const event = await expectEvent.inTransaction(this.txHash, MockRegulator, 'SupplyDecrease', {}); @@ -626,11 +569,6 @@ describe('Regulator', function () { }); }); - it('updates era', async function () { - expect(await this.regulator.eraStatus()).to.be.bignumber.equal(new BN(1)); - expect(await this.regulator.eraStart()).to.be.bignumber.equal(new BN(7)); - }); - it('emits SupplyDecrease event', async function () { const event = await expectEvent.inTransaction(this.txHash, MockRegulator, 'SupplyDecrease', {}); @@ -650,6 +588,7 @@ describe('Regulator', function () { await this.regulator.mintToE(this.regulator.address, 1000000); await this.regulator.incrementEpochE(); // 2 + }); describe('on step', function () { @@ -679,32 +618,6 @@ describe('Regulator', function () { expect(event.args.epoch).to.be.bignumber.equal(new BN(7)); }); - - describe('from contraction', function () { - beforeEach(async function () { - await this.regulator.updateEraE(1); - await this.regulator.incrementEpochE(); // 3 - await this.regulator.stepE(); - }); - - it('updates era', async function () { - expect(await this.regulator.eraStatus()).to.be.bignumber.equal(new BN(1)); - expect(await this.regulator.eraStart()).to.be.bignumber.equal(new BN(7)); - }); - }); - - describe('from expansion', function () { - beforeEach(async function () { - await this.regulator.updateEraE(0); - await this.regulator.incrementEpochE(); // 3 - await this.regulator.stepE(); - }); - - it('updates era', async function () { - expect(await this.regulator.eraStatus()).to.be.bignumber.equal(new BN(0)); - expect(await this.regulator.eraStart()).to.be.bignumber.equal(new BN(7)); - }); - }); }); }); diff --git a/protocol/test/dao/State.test.js b/protocol/test/dao/State.test.js index b5bf5e8b..33f4d850 100644 --- a/protocol/test/dao/State.test.js +++ b/protocol/test/dao/State.test.js @@ -23,13 +23,13 @@ describe('State', function () { describe('erc20 details', function () { describe('name', function () { it('increments total bonded', async function () { - expect(await this.setters.name()).to.be.equal("Empty Set Dollar Stake"); + expect(await this.setters.name()).to.be.equal("Universal Dollar Stake"); }); }); describe('symbol', function () { it('increments total bonded', async function () { - expect(await this.setters.symbol()).to.be.equal("ESDS"); + expect(await this.setters.symbol()).to.be.equal("U8DS"); }); }); @@ -211,43 +211,6 @@ describe('State', function () { }); }); - describe('updateEra', function () { - beforeEach('call', async function () { - await this.setters.incrementEpochE(); - }); - - describe('before called', function () { - it('is 0', async function () { - expect(await this.setters.eraStatus()).to.be.bignumber.equal(new BN(0)); - expect(await this.setters.eraStart()).to.be.bignumber.equal(new BN(0)); - }); - }); - - describe('when called change', function () { - beforeEach('call', async function () { - await this.setters.updateEraE(1); - }); - - it('is update', async function () { - expect(await this.setters.eraStatus()).to.be.bignumber.equal(new BN(1)); - expect(await this.setters.eraStart()).to.be.bignumber.equal(new BN(1)); - }); - }); - - describe('when called twi', function () { - beforeEach('call', async function () { - await this.setters.updateEraE(1); - await this.setters.incrementEpochE(); - await this.setters.updateEraE(0); - }); - - it('is update', async function () { - expect(await this.setters.eraStatus()).to.be.bignumber.equal(new BN(0)); - expect(await this.setters.eraStart()).to.be.bignumber.equal(new BN(2)); - }); - }); - }); - /** * Account */ @@ -369,25 +332,6 @@ describe('State', function () { }); }); - describe('incrementBalanceOfCouponUnderlying', function () { - const epoch = 1; - - describe('when called', function () { - beforeEach('call', async function () { - await this.setters.incrementBalanceOfCouponUnderlyingE(userAddress, epoch, 100); - await this.setters.incrementBalanceOfCouponUnderlyingE(userAddress, epoch, 100); - }); - - it('increments balance of coupons for user during epoch', async function () { - expect(await this.setters.balanceOfCouponUnderlying(userAddress, epoch)).to.be.bignumber.equal(new BN(200)); - }); - - it('increments total outstanding coupons', async function () { - expect(await this.setters.totalCouponUnderlying()).to.be.bignumber.equal(new BN(200)); - }); - }); - }); - describe('decrementBalanceOfCoupons', function () { const epoch = 1; @@ -418,39 +362,7 @@ describe('State', function () { it('reverts', async function () { await expectRevert( - this.setters.decrementBalanceOfCouponsE(userAddress, 200, epoch, "decrementBalanceOfCouponsE"), - "decrementBalanceOfCoupons"); - }); - }); - }); - - describe('decrementBalanceOfCouponUnderlying', function () { - const epoch = 1; - - describe('when called', function () { - beforeEach('call', async function () { - await this.setters.incrementBalanceOfCouponUnderlyingE(userAddress, epoch, 500); - await this.setters.decrementBalanceOfCouponUnderlyingE(userAddress, epoch, 100, "decrementBalanceOfCouponsE - 1"); - await this.setters.decrementBalanceOfCouponUnderlyingE(userAddress, epoch, 100, "decrementBalanceOfCouponsE - 2"); - }); - - it('decrements balance of coupons for user during epoch', async function () { - expect(await this.setters.balanceOfCouponUnderlying(userAddress, epoch)).to.be.bignumber.equal(new BN(300)); - }); - - it('decrements total outstanding coupons', async function () { - expect(await this.setters.totalCouponUnderlying()).to.be.bignumber.equal(new BN(300)); - }); - }); - - describe('when called erroneously', function () { - beforeEach('call', async function () { - await this.setters.incrementBalanceOfCouponUnderlyingE(userAddress, epoch, 100); - }); - - it('reverts', async function () { - await expectRevert( - this.setters.decrementBalanceOfCouponUnderlyingE(userAddress, 200, epoch, "decrementBalanceOfCouponsE"), + this.setters.decrementBalanceOfCouponsE(200, epoch, "decrementBalanceOfCouponsE"), "decrementBalanceOfCouponsE"); }); }); diff --git a/protocol/test/oracle/Oracle.test.js b/protocol/test/oracle/Oracle.test.js index 4ccfb0b2..dd6b6de6 100644 --- a/protocol/test/oracle/Oracle.test.js +++ b/protocol/test/oracle/Oracle.test.js @@ -27,9 +27,9 @@ async function priceForToBN(oracle) { return (await oracle.latestPrice()).value; } -async function simulateTrade(amm, esd, usdc) { +async function simulateTrade(amm, dollar, usdc) { return await amm.simulateTrade( - new BN(esd).mul(new BN(10).pow(new BN(18))), + new BN(dollar).mul(new BN(10).pow(new BN(18))), new BN(usdc).mul(new BN(10).pow(new BN(6)))); } diff --git a/protocol/test/oracle/Pool.test.js b/protocol/test/oracle/Pool.test.js index f6dc4d76..b4d211e0 100644 --- a/protocol/test/oracle/Pool.test.js +++ b/protocol/test/oracle/Pool.test.js @@ -8,7 +8,7 @@ const MockToken = contract.fromArtifact('MockToken'); const MockUniswapV2PairLiquidity = contract.fromArtifact('MockUniswapV2PairLiquidity'); const MockSettableDAO = contract.fromArtifact('MockSettableDAO'); -const INITIAL_STAKE_MULTIPLE = new BN(10).pow(new BN(6)); // 100 ESD -> 100M ESDS +const INITIAL_STAKE_MULTIPLE = new BN(10).pow(new BN(6)); // 100 U8D -> 100M U8DS const FROZEN = new BN(0); const FLUID = new BN(1); @@ -23,7 +23,7 @@ describe('Pool', function () { beforeEach(async function () { this.dao = await MockSettableDAO.new({from: ownerAddress, gas: 8000000}); await this.dao.set(1); - this.dollar = await MockToken.new("Empty Set Dollar", "ESD", 18, {from: ownerAddress, gas: 8000000}); + this.dollar = await MockToken.new("Universal Dollar", "U8D", 18, {from: ownerAddress, gas: 8000000}); this.usdc = await MockToken.new("USD//C", "USDC", 18, {from: ownerAddress, gas: 8000000}); this.univ2 = await MockUniswapV2PairLiquidity.new({from: ownerAddress, gas: 8000000}); this.pool = await MockPool.new(this.usdc.address, {from: ownerAddress, gas: 8000000}); @@ -894,7 +894,7 @@ describe('Pool', function () { await incrementEpoch(this.dao); await this.dollar.mint(this.pool.address, 1000); - // 1000 ESD + 3000 USDC + // 1000 U8D + 3000 USDC await this.univ2.set(1000, 3000, 10); this.result = await this.pool.provide(1000, {from: userAddress}); diff --git a/protocol/test/oracle/PoolState.test.js b/protocol/test/oracle/PoolState.test.js index 4b536ff8..26daa67c 100644 --- a/protocol/test/oracle/PoolState.test.js +++ b/protocol/test/oracle/PoolState.test.js @@ -12,7 +12,7 @@ describe('PollState', function () { beforeEach(async function () { this.dao = await MockSettableDAO.new({from: ownerAddress}); - this.dollar = await MockToken.new("Empty Set Dollar", "ESD", 18, {from: ownerAddress}); + this.dollar = await MockToken.new("Universal Dollar", "U8D", 18, {from: ownerAddress}); this.setters = await MockPoolState.new({from: ownerAddress}); await this.setters.set(this.dao.address, this.dollar.address); }); diff --git a/protocol/test/token/Dollar.test.js b/protocol/test/token/Dollar.test.js index 158ae146..61288122 100644 --- a/protocol/test/token/Dollar.test.js +++ b/protocol/test/token/Dollar.test.js @@ -24,7 +24,7 @@ const permit = [ async function signPermit(dollar, privateKey, message) { const domainData = { - name: "Empty Set Dollar", + name: "Universal Dollar", version: "1", chainId: "1", verifyingContract: dollar, diff --git a/protocol/truffle.js b/protocol/truffle.js index 1235a24a..f197631e 100644 --- a/protocol/truffle.js +++ b/protocol/truffle.js @@ -18,9 +18,16 @@ * */ const PrivateKeyProvider = require('truffle-privatekey-provider'); -const privateKey = process.env.ESD_PRIVATE_KEY; -const infuraId = process.env.ESD_INFURA_ID; -const etherscanKey = process.env.ESD_ETHERSCAN_KEY; +const dotenv = require('dotenv'); +const path = require('path'); + +dotenv.config({ + path: path.resolve(__dirname, '.env'), +}); + +const privateKey = process.env.PRIVATE_KEY; +const infuraId = process.env.INFURA_ID; +const etherscanKey = process.env.ETHERSCAN_KEY; module.exports = { /** @@ -42,7 +49,7 @@ module.exports = { // development: { host: "127.0.0.1", // Localhost (default: none) - port: 7545, // Standard Ethereum port (default: none) + port: 8545, // Standard Ethereum port (default: none) network_id: "*", // Any network (default: none) gas: 8000000, }, @@ -52,8 +59,9 @@ module.exports = { provider: () => new PrivateKeyProvider(privateKey, 'https://mainnet.infura.io/v3/' + infuraId), network_id: 1, // Mainnet's id gas: 5500000, // Gas sent with each transaction (default: ~6700000) - gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei) - timeoutBlocks: 1440, // # of blocks before a deployment times out (minimum/default: 50) + gasPrice: 100e9, // 100 gwei (in wei) (default: 100 gwei) + timeoutBlocks: 1440, // # of blocks before a deployment times out (minimum/default: 50) + skipDryRun: true // Skip dry run before migrations? (default: false for public nets ) }, // Useful for deploying to a public network. @@ -61,7 +69,8 @@ module.exports = { ropsten: { provider: () => new PrivateKeyProvider(privateKey, 'https://ropsten.infura.io/v3/' + infuraId), network_id: 3, // Ropsten's id - gas: 5500000, // Ropsten has a lower block limit than mainnet + gas: 7500000, // Ropsten has a lower block limit than mainnet + gasPrice: 1e9, // 1 gwei (in wei) confirmations: 2, // # of confs to wait between deployments. (default: 0) timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50) skipDryRun: true // Skip dry run before migrations? (default: false for public nets ) @@ -70,12 +79,23 @@ module.exports = { rinkeby: { provider: () => new PrivateKeyProvider(privateKey, 'https://rinkeby.infura.io/v3/' + infuraId), network_id: 4, // rinkeby's id - gas: 5500000, // rinkeby has a lower block limit than mainnet + gas: 7500000, // rinkeby has a lower block limit than mainnet + gasPrice: 1e9, // 1 gwei (in wei) confirmations: 2, // # of confs to wait between deployments. (default: 0) timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50) skipDryRun: true // Skip dry run before migrations? (default: false for public nets ) }, + kovan: { + provider: () => new PrivateKeyProvider(privateKey, 'https://kovan.infura.io/v3/' + infuraId), + network_id: 42, // kovan's id + gas: 5500000, // kovan's gas limit + gasPrice: 1e9, // 1 gwei (in wei) + confirmations: 0, // # of confs to wait between deployments. (default: 0) + timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50) + skipDryRun: true // Skip dry run before migrations? (default: false for public nets ) + }, + // Useful for private networks // private: { // provider: () => new HDWalletProvider(mnemonic, `https://network.io`), @@ -86,7 +106,7 @@ module.exports = { // Set default mocha options here, use special reporters etc. mocha: { - // timeout: 100000 + timeout: 100000 }, // Configure your compilers