Wie kann ich das Eigentum auf einen anderen Vertrag übertragen?

Ich habe einen Vertrag, der vom Vertrag von OpenZeppelin erbt Claimable(siehe hier ):

pragma solidity ^0.4.24;
import "./Claimable.sol";

contract MyTestContract is Claimable {
    uint256 public id;
    function set(uint256 _id) external onlyOwner {id = _id;}
}

Der Zweck besteht natürlich darin, die Aufrufberechtigung für die Funktion einzuschränken set.

Diese Funktion kann nur von dem Account aus aufgerufen werden, den ich zum Deployment des Vertrages verwende.

Nach der Bereitstellung möchte ich die Inhaberschaft von diesem Konto auf einen anderen Vertrag übertragen.

Der Grund dafür ist nicht Teil meiner Frage, aber für alles, was darauf ankommt, muss ich eine Mehrfachsignatur für die Funktion erzwingen und die Ausführung erst zulassen, nachdem X von Y zugelassenen Benutzern eine Anfrage gestellt haben . Daher muss ich das Eigentum an dem Vertrag von meinem Konto auf einen MultiSig-Vertrag von Gnosis (siehe hier ) übertragen , den ich selbst einsetze.

Das Problem, mit dem ich ein Problem habe und mit dem ich mich nicht wirklich beschäftigen kann, ist, wie man das Eigentum an etwas überträgt, das "nicht gerade ein Konto" ist.

Wenn ich das Eigentum von meinem Konto auf ein anderes Konto im Netzwerk übertrage, funktioniert es einwandfrei.

Zum Beispiel richte ich ein Ganache-Netzwerk mit 8 Konten ein und führe dann diesen Truffle-Test durch:

contract('MyTestContract', (accounts) => {
    it('Transfer Ownership', async () => {
        let   myTestContract = await artifacts.require('MyTestContract').new();
        let   owner = await myTestContract.owner();
        assert(owner === accounts[0]);
        await myTestContract.transferOwnership(accounts[1]);
        await myTestContract.claimOwnership({from: accounts[1]});
        let   newOwner = await myTestContract.owner();
        assert(newOwner === accounts[1]);
    });
});

Aber wenn ich das Eigentum von meinem Konto auf die Adresse eines Vertrags übertrage, den ich im Netzwerk einsetze, meldet Truffle:

Fehler: Absenderkonto nicht erkannt

Jetzt macht der Fehler an sich schon Sinn, da es im Netzwerk kein solches Konto gibt.

Also meine Frage hier - ist es überhaupt möglich zu tun, was ich versuche zu erreichen?

Ich habe das Gefühl, dass ich den Unterschied zwischen Konten und Verträgen grundlegend missverstehe, und ich wäre sehr dankbar, wenn mir jemand das erklären könnte.

Vielen Dank!

AKTUALISIEREN:

Zur Verdeutlichung übertrage ich das Eigentum an dem MultiSig-Vertrag folgendermaßen:

await myTestContract.transferOwnership(multiSigContract.address);
await myTestContract.claimOwnership({from: multiSigContract.address});

Und übrigens, wenn ich Ownableanstelle von verwende Claimable, dh:

On-Chain-Code:

contract MyTestContract is Ownable {...}

Off-Chain-Code:

await myTestContract.transferOwnership(multiSigContract.address);

Die Eigentumsübertragung wird erfolgreich abgeschlossen, und der MultiSig-Vertrag ist der einzige, der die setFunktion aufrufen kann.

Das Problem liegt also im Wesentlichen bei:

await myTestContract.claimOwnership({from: multiSigContract.address});
Ethereum ist eine virtuelle Maschine, mit der Sie alles tun können, was Sie wollen. Was die Regeln für den Eigentümerwechsel betrifft, so sind es wirklich die Regeln Ihres Vertrags, die Sie kontrollieren können. Und das addresskann einen beliebigen Wert von 20 Bytes enthalten, den Sie möchten.
Versuchen Sie zufällig, die Transaktion von der Vertragsadresse zu senden, an die Sie versuchen, das Eigentum zu übertragen?
@Nulik: Danke für die Klarstellung. Es gibt also nichts, was ich hier wirklich vermisse. Bleibt nur noch die Frage, wie kann ich den Anruf erfolgreich abschließen myTestContract.claimOwnership({from: myMultiSigContract.address})?
@Henk: Ja genau. Siehe meine Antwort an Nulik oben. Laut ClaimableVertragstest (ebenfalls im GitHub-Repository von OpenZeppelin) soll ich das tun. Bin ich hier falsch?

