Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kernel: allow initializing app proxies on overloaded newAppInstance #415

Merged
merged 2 commits into from
Sep 3, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions contracts/factory/APMRegistryFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -55,17 +55,20 @@ contract APMRegistryFactory is APMRegistryConstants {
acl.createPermission(this, dao, dao.APP_MANAGER_ROLE(), this);

// Deploy app proxies
bytes memory noInit = new bytes(0);
ENSSubdomainRegistrar ensSub = ENSSubdomainRegistrar(
dao.newAppInstance(
keccak256(abi.encodePacked(node, keccak256(abi.encodePacked(ENS_SUB_APP_NAME)))),
ensSubdomainRegistrarBase,
noInit,
false
)
);
APMRegistry apm = APMRegistry(
dao.newAppInstance(
keccak256(abi.encodePacked(node, keccak256(abi.encodePacked(APM_APP_NAME)))),
registryBase,
noInit,
false
)
);
Expand Down
4 changes: 2 additions & 2 deletions contracts/factory/EVMScriptRegistryFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ contract EVMScriptRegistryFactory is AppProxyFactory, EVMScriptRegistryConstants
}

function newEVMScriptRegistry(Kernel _dao) public returns (EVMScriptRegistry reg) {
reg = EVMScriptRegistry(_dao.newPinnedAppInstance(EVMSCRIPT_REGISTRY_APP_ID, baseReg, true));
reg.initialize();
bytes memory initPayload = abi.encodeWithSelector(reg.initialize.selector);
reg = EVMScriptRegistry(_dao.newPinnedAppInstance(EVMSCRIPT_REGISTRY_APP_ID, baseReg, initPayload, true));

ACL acl = ACL(_dao.acl());

Expand Down
14 changes: 8 additions & 6 deletions contracts/kernel/Kernel.sol
Original file line number Diff line number Diff line change
Expand Up @@ -59,26 +59,27 @@ contract Kernel is IKernel, KernelStorage, Petrifiable, IsContract, VaultRecover
auth(APP_MANAGER_ROLE, arr(APP_BASES_NAMESPACE, _appId))
returns (ERCProxy appProxy)
{
return newAppInstance(_appId, _appBase, false);
return newAppInstance(_appId, _appBase, new bytes(0), false);
}

/**
* @dev Create a new instance of an app linked to this kernel and set its base
* implementation if it was not already set
* @param _appId Identifier for app
* @param _appBase Address of the app's base implementation
* @param _initializePayload Payload for call made by the proxy during its construction to initialize
* @param _setDefault Whether the app proxy app is the default one.
* Useful when the Kernel needs to know of an instance of a particular app,
* like Vault for escape hatch mechanism.
* @return AppProxy instance
*/
function newAppInstance(bytes32 _appId, address _appBase, bool _setDefault)
function newAppInstance(bytes32 _appId, address _appBase, bytes _initializePayload, bool _setDefault)
public
auth(APP_MANAGER_ROLE, arr(APP_BASES_NAMESPACE, _appId))
returns (ERCProxy appProxy)
{
_setAppIfNew(APP_BASES_NAMESPACE, _appId, _appBase);
appProxy = newAppProxy(this, _appId);
appProxy = newAppProxy(this, _appId, _initializePayload);
// By calling setApp directly and not the internal functions, we make sure the params are checked
// and it will only succeed if sender has permissions to set something to the namespace.
if (_setDefault) {
Expand All @@ -97,26 +98,27 @@ contract Kernel is IKernel, KernelStorage, Petrifiable, IsContract, VaultRecover
auth(APP_MANAGER_ROLE, arr(APP_BASES_NAMESPACE, _appId))
returns (ERCProxy appProxy)
{
return newPinnedAppInstance(_appId, _appBase, false);
return newPinnedAppInstance(_appId, _appBase, new bytes(0), false);
}

/**
* @dev Create a new pinned instance of an app linked to this kernel and set
* its base implementation if it was not already set
* @param _appId Identifier for app
* @param _appBase Address of the app's base implementation
* @param _initializePayload Payload for call made by the proxy during its construction to initialize
* @param _setDefault Whether the app proxy app is the default one.
* Useful when the Kernel needs to know of an instance of a particular app,
* like Vault for escape hatch mechanism.
* @return AppProxy instance
*/
function newPinnedAppInstance(bytes32 _appId, address _appBase, bool _setDefault)
function newPinnedAppInstance(bytes32 _appId, address _appBase, bytes _initializePayload, bool _setDefault)
public
auth(APP_MANAGER_ROLE, arr(APP_BASES_NAMESPACE, _appId))
returns (ERCProxy appProxy)
{
_setAppIfNew(APP_BASES_NAMESPACE, _appId, _appBase);
appProxy = newAppProxyPinned(this, _appId);
appProxy = newAppProxyPinned(this, _appId, _initializePayload);
// By calling setApp directly and not the internal functions, we make sure the params are checked
// and it will only succeed if sender has permissions to set something to the namespace.
if (_setDefault) {
Expand Down
4 changes: 3 additions & 1 deletion contracts/test/mocks/APMRegistryFactoryMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,20 @@ contract APMRegistryFactoryMock is APMRegistryFactory {
acl.createPermission(this, dao, dao.APP_MANAGER_ROLE(), this);

// Deploy app proxies
// Deploy app proxies
bytes memory noInit = new bytes(0);
ENSSubdomainRegistrar ensSub = ENSSubdomainRegistrar(
dao.newAppInstance(
keccak256(abi.encodePacked(node, keccak256(abi.encodePacked(ENS_SUB_APP_NAME)))),
ensSubdomainRegistrarBase,
noInit,
false
)
);
APMRegistry apm = APMRegistry(
dao.newAppInstance(
keccak256(abi.encodePacked(node, keccak256(abi.encodePacked(APM_APP_NAME)))),
registryBase,
noInit,
false
)
);
Expand Down
12 changes: 6 additions & 6 deletions contracts/test/mocks/KernelOverloadMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ contract KernelOverloadMock {
kernel = Kernel(_kernel);
}

//function newAppInstance(bytes32 _name, address _appBase, bool _setDefault) auth(APP_MANAGER_ROLE, arr(APP_BASES_NAMESPACE, _name)) public returns (ERCProxy appProxy) {
function newAppInstance(bytes32 _name, address _appBase, bool _setDefault) public returns (ERCProxy appProxy) {
appProxy = kernel.newAppInstance(_name, _appBase, _setDefault);
//function newAppInstance(bytes32 _name, address _appBase, bytes _initializePayload, bool _setDefault) auth(APP_MANAGER_ROLE, arr(APP_BASES_NAMESPACE, _name)) public returns (ERCProxy appProxy) {
function newAppInstance(bytes32 _name, address _appBase, bytes _initializePayload, bool _setDefault) public returns (ERCProxy appProxy) {
appProxy = kernel.newAppInstance(_name, _appBase, _initializePayload, _setDefault);
emit NewAppProxy(appProxy);
}

// function newPinnedAppInstance(bytes32 _name, address _appBase) auth(APP_MANAGER_ROLE, arr(APP_BASES_NAMESPACE, _name)) public returns (ERCProxy appProxy) {
function newPinnedAppInstance(bytes32 _name, address _appBase, bool _setDefault) public returns (ERCProxy appProxy) {
appProxy = kernel.newPinnedAppInstance(_name, _appBase, _setDefault);
// function newPinnedAppInstance(bytes32 _name, address _appBase, bytes _initializePayload, bool _setDefault) auth(APP_MANAGER_ROLE, arr(APP_BASES_NAMESPACE, _name)) public returns (ERCProxy appProxy) {
function newPinnedAppInstance(bytes32 _name, address _appBase, bytes _initializePayload, bool _setDefault) public returns (ERCProxy appProxy) {
appProxy = kernel.newPinnedAppInstance(_name, _appBase, _initializePayload, _setDefault);
emit NewAppProxy(appProxy);
}
}
26 changes: 25 additions & 1 deletion test/kernel_apps.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,13 +145,37 @@ contract('Kernel apps', accounts => {
const kernelMock = await KernelOverloadMock.new(kernel.address)

await withAppManagerPermission(kernelMock.address, async () => {
const receipt = await kernelMock[newInstanceFn](APP_ID, appBase1.address, true)
const receipt = await kernelMock[newInstanceFn](APP_ID, appBase1.address, '0x', true)
appProxyAddr = receipt.logs.filter(l => l.event == 'NewAppProxy')[0].args.proxy
})

// Check that both the app base and default app are set
assert.equal(await kernel.getApp(APP_BASES_NAMESPACE, APP_ID), appBase1.address)
assert.equal(await kernel.getApp(APP_ADDR_NAMESPACE, APP_ID), appProxyAddr)

// Make sure app is not initialized
assert.isFalse(await AppStub.at(appProxyAddr).hasInitialized(), 'App shouldnt have been initialized')
})

it("allows initializing proxy when using the overloaded version", async () => {
let appProxyAddr

// Create KernelOverloadMock instance so we can use the overloaded version
const kernelMock = await KernelOverloadMock.new(kernel.address)

const initData = appBase1.initialize.request().params[0].data

await withAppManagerPermission(kernelMock.address, async () => {
const receipt = await kernelMock[newInstanceFn](APP_ID, appBase1.address, initData, false)
appProxyAddr = receipt.logs.filter(l => l.event == 'NewAppProxy')[0].args.proxy
})

// Make sure app was initialized
assert.isTrue(await AppStub.at(appProxyAddr).hasInitialized(), 'App should have been initialized')

// Check that both the app base has been set, but the app isn't the default app
assert.equal(await kernel.getApp(APP_BASES_NAMESPACE, APP_ID), appBase1.address)
assert.equal(await kernel.getApp(APP_ADDR_NAMESPACE, APP_ID), ZERO_ADDR)
})

it("fails if the app base is not given", async() => {
Expand Down