-
Notifications
You must be signed in to change notification settings - Fork 49
/
Copy pathProxy.sol
128 lines (115 loc) · 4.16 KB
/
Proxy.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
pragma solidity ^0.5.17;
/**
* @title Base Proxy contract.
* @notice The proxy performs delegated calls to the contract implementation
* it is pointing to. This way upgradable contracts are possible on blockchain.
*
* Delegating proxy contracts are widely used for both upgradeability and gas
* savings. These proxies rely on a logic contract (also known as implementation
* contract or master copy) that is called using delegatecall. This allows
* proxies to keep a persistent state (storage and balance) while the code is
* delegated to the logic contract.
*
* Proxy contract is meant to be inherited and its internal functions
* _setImplementation and _setProxyOwner to be called when upgrades become
* neccessary.
*
* The loan token (iToken) contract as well as the protocol contract act as
* proxies, delegating all calls to underlying contracts. Therefore, if you
* want to interact with them using web3, you need to use the ABIs from the
* contracts containing the actual logic or the interface contract.
* ABI for LoanToken contracts: LoanTokenLogicStandard
* ABI for Protocol contract: ISovryn
*
* @dev UpgradableProxy is the contract that inherits Proxy and wraps these
* functions.
* */
contract Proxy {
bytes32 private constant KEY_IMPLEMENTATION = keccak256("key.implementation");
bytes32 private constant KEY_OWNER = keccak256("key.proxy.owner");
event OwnershipTransferred(address indexed _oldOwner, address indexed _newOwner);
event ImplementationChanged(
address indexed _oldImplementation,
address indexed _newImplementation
);
/**
* @notice Set sender as an owner.
* */
constructor() public {
_setProxyOwner(msg.sender);
}
/**
* @notice Throw error if called not by an owner.
* */
modifier onlyProxyOwner() {
require(msg.sender == getProxyOwner(), "Proxy:: access denied");
_;
}
/**
* @notice Set address of the implementation.
* @param _implementation Address of the implementation.
* */
function _setImplementation(address _implementation) internal {
require(_implementation != address(0), "Proxy::setImplementation: invalid address");
emit ImplementationChanged(getImplementation(), _implementation);
bytes32 key = KEY_IMPLEMENTATION;
assembly {
sstore(key, _implementation)
}
}
/**
* @notice Return address of the implementation.
* @return Address of the implementation.
* */
function getImplementation() public view returns (address _implementation) {
bytes32 key = KEY_IMPLEMENTATION;
assembly {
_implementation := sload(key)
}
}
/**
* @notice Set address of the owner.
* @param _owner Address of the owner.
* */
function _setProxyOwner(address _owner) internal {
require(_owner != address(0), "Proxy::setProxyOwner: invalid address");
emit OwnershipTransferred(getProxyOwner(), _owner);
bytes32 key = KEY_OWNER;
assembly {
sstore(key, _owner)
}
}
/**
* @notice Return address of the owner.
* @return Address of the owner.
* */
function getProxyOwner() public view returns (address _owner) {
bytes32 key = KEY_OWNER;
assembly {
_owner := sload(key)
}
}
/**
* @notice Fallback function performs a delegate call
* to the actual implementation address is pointing this proxy.
* Returns whatever the implementation call returns.
* */
function() external payable {
address implementation = getImplementation();
require(implementation != address(0), "Proxy::(): implementation not found");
assembly {
let pointer := mload(0x40)
calldatacopy(pointer, 0, calldatasize)
let result := delegatecall(gas, implementation, pointer, calldatasize, 0, 0)
let size := returndatasize
returndatacopy(pointer, 0, size)
switch result
case 0 {
revert(pointer, size)
}
default {
return(pointer, size)
}
}
}
}