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 Ownable
anstelle 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 set
Funktion aufrufen kann.
Das Problem liegt also im Wesentlichen bei:
await myTestContract.claimOwnership({from: multiSigContract.address});
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:
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);
claimOwnership
von myTestContract
?????accounts[0]
(und nicht von MultiSig) ist.multisigInstance
ist der ausstehende Eigentümer, also darf er die Funktion aufrufen claimOwnership
(tatsächlich ist er der einzige, der dies tun darf). Genial, danke!!!
Nulik
address
kann einen beliebigen Wert von 20 Bytes enthalten, den Sie möchten.Henk
gute Stimmung
myTestContract.claimOwnership({from: myMultiSigContract.address})
?gute Stimmung
Claimable
Vertragstest (ebenfalls im GitHub-Repository von OpenZeppelin) soll ich das tun. Bin ich hier falsch?