Skip to content
This repository was archived by the owner on Aug 21, 2023. It is now read-only.

Commit dfa1cc5

Browse files
authored
Merge pull request #34 from bugout-dev/hotfix-security-fix
Pool creation can only be done by controller now.
2 parents 5be59e6 + 1ca03f8 commit dfa1cc5

5 files changed

Lines changed: 215 additions & 8 deletions

File tree

contracts/terminus/TerminusFacet.sol

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ contract TerminusFacet is ERC1155WithTerminusStorage {
3939
uint256[] amounts
4040
);
4141

42+
function setController(address newController) external {
43+
LibTerminus.enforceIsController();
44+
LibTerminus.setController(newController);
45+
}
46+
4247
function poolMintBatch(
4348
uint256 id,
4449
address[] memory toAddresses,
@@ -172,6 +177,7 @@ contract TerminusFacet is ERC1155WithTerminusStorage {
172177
}
173178

174179
function createSimplePool(uint256 _capacity) external returns (uint256) {
180+
LibTerminus.enforceIsController();
175181
LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage();
176182
uint256 requiredPayment = ts.poolBasePrice;
177183
IERC20 paymentTokenContract = _paymentTokenContract();
@@ -193,6 +199,7 @@ contract TerminusFacet is ERC1155WithTerminusStorage {
193199
bool _transferable,
194200
bool _burnable
195201
) external returns (uint256) {
202+
LibTerminus.enforceIsController();
196203
LibTerminus.TerminusStorage storage ts = LibTerminus.terminusStorage();
197204
// TODO(zomglings): Implement requiredPayment update based on pool features.
198205
uint256 requiredPayment = ts.poolBasePrice;

dao/TerminusFacet.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,12 @@ def set_contract_uri(self, _contract_uri: str, transaction_config) -> Any:
217217
self.assert_contract_is_instantiated()
218218
return self.contract.setContractURI(_contract_uri, transaction_config)
219219

220+
def set_controller(
221+
self, new_controller: ChecksumAddress, transaction_config
222+
) -> Any:
223+
self.assert_contract_is_instantiated()
224+
return self.contract.setController(new_controller, transaction_config)
225+
220226
def set_payment_token(
221227
self, new_payment_token: ChecksumAddress, transaction_config
222228
) -> Any:
@@ -536,6 +542,16 @@ def handle_set_contract_uri(args: argparse.Namespace) -> None:
536542
print(result)
537543

538544

545+
def handle_set_controller(args: argparse.Namespace) -> None:
546+
network.connect(args.network)
547+
contract = TerminusFacet(args.address)
548+
transaction_config = get_transaction_config(args)
549+
result = contract.set_controller(
550+
new_controller=args.new_controller, transaction_config=transaction_config
551+
)
552+
print(result)
553+
554+
539555
def handle_set_payment_token(args: argparse.Namespace) -> None:
540556
network.connect(args.network)
541557
contract = TerminusFacet(args.address)
@@ -834,6 +850,13 @@ def generate_cli() -> argparse.ArgumentParser:
834850
)
835851
set_contract_uri_parser.set_defaults(func=handle_set_contract_uri)
836852

853+
set_controller_parser = subcommands.add_parser("set-controller")
854+
add_default_arguments(set_controller_parser, True)
855+
set_controller_parser.add_argument(
856+
"--new-controller", required=True, help="Type: address"
857+
)
858+
set_controller_parser.set_defaults(func=handle_set_controller)
859+
837860
set_payment_token_parser = subcommands.add_parser("set-payment-token")
838861
add_default_arguments(set_payment_token_parser, True)
839862
set_payment_token_parser.add_argument(

dao/test_terminus.py

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import unittest
33

44
from brownie import accounts
5+
from brownie.exceptions import VirtualMachineError
56

67
from . import ERC20Facet, TerminusFacet, TerminusInitializer
78
from .core import facet_cut
@@ -32,6 +33,34 @@ def test_add_and_replace(self):
3233
self.assertEqual(controller, accounts[0].address)
3334

3435

36+
class TestController(TerminusTestCase):
37+
def test_set_controller_fails_when_not_called_by_controller(self):
38+
terminus_diamond_address = self.terminus_contracts["Diamond"]
39+
diamond_terminus = TerminusFacet.TerminusFacet(terminus_diamond_address)
40+
41+
with self.assertRaises(VirtualMachineError):
42+
diamond_terminus.set_controller(accounts[1].address, {"from": accounts[1]})
43+
44+
def test_set_controller_fails_when_not_called_by_controller_even_if_they_change_to_existing_controller(
45+
self,
46+
):
47+
terminus_diamond_address = self.terminus_contracts["Diamond"]
48+
diamond_terminus = TerminusFacet.TerminusFacet(terminus_diamond_address)
49+
50+
with self.assertRaises(VirtualMachineError):
51+
diamond_terminus.set_controller(accounts[0].address, {"from": accounts[1]})
52+
53+
def test_set_controller(self):
54+
terminus_diamond_address = self.terminus_contracts["Diamond"]
55+
diamond_terminus = TerminusFacet.TerminusFacet(terminus_diamond_address)
56+
57+
self.assertEqual(diamond_terminus.terminus_controller(), accounts[0].address)
58+
diamond_terminus.set_controller(accounts[3].address, {"from": accounts[0]})
59+
self.assertEqual(diamond_terminus.terminus_controller(), accounts[3].address)
60+
diamond_terminus.set_controller(accounts[0].address, {"from": accounts[3]})
61+
self.assertEqual(diamond_terminus.terminus_controller(), accounts[0].address)
62+
63+
3564
class TestContractURI(TerminusTestCase):
3665
def test_contract_uri(self):
3766
terminus_diamond_address = self.terminus_contracts["Diamond"]
@@ -64,12 +93,14 @@ def test_create_simple_pool(self):
6493
pool_base_price = diamond_terminus.pool_base_price()
6594
self.assertEqual(pool_base_price, 1000)
6695

96+
diamond_terminus.set_controller(accounts[1].address, {"from": accounts[0]})
97+
6798
diamond_moonstream.mint(accounts[1], 1000, {"from": accounts[0]})
6899
initial_payer_balance = diamond_moonstream.balance_of(accounts[1].address)
69100
initial_terminus_balance = diamond_moonstream.balance_of(
70101
terminus_diamond_address
71102
)
72-
initial_controller_balance = diamond_moonstream.balance_of(accounts[0].address)
103+
initial_controller_balance = diamond_moonstream.balance_of(accounts[1].address)
73104

74105
diamond_moonstream.approve(
75106
terminus_diamond_address, 1000, {"from": accounts[1]}
@@ -87,33 +118,35 @@ def test_create_simple_pool(self):
87118
terminus_diamond_address
88119
)
89120
intermediate_controller_balance = diamond_moonstream.balance_of(
90-
accounts[0].address
121+
accounts[1].address
91122
)
92123
self.assertEqual(final_payer_balance, initial_payer_balance - 1000)
93124
self.assertEqual(intermediate_terminus_balance, initial_terminus_balance + 1000)
94-
self.assertEqual(intermediate_controller_balance, initial_controller_balance)
125+
self.assertEqual(
126+
intermediate_controller_balance, initial_controller_balance - 1000
127+
)
95128

96129
with self.assertRaises(Exception):
97130
diamond_terminus.withdraw_payments(
98-
accounts[1].address, 1000, {"from": accounts[1]}
131+
accounts[0].address, 1000, {"from": accounts[0]}
99132
)
100133

101134
with self.assertRaises(Exception):
102135
diamond_terminus.withdraw_payments(
103-
accounts[0].address, 1000, {"from": accounts[1]}
136+
accounts[1].address, 1000, {"from": accounts[0]}
104137
)
105138

106139
with self.assertRaises(Exception):
107140
diamond_terminus.withdraw_payments(
108-
accounts[1].address, 1000, {"from": accounts[0]}
141+
accounts[0].address, 1000, {"from": accounts[1]}
109142
)
110143

111144
diamond_terminus.withdraw_payments(
112-
accounts[0].address, 1000, {"from": accounts[0]}
145+
accounts[1].address, 1000, {"from": accounts[1]}
113146
)
114147

115148
final_terminus_balance = diamond_moonstream.balance_of(terminus_diamond_address)
116-
final_controller_balance = diamond_moonstream.balance_of(accounts[0].address)
149+
final_controller_balance = diamond_moonstream.balance_of(accounts[1].address)
117150
self.assertEqual(final_terminus_balance, intermediate_terminus_balance - 1000)
118151
self.assertEqual(
119152
final_controller_balance, intermediate_controller_balance + 1000
@@ -152,6 +185,8 @@ def setUpClass(cls) -> None:
152185
cls.diamond_terminus = diamond_terminus
153186
cls.diamond_moonstream = diamond_moonstream
154187

188+
cls.diamond_terminus.set_controller(accounts[1].address, {"from": accounts[0]})
189+
155190
def setUp(self) -> None:
156191
self.diamond_terminus.create_simple_pool(10, {"from": accounts[1]})
157192

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# Update the Terminus contract
2+
3+
The Terminus contract is deployed as an EIP2535 Diamond proxy contract with a Terminus facet attached to it.
4+
5+
This checklist describes how to update the `TerminusFacet` on the Terminus diamond contract.
6+
7+
## Deployed addresses
8+
9+
You will modify this section as you go through the checklist
10+
11+
### `TerminusFacet` address
12+
13+
```
14+
export TERMINUS_FACET_ADDRESS="0x6396813307826Fb315e65CA7138A41CFa09a8AB3"
15+
```
16+
17+
## Environment variables
18+
19+
- [x] `export DAO_NETWORK=<desired brownie network>`
20+
- [x] `export DAO_OWNER=<path to keystore file for owner account>`
21+
- [x] `export DAO_OWNER_ADDRESS=$(jq -r .address $DAO_OWNER)`
22+
- [x] `export MAX_FEE_PER_GAS="200 gwei"`
23+
- [x] `export MAX_PRIORITY_FEE_PER_GAS="80 gwei"`
24+
- [x] `export CONFIRMATIONS=1`
25+
- [x] `export TERMINUS_DIAMOND=0x99A558BDBdE247C2B2716f0D4cFb0E246DFB697D`
26+
27+
## Detach existing `TerminusFacet`
28+
29+
- [x] Remove `TerminusFacet` from diamond. (This may require checkout of earlier commit and `brownie compile`.)
30+
31+
```bash
32+
dao core facet-cut \
33+
--address $TERMINUS_DIAMOND \
34+
--network $DAO_NETWORK \
35+
--sender $DAO_OWNER \
36+
--max-fee-per-gas "$MAX_FEE_PER_GAS" \
37+
--max-priority-fee-per-gas "$MAX_PRIORITY_FEE_PER_GAS" \
38+
--confirmations $CONFIRMATIONS \
39+
--facet-name TerminusFacet \
40+
--action remove
41+
```
42+
43+
44+
## Deploy `TerminusFacet`
45+
46+
- [x] Check out relevant commit and `brownie compile`.
47+
48+
- [x] Deploy `TerminusFacet` contract
49+
50+
```bash
51+
dao terminus deploy \
52+
--network $DAO_NETWORK \
53+
--sender $DAO_OWNER \
54+
--max-fee-per-gas "$MAX_FEE_PER_GAS" \
55+
--max-priority-fee-per-gas "$MAX_PRIORITY_FEE_PER_GAS" \
56+
--confirmations $CONFIRMATIONS
57+
```
58+
59+
- [x] Export address of deployed contract as `export TERMINUS_FACET_ADDRESS=0x6396813307826Fb315e65CA7138A41CFa09a8AB3`
60+
61+
- [x] Store address of deployed contract under `Deployed addresses / TerminusFacet address` above
62+
63+
- [x] Attach `TerminusFacet` to diamond:
64+
65+
```bash
66+
dao core facet-cut \
67+
--address $TERMINUS_DIAMOND \
68+
--network $DAO_NETWORK \
69+
--sender $DAO_OWNER \
70+
--max-fee-per-gas "$MAX_FEE_PER_GAS" \
71+
--max-priority-fee-per-gas "$MAX_PRIORITY_FEE_PER_GAS" \
72+
--confirmations $CONFIRMATIONS \
73+
--facet-name TerminusFacet \
74+
--facet-address $TERMINUS_FACET_ADDRESS \
75+
--action add
76+
```
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Update the Terminus contract
2+
3+
The Terminus contract is deployed as an EIP2535 Diamond proxy contract with a Terminus facet attached to it.
4+
5+
This checklist describes how to update the `TerminusFacet` on the Terminus diamond contract.
6+
7+
## Deployed addresses
8+
9+
You will modify this section as you go through the checklist
10+
11+
### `TerminusFacet` address
12+
13+
```
14+
export TERMINUS_FACET_ADDRESS="0x6396813307826Fb315e65CA7138A41CFa09a8AB3"
15+
```
16+
17+
## Environment variables
18+
19+
- [x] `export DAO_NETWORK=<desired brownie network>`
20+
- [x] `export DAO_OWNER=<path to keystore file for owner account>`
21+
- [x] `export DAO_OWNER_ADDRESS=$(jq -r .address $DAO_OWNER)`
22+
- [x] `export MAX_FEE_PER_GAS="200 gwei"`
23+
- [x] `export MAX_PRIORITY_FEE_PER_GAS="80 gwei"`
24+
- [x] `export CONFIRMATIONS=1`
25+
- [x] `export TERMINUS_DIAMOND=0x062BEc5e84289Da2CD6147E0e4DA402B33B8f796`
26+
27+
28+
## Detach existing `TerminusFacet`
29+
30+
- [x] Remove `TerminusFacet` from diamond. (This may require checkout of earlier commit and `brownie compile`.)
31+
32+
```bash
33+
dao core facet-cut \
34+
--address $TERMINUS_DIAMOND \
35+
--network $DAO_NETWORK \
36+
--sender $DAO_OWNER \
37+
--max-fee-per-gas "$MAX_FEE_PER_GAS" \
38+
--max-priority-fee-per-gas "$MAX_PRIORITY_FEE_PER_GAS" \
39+
--confirmations $CONFIRMATIONS \
40+
--facet-name TerminusFacet \
41+
--action remove
42+
```
43+
44+
45+
## Deploy `TerminusFacet`
46+
47+
- [x] Check out correct branch and `brownie compile`.
48+
49+
- [x] Export address of deployed contract as `export TERMINUS_FACET_ADDRESS=0x6396813307826Fb315e65CA7138A41CFa09a8AB3`
50+
51+
- [x] Store address of deployed contract under `Deployed addresses / TerminusFacet address` above
52+
53+
- [ ] Attach `TerminusFacet` to diamond:
54+
55+
```bash
56+
dao core facet-cut \
57+
--address $TERMINUS_DIAMOND \
58+
--network $DAO_NETWORK \
59+
--sender $DAO_OWNER \
60+
--max-fee-per-gas "$MAX_FEE_PER_GAS" \
61+
--max-priority-fee-per-gas "$MAX_PRIORITY_FEE_PER_GAS" \
62+
--confirmations $CONFIRMATIONS \
63+
--facet-name TerminusFacet \
64+
--facet-address $TERMINUS_FACET_ADDRESS \
65+
--action add
66+
```

0 commit comments

Comments
 (0)