-
Notifications
You must be signed in to change notification settings - Fork 29
Remove Release contract #168
Remove Release contract #168
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Partial Review: solidity code and modified tests LGTM, plz see minor comments.
@@ -7,8 +7,7 @@ import "openzeppelin-solidity/contracts/ownership/Ownable.sol"; | |||
/** | |||
* @title AppDirectory | |||
* @dev Implementation directory with a standard library as a fallback provider. | |||
* If the implementation is not found in the directory, it will search in the | |||
* standard library. | |||
* @dev If the implementation is not found in the directory, it will search in the standard library. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regarding @dev
there is a good explanation about it here: OpenZeppelin/openzeppelin-contracts#995 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand the comments about max-len
. These are all below 120. @fiiiu Can you clarify what change you're suggesting, if any?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry I was unclear, I was simply asking whether the max-len
is indeed 120, because these comments were recently edited (and split in several lines) by @ElOpio, who is on top of the style guides..
If it is indeed 120, it's good as it is (in the PR).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh! But I did suggest removing the second @dev.
stdlib = _stdlib; | ||
} | ||
|
||
/** | ||
* @dev Returns the implementation address for a given contract name. | ||
* If the implementation is not found in the directory, it will search in the | ||
* standard library. | ||
* @dev If the implementation is not found in the directory, it will search in the standard library. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here.
* @param contractName Name of the contract. | ||
* @return Address where the contract is implemented, or 0 if it is not | ||
* found. | ||
* @return Address where the contract is implemented, or 0 if it is not found. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See max-len
comment above, also other instances below.
*/ | ||
function changeDeveloper(address newDeveloper) external onlyDeveloper { | ||
require(newDeveloper != address(0)); | ||
emit DeveloperChanged(developer, newDeveloper); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
emit
after the change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I followed what we did in AdminUpgradeabilityProxy
zos-lib/contracts/upgradeability/AdminUpgradeabilityProxy.sol
Lines 71 to 75 in 47edcb5
function changeAdmin(address newAdmin) external ifAdmin { | |
require(newAdmin != address(0)); | |
emit AdminChanged(_admin(), newAdmin); | |
_setAdmin(newAdmin); | |
} |
should we change that too?
* @dev It sets the the developer of this implementation directory. | ||
*/ | ||
function ImplementationDirectory(address _developer) public { | ||
developer = _developer; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In Release
, the developer
was set to msg.sender
, thus the owner
and the developer
were the same. Here, they can be independently modified.
Maybe the gist of this PR includes separating these two, but it's not clear from the issue (#69), and I'm yet to see a place where this is actually used. I believe this was relevant in the context of an app's stdlib
.. but still, are we adding functionality or we just need an alias? (In an AppDirectory
, there will now be: 1) its owner
, 2) its developer
, 3) its stdlib
owner
, and 4) its stdlib
developer
.. )
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exactly, that was intentional...
IMO, having just an alias doesn't make much sense. We are now making possible to have an owner responsible to set/unset implementations and additionally a developer, that in a future could receive payouts for a stdlib. However, it's just an idea, we can make these two the same address
7383b4a
to
650e7e4
Compare
please @fiiiu review again 🙏 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a bit uncomfortable with the duplication of code in the PackageWith...
classes (and their long names). Can we merge them into a common abstraction parameterized by the type of package that they use?
I haven't reviewed the tests. I think this PR is in going in the right direction by abstracting the directory logic of a package into the newVersion
function. I would be interested in exploring a bit further the possibility to reduce code duplication across the different package types.
@@ -37,7 +37,7 @@ export default class App { | |||
this.txParams = txParams | |||
} | |||
|
|||
address() { | |||
get address() { | |||
return this._app.address |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the type of this._app
here? We need some inline documentation in these files.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_app
is the PackagedApp
contract
We have another issue to tackle inline doc for the lib
src/app/App.js
Outdated
log.info(`Setting stdlib ${stdlibAddress}...`) | ||
await this.currentDirectory().setStdlib(stdlibAddress, this.txParams) | ||
return stdlibAddress | ||
return this.currentDirectory().setStdlib(stdlibAddress) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't this return a tx receipt? Shouldn't we be hiding that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ignore this. I was wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, the directory is a wrapped AppDirectory
here, it will return the address directly
|
||
static async fetch(address, txParams = {}) { | ||
const provider = new PackageProvider(txParams) | ||
return await provider.fetchForFrezzableDirectories(address) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo here: Frezzable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Solidity code and modified tests LGTM!
@@ -7,8 +7,7 @@ import "openzeppelin-solidity/contracts/ownership/Ownable.sol"; | |||
/** | |||
* @title AppDirectory | |||
* @dev Implementation directory with a standard library as a fallback provider. | |||
* If the implementation is not found in the directory, it will search in the | |||
* standard library. | |||
* @dev If the implementation is not found in the directory, it will search in the standard library. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh! But I did suggest removing the second @dev.
stdlib = _stdlib; | ||
} | ||
|
||
/** | ||
* @dev Returns the implementation address for a given contract name. | ||
* If the implementation is not found in the directory, it will search in the | ||
* standard library. | ||
* @dev If the implementation is not found in the directory, it will search in the standard library. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here.
@@ -92,11 +79,11 @@ export default class App { | |||
? await this._createProxy(contractName) | |||
: await this._createProxyAndCall(contractClass, contractName, initMethodName, initArgs) | |||
|
|||
log.info(` TX receipt received: ${receipt.transactionHash}`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the record the convention afaict was to log.info("Doing x")
and then log.info(" Did x")
with the space in the beginning to hint at its relation to the previous log message. (I opened #172 to replace all this by something nicer.)
ecfccbf
to
b6bce97
Compare
@frangio thanks for reviewing, I addressed your comments, please review again 🙏 |
b6bce97
to
7751751
Compare
@facuspagnuolo It's not necessary to use |
0432aea
to
f3d3d20
Compare
I know @frangio, I was just trying to see if Travis stops complaining about not finding dependencies |
f3d3d20
to
51e0899
Compare
I'm going to take a shot at fixing the broken build. |
I deleted all caches on Travis and it is working now. Very weird. |
Thanks @frangio ! |
ddb0708
to
6fe5ccc
Compare
6fe5ccc
to
14a7960
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As we discussed offline, there are a few places where the JS wrappers reimplement logic that should be delegated to the smart contract.
I found this PR to be too large. I did my best reviewing and I think the pull request is ok, but I can't be too confident about it. There are too many changes to focus on given the limited time that I have and my lack of knowledged of the codebase. Can we try to aim for smaller PRs next time? 🙂
@@ -37,7 +37,7 @@ export default class App { | |||
this.txParams = txParams | |||
} | |||
|
|||
address() { | |||
get address() { | |||
return this._app.address |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is backwards-incompatible, for the record.
src/app/App.js
Outdated
@@ -50,40 +50,27 @@ export default class App { | |||
} | |||
|
|||
async getImplementation(contractName) { | |||
const directory = this.currentDirectory() | |||
return directory.getImplementation(contractName) | |||
return this.package.getImplementation(this.version, contractName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be delegated to the smart contract instead of duplicating the logic.
src/package/Package.js
Outdated
return new Release(releaseAddress) | ||
async getImplementation(version, contractName) { | ||
const implementationDirectory = await this.getImplementationDirectory(version) | ||
return implementationDirectory.getImplementation(contractName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be delegated to the smart contract as well.
src/app/App.js
Outdated
async newVersion(version, stdlibAddress = 0x0) { | ||
const directory = await this.package.newVersion(version, stdlibAddress) | ||
await this._app.setVersion(version, this.txParams) | ||
log.info(`Version set`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This message could be a bit more informative like Version ${version} set in app
.
src/app/App.js
Outdated
const directory = await this.package.newVersion(version, stdlibAddress) | ||
await this._app.setVersion(version, this.txParams) | ||
log.info(`Version set`) | ||
this.directories[version] = directory |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need this.directories
at all? It's apparently only used in currentDirectory
, which duplicates the smart contract logic of BaseApp#getProvider
.
this.txParams = txParams | ||
} | ||
|
||
async fetch(address) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this async
if there is nothing asynchronous in its body? For comparison, PackageProvider#fetch
isn't async
.
|
||
async freeze() { | ||
this.log.info('Freezing implementation directory...') | ||
await this.directory.freeze(this.txParams) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should log "Frozen" after the await
.
log.info('Registering implementation in release...') | ||
await this.release.setImplementation(contractAlias, implementation.address, this.txParams) | ||
log.info('Registering implementation in implementation directory...') | ||
await this.directory.setImplementation(contractAlias, implementation.address, this.txParams) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should log something after the await
as well.
FreezableImplementationDirectory, | ||
AppDirectory, | ||
PackageWithAppDirectories, | ||
PackageWithNonFreezableDirectories, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need to simplify the external interface. We can discuss it in another issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree
@@ -14,7 +14,7 @@ const DEFAULT_COVERAGE_TX_PARAMS = { | |||
|
|||
export default { | |||
getFromLocal(contractName) { | |||
const buildDir = `${process.cwd()}/build/contracts/` | |||
const buildDir = `${process.cwd()}/build/contracts` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's try to keep these random changes out of random PRs. 😅
5cc5a4f
to
34c46a4
Compare
Thanks a lot for the review @frangio! Comments addressed. Regarding the Package interface, I do agree. I pushed another PR to reduce the interface the user should care about. We are now exporting just one object, and the user is free to choose which type of directory will be using, otherwise, |
@@ -32,12 +32,11 @@ contract('App', function ([_, owner]) { | |||
|
|||
it('initializes all app properties', async function () { | |||
this.app.version.should.eq(initialVersion); | |||
this.app.directories.should.have.key(initialVersion); | |||
this.app.directory.should.not.be.null |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This type of assertion doesn't work because if this.app.directory
is ever null
, it will fail with "cannot access property should
of null
".
I've used should.exist(this.app.directory)
before, but you need to const should = require('chai').should()
at the beginning of the file, or we could export it from the setup and do const should = require('../../setup');
.
Additionally, this probably only checks for null
but we don't want it to be undefined
either.
Fixes #69
I removed the
Release
contract and its JS wrappers.I refactored a the rest of JS wrappers architecture in order to represent the real hierarchy we have of directory contracts.