Hi @arosboro,
If I have understood what you are doing correctly:
- The secondary contract needs the address of the primary contract.
- The primary contract needs the address of the secondary contract.
Using upgradeable contracts one way to do this would be:
- The primary contract needs to be created and initialized with the owner
- The secondary contract needs to be created and initialized with the address of the primary contract
- The primary contract needs to have the address of the secondary contract set, and this needs appropriate access control, in this case
onlyOwner
.
Please note, initializers
should only be run once, so we need to add a check to ensure this using the modifier initializer
. See the Initializers documentation for details.
As an aside, I used OpenZeppelin Contracts Ethereum Package 2.2.3 as there was an issue with version 2.3.
openzeppelin link @openzeppelin/contracts-ethereum-package@2.2.3
I have created a small example doing this process:
Alpha.sol
pragma solidity ^0.5.0;
// Import base Initializable contract
import "@openzeppelin/upgrades/contracts/Initializable.sol";
// Import interface and library from OpenZeppelin contracts
import "@openzeppelin/contracts-ethereum-package/contracts/ownership/Ownable.sol";
import "./Beta.sol";
contract Alpha is Initializable, Ownable {
Beta private _beta;
function initialize(address sender) public initializer {
Ownable.initialize(sender);
}
function setBeta(Beta beta) public onlyOwner {
_beta = beta;
}
function doStuff() public {
_beta.doStuff();
}
}
Beta.sol
pragma solidity ^0.5.0;
// Import base Initializable contract
import "@openzeppelin/upgrades/contracts/Initializable.sol";
// Import interface and library from OpenZeppelin contracts
import "@openzeppelin/contracts-ethereum-package/contracts/ownership/Secondary.sol";
contract Beta is Initializable, Secondary {
function initialize(address sender) public initializer {
Secondary.initialize(sender);
}
function doStuff() public onlyPrimary {
}
}
Get Account
Choose account to use for owner, for simplicity, I used the first account.
$ oz accounts
? Pick a network development
Accounts for dev-1573097128410:
Default: 0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1
All:
- 0: 0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1
...
Create Alpha
Create the Alpha contract on ganache-cli
and call initialize
to set the address of the owner.
$ oz create
✓ Compiled contracts with solc 0.5.12 (commit.7709ece9)
? Pick a contract to instantiate Alpha
? Pick a network development
✓ Deploying @openzeppelin/contracts-ethereum-package dependency to network dev-1573097445291
✓ Contract Alpha deployed
✓ Contract Beta deployed
All contracts have been deployed
? Do you want to call a function on the instance after creating it? Yes
? Select which function * initialize(sender: address)
? sender (address): 0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1
✓ Setting everything up to create contract instances
✓ Instance created at 0x26b4AFb60d6C903165150C6F0AA14F8016bE4aec
0x26b4AFb60d6C903165150C6F0AA14F8016bE4aec
Create Beta
Create the Beta contract on ganache-cli
and call initialize
to set the address of the Alpha contract.
$ oz create
Nothing to compile, all contracts are up to date.
? Pick a contract to instantiate Beta
? Pick a network development
All contracts are up to date
? Do you want to call a function on the instance after creating it? Yes
? Select which function * initialize(sender: address)
? sender (address): 0x26b4AFb60d6C903165150C6F0AA14F8016bE4aec
✓ Instance created at 0x630589690929E9cdEFDeF0734717a9eF3Ec7Fcfe
0x630589690929E9cdEFDeF0734717a9eF3Ec7Fcfe
Set Beta address
On the Alpha contract, set the Beta address, so that the Alpha contract can call the Beta.
$ oz send-tx
? Pick a network development
? Pick an instance Alpha at 0x26b4AFb60d6C903165150C6F0AA14F8016bE4aec
? Select which function setBeta(beta: address)
? beta (address): 0x630589690929E9cdEFDeF0734717a9eF3Ec7Fcfe
✓ Transaction successful. Transaction hash: 0x90e0ae6bca057719273ce3d98d0ff5f5a83293fa6de4f698df5e916f48cfdc54
Call Beta not from Primary
Attempt to call an onlyPrimary
function on the Beta contract not from the Primary contract. This will fail.
$ oz send-tx
? Pick a network development
? Pick an instance Beta at 0x630589690929E9cdEFDeF0734717a9eF3Ec7Fcfe
? Select which function doStuff()
✖ Calling: 'doStuff' with no arguments
Error while trying to send transaction to 0x630589690929E9cdEFDeF0734717a9eF3Ec7Fcfe. Error: Returned error: VM Exception while processing transaction: revert Secondary: caller is not the primary account
Call Beta from Primary
Call an onlyPrimary
function on the Beta contract from the Primary contract. This will succeed.
$ oz send-tx
? Pick a network development
? Pick an instance Alpha at 0x26b4AFb60d6C903165150C6F0AA14F8016bE4aec
? Select which function doStuff()
✓ Transaction successful. Transaction hash: 0x3dab346850fd0590fdd7430bde5877bb3bfaf52dd2e9058abca8baea7eb72da3
Feel free to ask all the questions that you need.