Contracts are also accounts! Pretty useful pattern:
First, we create the actual Thing we like.
pragma solidity ^0.8.10;
contract Thing {
address public owner;
uint argument;
modifier restricted() {
require(msg.sender == owner);
_;
}
constructor (uint _argument) {
owner = msg.sender;
argument = _argument;
}
function doThing() public restricted {}
}
Then we make a thing to make, and thus own, more Things.
// test/ThingMaker.sol (truffle only runs
// files beginning with Test but you could
// put it somewhere else too)
pragma solidity ^0.8.10;
import "../contracts/Thing.sol";
contract ThingMaker {
function makeThing(uint argument) public returns (Thing) {
Thing thing = new Thing(argument);
return thing;
}
}
Finally, we have a test for the Things which can use any number of Things they do, or do not, own (you can just make a Thing[] preOwnedThingArray
if you like). All tests pass! Be sure to use actual error messages though.
// test/TestThing.sol
pragma solidity ^0.8.10;
import "../contracts/Thing.sol";
import "./ThingMaker.sol";
contract TestThing {
Thing preOwnedThing;
function beforeEach() public {
uint arg = 123;
ThingMaker maker = new ThingMaker();
preOwnedThing = maker.makeThing(arg);
}
function testOwnerCanDoThing() public {
uint arg = 123;
Thing thing = new Thing(arg);
thing.doThing();
}
function testNonOwnerCannotDoThing() public {
try preOwnedThing.doThing() {
assert(1==2);
} catch {}
}
}
Now this covers the 0 and 1 unprivileged account case - if you instead want to interact with one contract with a bunch of accounts, you can flip the script and just create a ThingInteractor.sol
, but I'm afraid you're probably going to have to make separate function in that contract (maybe there's some magic to avoid that, will have to try to remember to get back to you if I can think of some) to interact with whatever you like and then just create new ThingInteractors on demand.