2

I'm playing around w/ Gnosis' MultiSigWallet and noticed in their replaceOwner function it has a modifier that requires msg.sender to be the MultiSigWallet contract itself:

modifier onlyWallet() {
    require(msg.sender == address(this));
    _;
}

In Truffle console, how would I go about testing this and calling the replaceOwner function from the MultiSigWallet's address? I.e., if I try something like this:

wallet.replaceOwner('owner_address','newOwner_address', {from: 'multisigwallet_address'})

I'll get an Error: sender account not recognized

Is there a way within Truffle's console to make calls from contract addresses or is it only possible to make calls from the user addresses?

This post is related and I understand how this works, but I'm more curious to see if we can do this easily w/in Truffle for expedient testing purposes.

2

Here you go (got plenty more coverage for this contract if you're interested):

contract("MultiSigWallet", function(accounts) {
    let hMultiSigWallet;

    let utils = require("./utils");

    let NUM_OF_OWNERS    = 6;
    let NUM_OF_REQ_CONFS = 5;

    let owners   = accounts.slice(1, 1 + NUM_OF_OWNERS);
    let newOwner = accounts[1 + NUM_OF_OWNERS];

    beforeEach(async function() {
        hMultiSigWallet = await artifacts.require("MultiSigWallet").new(owners, NUM_OF_REQ_CONFS);
    });

    describe("functional assertion:", function() {
        it("function replaceOwner should abort with an error if called with a non-existing current owner", async function() {
            await execute(hMultiSigWallet.contract.replaceOwner, [newOwner, newOwner], "ExecutionFailure");
        });
        it("function replaceOwner should abort with an error if called with an already-existing new owner", async function() {
            await execute(hMultiSigWallet.contract.replaceOwner, [owners[0], owners[0]], "ExecutionFailure");
        });
        it("function replaceOwner should complete successfully if called with legal input arguments", async function() {
            await execute(hMultiSigWallet.contract.replaceOwner, [owners[0], newOwner], "Execution");
        });
    });

    async function execute(func, args, state) {
        let submitReceipt = await hMultiSigWallet.submitTransaction(hMultiSigWallet.address, 0, func.getData(...args), {from: owners[0]});
        let transactionId = utils.getParamFromTxEvent(submitReceipt, "transactionId", null, "Submission");
        for (let i = 1; i < NUM_OF_REQ_CONFS - 1; i++) {
            let confirmReceipt   = await hMultiSigWallet.confirmTransaction(transactionId, {from: owners[i]});
            let newTransactionId = utils.getParamFromTxEvent(confirmReceipt, "transactionId", null, "Confirmation");
            assert(newTransactionId.equals(transactionId), `expected = ${transactionId}, actual = ${newTransactionId}`);
        }
        let confirmReceipt   = await hMultiSigWallet.confirmTransaction(transactionId, {from: owners[NUM_OF_REQ_CONFS - 1]});
        let newTransactionId = utils.getParamFromTxEvent(confirmReceipt, "transactionId", null, state);
        assert(newTransactionId.equals(transactionId), `expected = ${transactionId}, actual = ${newTransactionId}`);
    }
});
  • Just make sure that you start Ganache with a sufficient number of accounts (at least NUM_OF_OWNERS + 2). – goodvibration Dec 13 '18 at 16:19
  • Thanks! So, it looks like the fastest way to test is w/ unit tests? There's no easy / quick way to do it w/in truffle console? – dougiebuckets Dec 13 '18 at 18:40
  • @dougiebuckets: I don't use truffle console so it's hard for me to answer this question, but you can get it running via truffle test. – goodvibration Dec 13 '18 at 19:09
  • @dougiebuckets The trick is that, as you pointed out, the contract itself has to call replaceOwner. The only way to get it to do that is the same way you make the contract do anything; call submitTransaction and then confirmTransaction a sufficient number of times from the various owner accounts. So there's no quick shortcut to this... it's the nature of the contract you're using. – smarx Dec 14 '18 at 0:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.