如何將所有權轉移到另一個契約?
Claimable
我有一個繼承自OpenZeppelin的契約的契約(請參見此處):pragma solidity ^0.4.24; import "./Claimable.sol"; contract MyTestContract is Claimable { uint256 public id; function set(uint256 _id) external onlyOwner {id = _id;} }
目的當然是限制 function 的呼叫權限
set
。這個函式只能從我用來部署合約的賬戶中呼叫。
部署後,我想將此帳戶的所有權轉移到另一個契約。
這樣做的原因不是我的問題的一部分,但無論如何,我需要對函式強制執行多重簽名,並且只有在 Y 個允許的使用者中的 X 個送出請求後才允許執行它。因此,我需要將合約的所有權從我的賬戶轉移到 Gnosis 的 MultiSig 合約(參見此處),我自己部署了該合約。
我遇到問題並且無法真正解決的問題是如何將所有權轉移到“不完全是帳戶”的東西。
當我將所有權從我的帳戶轉移到網路上的另一個帳戶時,它工作正常。
例如,我建立了一個有 8 個帳戶的 Ganache 網路,然後執行這個 Truffle 測試:
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]); }); });
但是當我將所有權從我的賬戶轉移到我部署到網路中的合約地址時,Truffle 報告:
錯誤:無法辨識發件人帳戶
現在,錯誤本身是有道理的,因為網路上沒有這樣的帳戶。
所以我的問題是 - 是否有可能做我想要實現的目標?
我覺得我對賬戶和契約之間的區別有一些基本的誤解,如果有人能為我澄清一下,我將非常感激。
非常感謝你!
更新:
澄清一下,這是我將所有權轉移到 MultiSig 合約的方式:
await myTestContract.transferOwnership(multiSigContract.address); await myTestContract.claimOwnership({from: multiSigContract.address});
順便說一句,當我使用
Ownable
而不是Claimable
,即:鏈上程式碼:
contract MyTestContract is Ownable {...}
鏈下程式碼:
await myTestContract.transferOwnership(multiSigContract.address);
所有權轉移成功完成,MultiSig 合約是唯一可以呼叫該
set
函式的合約。所以問題本質上是:
await myTestContract.claimOwnership({from: multiSigContract.address});
await myTestContract.claimOwnership({from: multiSigContract.address});
是問題所在。您是在告訴 truffle 發送由它無法控制的地址簽名的交易。因此錯誤。
您可以將 Gnosis MultiSigContract 視為您發布交易的“中繼”,然後需要批准才能通過(如果需要,確認高於 1)。
為了使您的主契約的“契約”“聲明所有權”,您需要創建一個交易來執行此操作:
流動:
- 部署主合約
- 部署多重簽名(設置 2 個確認,並將賬戶 1 和 2 添加為所有者)
- 從“myTestcontract”呼叫 transferOwnership
- 創建並送出呼叫主合約上的“claimOwnership”方法的交易到多重簽名
- 從賬戶 1 和 2 呼叫多重簽名合約的“confirmTransaction”。
- multi-sig 應該是新的所有者。
困難的部分是第 4 步,它將帶您了解如何建構solidity abi 呼叫的內部工作原理。您可以選擇手動執行( bytes4(sha3(“contract_method(bytes,bool,uint256
$$ $$)”) ),或者讓 truffle instance.contract.metod.getData 助手為你做這件事。 看看https://github.com/gnosis/MultiSigWallet/blob/master/test/javascript/testExternalCalls.js
您的最終程式碼應類似於:(未經測試)
// 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);