Antworten (1)

await myTestContract.claimOwnership({from: multiSigContract.address});

da liegt das problem. Sie weisen Truffle an, eine Transaktion zu senden, die von einer Adresse signiert ist, die es nicht kontrolliert. Also der Fehler .

Sie können sich den Gnosis MultiSigContract als ein "Relais" vorstellen, an das Sie Transaktionen senden, für deren Durchführung dann Genehmigungen erforderlich sind (falls erforderlich, Bestätigungen höher als 1 ).

Damit der „Vertrag“ die „Besitzerschaft“ Ihres Hauptvertrags beansprucht, müssen Sie eine Transaktion erstellen, die genau das tut:

Fluss:

  1. Hauptvertrag bereitstellen
  2. Multi-Sig bereitstellen (2 Bestätigungen festlegen und Konto 1 und 2 als Eigentümer hinzufügen)
  3. RufübertragungBesitz von "myTestcontract"
  4. Erstellen und senden Sie eine Transaktion, die die Methode "claimOwnership" für den Hauptvertrag aufruft, an die Multisig
  5. Rufen Sie "confirmTransaction" für den Multi-Sig-Vertrag von Konto 1 und 2 auf.
  6. multi-sig sollte der neue Eigentümer sein.

Der schwierige Teil ist Schritt 4, der Sie in das Innenleben des Aufbaus von Solidity-Abi-Calls führt. Sie können dies manuell tun ( bytes4(sha3("contract_method(bytes,bool,uint256[])") ) oder es den Truffle-Helfer instance.contract.metod.getData für Sie erledigen lassen.

Schauen Sie sich https://github.com/gnosis/MultiSigWallet/blob/master/test/javascript/testExternalCalls.js an

Ihr endgültiger Code sollte etwa so aussehen: ( ungetestet )

    // 1 - deploy main contract

    let   myTestContract = await artifacts.require('MyTestContract').new();
    let   owner = await myTestContract.owner();
    assert(owner === accounts[0]);

    // 2 - deploy multi-sig ( set 2 confirmations , and add account 1 and 2 as owner )
    const deployMultisig = (owners, confirmations) => {
        return MultiSigWallet.new(owners, confirmations)
    }

    let requiredConfirmations = 2
    let multisigInstance = await deployMultisig([accounts[1], accounts[2]], requiredConfirmations)

    // 3 - call transferOwnership from "myTestcontract"
    await myTestContract.transferOwnership(multisigInstance.address);

    // 4 - create and submit a transaction that calls the "claimOwnership" method on main contract to the multisig

    // Encode claimOwnership call for the multisig
    const claimOwnershipEncoded = myTestContract.contract.claimOwnership.getData()

    await multisigInstance.submitTransaction(
        myTestContract.address, // address to call with this transaction
        0,                      // value
        claimOwnershipEncoded,  // encoded data
        {from: accounts[1]}     // first owner
    );

    // 5 - call "confirmTransaction" on multi-sig contract from account 2nd account

    const transactionId = 1 // transactionCount starts at 0, so once we add one, we're at 1 
    await multisigInstance.confirmTransaction(transactionId, {from: accounts[2]})

    // 6 - multi-sig should be the new owner.

    let   newOwner = await myTestContract.owner();
    assert(newOwner === multisigInstance.address);
Sie verwenden also tatsächlich den MultiSig-Vertrag, um die Funktion claimOwnershipvon myTestContract?????
Ich bezweifle, dass MultiSig diese Transaktion abschließen kann, da mein Vertrag zu diesem Zeitpunkt immer noch Eigentum von accounts[0](und nicht von MultiSig) ist.
Entschuldigung, ich nehme es zurück, Sie haben vollkommen Recht. Der multisigInstanceist der ausstehende Eigentümer, also darf er die Funktion aufrufen claimOwnership(tatsächlich ist er der einzige, der dies tun darf). Genial, danke!!!
Sehr gerne :) Es dauert eine Weile, bis Sie sich darüber im Klaren sind, wie die Dinge erledigt werden müssen, aber sobald Sie dort sind, sind Ihnen keine Grenzen gesetzt