Skip to content

Latest commit

 

History

History
431 lines (369 loc) · 13 KB

Proxy.md

File metadata and controls

431 lines (369 loc) · 13 KB

Base Proxy contract. (Proxy.sol)

View Source: contracts/proxy/Proxy.sol

↘ Derived Contracts: TeamVesting, UpgradableProxy

Proxy contract

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

Contract Members

Constants & Variables

bytes32 private constant KEY_IMPLEMENTATION;
bytes32 private constant KEY_OWNER;

Events

event OwnershipTransferred(address indexed _oldOwner, address indexed _newOwner);
event ImplementationChanged(address indexed _oldImplementation, address indexed _newImplementation);

Modifiers

onlyProxyOwner

Throw error if called not by an owner.

modifier onlyProxyOwner() internal

Functions


constructor

Set sender as an owner.

function () public nonpayable
Source Code
constructor() public {
        _setProxyOwner(msg.sender);
    }

_setImplementation

Set address of the implementation.

function _setImplementation(address _implementation) internal nonpayable

Arguments

Name Type Description
_implementation address Address of the implementation.
Source Code
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)
        }
    }

getImplementation

Return address of the implementation.

function getImplementation() public view
returns(_implementation address)
Source Code
function getImplementation() public view returns (address _implementation) {
        bytes32 key = KEY_IMPLEMENTATION;
        assembly {
            _implementation := sload(key)
        }
    }

_setProxyOwner

Set address of the owner.

function _setProxyOwner(address _owner) internal nonpayable

Arguments

Name Type Description
_owner address Address of the owner.
Source Code
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)
        }
    }

getProxyOwner

Return address of the owner.

function getProxyOwner() public view
returns(_owner address)
Source Code
function getProxyOwner() public view returns (address _owner) {
        bytes32 key = KEY_OWNER;
        assembly {
            _owner := sload(key)
        }
    }

constructor

Fallback function performs a delegate call to the actual implementation address is pointing this proxy. Returns whatever the implementation call returns.

function () external payable
Source Code
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)
                }
        }
    }

Contracts