Vertrag, der keine aktualisierten Proxy-Verträge verwendet

Es gibt 2 Verträge Aund B, AImporte B, wo Bsich eine Bibliothek befindet, die aktualisiert werden kann. Um dies zu erreichen, habe ich versucht, ihn Bdurch einen Proxy-Vertrag und einen Delegierten-Vertrag zu ersetzen.

Wir haben jetzt Verträge Foo, die einen Proxy-Vertrag importieren Barund auf einen Delegiertenvertrag verweisen ZeroDelegate.

Foo.sol

pragma solidity ^0.4.18;

import './Bar.sol';

contract Foo {
    uint storageData;
    Bar bar;
    address barContractAddress;

    constructor(address _barContractAddress) public {
        barContractAddress = _barContractAddress;
    }

    function set(uint x) public {
        storageData = x;
    }

    function get() view public returns (uint) {
        return storageData;
    }

    function baz() public returns (uint) {
        bar = Bar(barContractAddress);
        storageData = bar.baz(storageData);
    }

}

Stangensol

pragma solidity ^0.4.18;

import './Proxy.sol';

contract Bar is Proxy {
    function baz(uint x) public returns (uint) {
        return  x * x;
    }
}

ZeroDelegate.sol

pragma solidity ^0.4.18;

contract ZeroDelegate {
    function baz(uint x) public returns (uint) {
        return x * 0;
    }
}

Proxy.sol

pragma solidity ^0.4.18;

import "zeppelin-solidity/contracts/ownership/Ownable.sol";

contract Proxy is Ownable {

    event Upgraded(address indexed implementation);

    address internal _implementation;

    function implementation() public view returns (address) {
        return _implementation;
    }

    function upgradeTo(address impl) public onlyOwner {
        require(_implementation != impl);
        _implementation = impl;
        emit Upgraded(impl);
    }

    function () payable public {
        address _impl = implementation();
        require(_impl != address(0));
        bytes memory data = msg.data;

        assembly {
            let result := delegatecall(gas, _impl, add(data, 0x20), mload(data), 0, 0)
            let size := returndatasize
            let ptr := mload(0x40)
            returndatacopy(ptr, 0, size)
            switch result
            case 0 { revert(ptr, size) }
            default { return(ptr, size) }
        }
    }
}

Jetzt stellen wir zuerst die Verträge Foo, Bar, bereit ZeroDelegate.

bar = await Bar.new()
foo = await Foo.new(bar.address)
zeroDelegate = await ZeroDelegate.new()

Und foo.baz()quadriert die Zahl 2 zu 4.

x = await foo.baz()
console.log(x.toNumber())  // 4

Als nächstes stufen wir den BarKontrakt auf hoch, quadrieren ZeroDelegateaber immer noch die Zahl 4 auf 16foo.baz()

await bar.upgradeTo(zeroDelegate.address)
bar = _.extend(bar, ZeroDelegate.at(bar.address))
await foo.baz()
x = await foo.get()
console.log(x.toNumber())  // 16, but expects 0

Wenn wir den Vertrag jedoch erneut bereitstellen Foo, verwendet er die aktualisierte Bar. Warum ist das so und wie können wir Foodie aktualisierten BarFunktionen nutzen, ohne sie erneut bereitstellen zu müssen Foo, was den Zweck der Verwendung eines aktualisierbaren Vertrags irgendwie zunichte macht?

foo = await Foo.new(bar.address)
await foo.baz()
x = await foo.get()
console.log(x.toNumber())  // 0

Antworten (1)

Sie müssen Ihre Fallback-Funktion mit dem Namen baz() erstellen und dann Bar.sol genauso behandeln wie ZeroDelegate (als nicht geerbter externer Vertrag – vielleicht tatsächlich eine Bibliothek). Der delegierte Aufruf wird an diesen externen Vertrag gesendet (auf den _imp gerade zeigt) und die Logik innerhalb dieses Vertrags verwenden. Wenn Sie _imp auf die Adresse von Bar oder ZeroDelegate aktualisieren, um sein Verhalten zu ändern.

Hier ist ein funktionierendes Beispiel mit einer aktualisierbaren TokenURI-Funktion:
https://github.com/clovers-network/clovers-contracts/blob/master/contracts/Clovers.sol
verweist auf:
https://github.com/clovers-network/ clovers-contracts/blob/master/contracts/CloversMetadata.sol