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:
-
-
-
-## 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).
+
## 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