-
Notifications
You must be signed in to change notification settings - Fork 974
/
Copy pathOwnerManager.sol
147 lines (136 loc) · 6.1 KB
/
OwnerManager.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.7.0 <0.9.0;
import {SelfAuthorized} from "../common/SelfAuthorized.sol";
import {IOwnerManager} from "../interfaces/IOwnerManager.sol";
/**
* @title OwnerManager - Manages Safe owners and a threshold to authorize transactions.
* @dev Uses a linked list to store the owners because the code generated by the solidity compiler
* is more efficient than using a dynamic array.
* @author Stefan George - @Georgi87
* @author Richard Meissner - @rmeissner
*/
abstract contract OwnerManager is SelfAuthorized, IOwnerManager {
// SENTINEL_OWNERS is used to traverse `owners`, so that:
// 1. `owners[SENTINEL_OWNERS]` contains the first owner
// 2. `owners[last_owner]` points back to SENTINEL_OWNERS
address internal constant SENTINEL_OWNERS = address(0x1);
mapping(address => address) internal owners;
uint256 internal ownerCount;
uint256 internal threshold;
/**
* @notice Sets the initial storage of the contract.
* @param _owners List of Safe owners.
* @param _threshold Number of required confirmations for a Safe transaction.
*/
function setupOwners(address[] memory _owners, uint256 _threshold) internal {
// Threshold can only be 0 at initialization.
// Check ensures that the setup function can only be called once.
if (threshold > 0) revertWithError("GS200");
// Validate that the threshold is smaller than the number of added owners.
if (_threshold > _owners.length) revertWithError("GS201");
// There has to be at least one Safe owner.
if (_threshold == 0) revertWithError("GS202");
// Initializing Safe owners.
address currentOwner = SENTINEL_OWNERS;
uint256 ownersLength = _owners.length;
for (uint256 i = 0; i < ownersLength; ++i) {
// Owner address cannot be null.
address owner = _owners[i];
if (owner == address(0) || owner == SENTINEL_OWNERS || owner == address(this) || currentOwner == owner)
revertWithError("GS203");
// No duplicate owners allowed.
if (owners[owner] != address(0)) revertWithError("GS204");
owners[currentOwner] = owner;
currentOwner = owner;
}
owners[currentOwner] = SENTINEL_OWNERS;
ownerCount = ownersLength;
threshold = _threshold;
}
/**
* @inheritdoc IOwnerManager
*/
function addOwnerWithThreshold(address owner, uint256 _threshold) public override authorized {
// Owner address cannot be null, the sentinel or the Safe itself.
if (owner == address(0) || owner == SENTINEL_OWNERS || owner == address(this)) revertWithError("GS203");
// No duplicate owners allowed.
if (owners[owner] != address(0)) revertWithError("GS204");
owners[owner] = owners[SENTINEL_OWNERS];
owners[SENTINEL_OWNERS] = owner;
++ownerCount;
emit AddedOwner(owner);
// Change threshold if threshold was changed.
if (threshold != _threshold) changeThreshold(_threshold);
}
/**
* @inheritdoc IOwnerManager
*/
function removeOwner(address prevOwner, address owner, uint256 _threshold) public override authorized {
// Only allow to remove an owner, if threshold can still be reached.
// Here we do pre-decrement as it is cheaper and allows us to check if the threshold is still reachable.
if (--ownerCount < _threshold) revertWithError("GS201");
// Validate owner address and check that it corresponds to owner index.
if (owner == address(0) || owner == SENTINEL_OWNERS) revertWithError("GS203");
if (owners[prevOwner] != owner) revertWithError("GS205");
owners[prevOwner] = owners[owner];
owners[owner] = address(0);
emit RemovedOwner(owner);
// Change threshold if threshold was changed.
if (threshold != _threshold) changeThreshold(_threshold);
}
/**
* @inheritdoc IOwnerManager
*/
function swapOwner(address prevOwner, address oldOwner, address newOwner) public override authorized {
// Owner address cannot be null, the sentinel or the Safe itself.
if (newOwner == address(0) || newOwner == SENTINEL_OWNERS || newOwner == address(this)) revertWithError("GS203");
// No duplicate owners allowed.
if (owners[newOwner] != address(0)) revertWithError("GS204");
// Validate oldOwner address and check that it corresponds to owner index.
if (oldOwner == address(0) || oldOwner == SENTINEL_OWNERS) revertWithError("GS203");
if (owners[prevOwner] != oldOwner) revertWithError("GS205");
owners[newOwner] = owners[oldOwner];
owners[prevOwner] = newOwner;
owners[oldOwner] = address(0);
emit RemovedOwner(oldOwner);
emit AddedOwner(newOwner);
}
/**
* @inheritdoc IOwnerManager
*/
function changeThreshold(uint256 _threshold) public override authorized {
// Validate that threshold is smaller than number of owners.
if (_threshold > ownerCount) revertWithError("GS201");
// There has to be at least one Safe owner.
if (_threshold == 0) revertWithError("GS202");
threshold = _threshold;
emit ChangedThreshold(_threshold);
}
/**
* @inheritdoc IOwnerManager
*/
function getThreshold() public view override returns (uint256) {
return threshold;
}
/**
* @inheritdoc IOwnerManager
*/
function isOwner(address owner) public view override returns (bool) {
return !(owner == SENTINEL_OWNERS || owners[owner] == address(0));
}
/**
* @inheritdoc IOwnerManager
*/
function getOwners() public view override returns (address[] memory) {
address[] memory array = new address[](ownerCount);
// populate return array
uint256 index = 0;
address currentOwner = owners[SENTINEL_OWNERS];
while (currentOwner != SENTINEL_OWNERS) {
array[index] = currentOwner;
currentOwner = owners[currentOwner];
++index;
}
return array;
}
}