What's the reason for the division between sdk and contracts?

So, I’ve been modifying the sdk proxy contracts lately… implementing one that’s Cautiously Transferable (new admin needs to confirm to complete admin transfer) - and now that I’m done with that, I’m wondering why, say, those proxy contracts aren’t available in the “contracts” repo. Actually took me quite a long time to find what I wanted. I know the proxy contracts are supposed to be used with the openzeppelin cli tools, but why bury them there exclusively?

The way it is now, I guess it wouldn’t make sense to submit a PR to the sdk for a version of a proxy that I’m not using with the cli… is that right?

For reference (or if anyone wants a cautiously upgradeable proxy :wink: ):


Hi @CallMeGwei

The OpenZeppelin documentation can help find what you need, including from Contracts and SDK. Would appreciate your thoughts on how this could be improved.
You can always ask questions in the forum too :smile:

Is there a reason that you want to use the OpenZeppelin SDK proxy contracts but not use the OpenZeppelin SDK? Standalone usage of the proxy contracts is discouraged as these are complex systems and manual operation is error prone, thus potentially unsafe.

As an aside, I really like the interactive commands in the SDK and these make my life much easier with so much handled for me by the SDK.

I think looking at the process of changing ownership and how it could be improved, is a great discussion to be had. Discussing in the forum, creating Issues and Pull Requests is highly encouraged. :rocket:

Hey @CallMeGwei, thanks for the contribution on the Cautious proxy! We try to keep the proxy as slim as possible (due to both security and gas costs), that’s why we avoid implementing additional features on it. That makes me think: would it be possible to implement the Cautious behaviour on the owner instead of on the proxy, if the owner is a contract? Maybe something like the following, which could be baked into the ProxyAdmin.

contract CautiousOwner {
  mapping(address => address) pendingTransfers;

  // The owner signals that she wants to start the transfer of an owned asset to someone else
  function startTransferOwnership(address what, address toWhom) internal {
    require(implementsInterface(toWhom, CautiousOwner));
    pendingTransfers[what] = toWhom;

  // To be called by that someone else, to claim ownership
  function claimOwnership(address what) external {
    require(pendingTransfers[what] == msg.sender);
    pendingTransfers[what] = address(0);

  // The owner calls this to claim a new asset from another cautious owner
  function claimOwnershipFrom(address what, address fromWhom) internal {

I’m interested in what @frangio or @nventuro think about this, since they have worked a lot with ownership patterns in OpenZeppelin Contracts.

Now, onto the original question: as @abcoathup mentioned, proxies can lead to nasty situations if used manually, hence the CLI and library around them to guard their usage. However, it could be argued that this may also be true of other contracts in the Contracts repository, or that this is too strong a limitation. To be honest, we will be probably re-evaluating this decision in the upcoming weeks, so proxies may make their way to Contracts, or even to a new package.


@spalladino In essence, that is what the ‘cautious’ additions facilitate. (Just swap ‘owner’ term for ‘admin’) [was just keeping the naming conventions in line with the other proxy contracts].

FWIW I do think that having a proxyAdmin layer (a contract managing a contract) leads to more possibilities of being locked out if things are managed manually. (When it comes to the proxyAdmin contract - You can lose access to owner or set owner to the wrong address. Then you could also set the proxy administrator address in proxy to the wrong address and there are no checks… seems… less than cautious.)

So, basically I was just looking to port over my Ownable tweaks to the proxy and not have to worry about another admin layer. BUT I couldn’t just simply inherit OwnableCautious because of the storage location quirks the proxy requires. I didn’t really look into it, but perhaps I could have just used assembly to pick the location for a new _owner var and inherited the cautious owner logic…

That would have then not inherited from the Admin proxy contract. May still investigate this later.

I will say the structure of the proxy contracts isn’t necessarily beginner friendly, if that is in any way a goal of the contracts leg of OpenZeppelin. Maybe a contracts-pro repo :wink: or flattening some stuff down and giving them their own names and documentation.

I think proxies are going to be increasingly important. And I think being cautious with transfers of control should be baked in to anything where a transfer is possible.

Interested to hear with you all think.


Is there a reason that you want to use the OpenZeppelin SDK proxy contracts but not use the OpenZeppelin SDK?

I didn’t want to use them as-is. I needed some extra features that aren’t implemented yet in the available proxy packages.

and manual operation is error prone

This is why I built in a safety net. :wink:

I am writing an ‘entity’ contract [I will shy away from the term ‘identity’ - as that is not my focus… though there is a very fine line]. For this entity, I want some aspects immutable and some aspects upgrade-able. It is also absolutely essential that the owner cannot inadvertently lose control of the entity. So, this takes aspects of a proxy, aspects of OwnableCautious, and aspects of… well… I’ll tell you when I’m done.

But that’s how I got here at this point.

1 Like