This repository has been archived by the owner on Apr 21, 2024. It is now read-only.
forked from gemini/dollar
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathERC20ImplUpgradeable.sol
107 lines (88 loc) · 3.59 KB
/
ERC20ImplUpgradeable.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
pragma solidity ^0.4.21;
import "./CustodianUpgradeable.sol";
import "./ERC20Impl.sol";
/** @title A contract to inherit upgradeable token implementations.
*
* @notice A contract that provides re-usable code for upgradeable
* token implementations. It itself inherits from `CustodianUpgradable`
* as the upgrade process is controlled by the custodian.
*
* @dev This contract is intended to be inherited by any contract
* requiring a reference to the active token implementation, either
* to delegate calls to it, or authorize calls from it. This contract
* provides the mechanism for that implementation to be be replaced,
* which constitutes an implementation upgrade.
*
* @author Gemini Trust Company, LLC
*/
contract ERC20ImplUpgradeable is CustodianUpgradeable {
// TYPES
/// @dev The struct type for pending implementation changes.
struct ImplChangeRequest {
address proposedNew;
}
// MEMBERS
// @dev The reference to the active token implementation.
ERC20Impl public erc20Impl;
/// @dev The map of lock ids to pending implementation changes.
mapping (bytes32 => ImplChangeRequest) public implChangeReqs;
// CONSTRUCTOR
function ERC20ImplUpgradeable(address _custodian) CustodianUpgradeable(_custodian) public {
erc20Impl = ERC20Impl(0x0);
}
// MODIFIERS
modifier onlyImpl {
require(msg.sender == address(erc20Impl));
_;
}
// PUBLIC FUNCTIONS
// (UPGRADE)
/** @notice Requests a change of the active implementation associated
* with this contract.
*
* @dev Returns a unique lock id associated with the request.
* Anyone can call this function, but confirming the request is authorized
* by the custodian.
*
* @param _proposedImpl The address of the new active implementation.
* @return lockId A unique identifier for this request.
*/
function requestImplChange(address _proposedImpl) public returns (bytes32 lockId) {
require(_proposedImpl != address(0));
lockId = generateLockId();
implChangeReqs[lockId] = ImplChangeRequest({
proposedNew: _proposedImpl
});
emit ImplChangeRequested(lockId, msg.sender, _proposedImpl);
}
/** @notice Confirms a pending change of the active implementation
* associated with this contract.
*
* @dev When called by the custodian with a lock id associated with a
* pending change, the `ERC20Impl erc20Impl` member will be updated
* with the requested address.
*
* @param _lockId The identifier of a pending change request.
*/
function confirmImplChange(bytes32 _lockId) public onlyCustodian {
erc20Impl = getImplChangeReq(_lockId);
delete implChangeReqs[_lockId];
emit ImplChangeConfirmed(_lockId, address(erc20Impl));
}
// PRIVATE FUNCTIONS
function getImplChangeReq(bytes32 _lockId) private view returns (ERC20Impl _proposedNew) {
ImplChangeRequest storage changeRequest = implChangeReqs[_lockId];
// reject ‘null’ results from the map lookup
// this can only be the case if an unknown `_lockId` is received
require(changeRequest.proposedNew != address(0));
return ERC20Impl(changeRequest.proposedNew);
}
/// @dev Emitted by successful `requestImplChange` calls.
event ImplChangeRequested(
bytes32 _lockId,
address _msgSender,
address _proposedImpl
);
/// @dev Emitted by successful `confirmImplChange` calls.
event ImplChangeConfirmed(bytes32 _lockId, address _newImpl);
}