ZeppelinOSでスマートコントラクトをアップグレードさせてみた

# アップグレード可能なスマートコントラクトを簡単に作りたい！
Ethereumでデプロイしたコントラクトはアップグレードすることができないため、バグや機能拡張があった際にどうすることもできません、、、
ですが、Proxyコントラクト(Proxyパターン)を利用することで、アップグレード可能なコントラクトを作成することが可能です！

具体的には、Proxy用コントラクトと処理コントラクトを分けて作成することで、
Proxy用コントラクトからdelegatecallで処理用コントラクトを外部呼出しし、データ保持用と処理用を切り分け、更新したい場合は処理用コントラクトを更新、Proxyコントラクトが外部呼出しを行う際の参照先を変更することで、アップグレード可能なスマートコントラクトを作成できるようになるみたいです。

詳しくは、以下のサイトでまとめてくださっているのでご参照ください。
[アップグレード可能なスマートコントラクトを実現する具体的なアプローチ](https://zoom-blc.com/how-to-develop-upgradable-contracts)。

上記方法をとることで、自前でアップグレード可能なコントラクトを作成することができると思います。
ですが、コントラクトのバージョン管理やバグなくアップグレードできるように作成するのが手間かつ不安です、、、

そんな中見つけたのがZeppelinOSです！(知らなかったですが、かなり前からあったみたいです...)
ZeppelinOS ：https://docs.zeppelinos.org/docs/start.html

簡単に導入できそうなので[ZeppelinOS](https://docs.zeppelinos.org/docs/start.html)を使ってスマートコントラクトをアップグレードさせてみました！
# 実施環境
Win10
Docker
# やってみる
## 環境作成
とりあえずDockerでtruffleとzosをインストール

truffle:スマートコントラクト開発用フレームワーク
zos:プロキシコントラクト用のフレームワーク
nan:zosインストール中エラーが出たので追加でインストール
zos-lib:zosで利用するライブラリ

```terminal
$ docker run -it --name zos-test node:10.15.3 //bin/bash
$ cd ~/
$ mkdir test
$ cd test
$ npm install -y truffle nan zos zos-lib
```

ZeppelinOSを初期化。

```terminal
$ npx zos init
? Welcome to ZeppelinOS! Choose a name for your project test
? Initial project version
Project initialized. Write a new contract in the contracts folder and run 'zos create' to deploy it.
$ tree -L 1
.
|-- contracts
|-- networks.js
|-- node_modules
|-- package-lock.json
`-- zos.json
```
networks.jsとzos.jsonファイルが作成されています。
接続先とzosの管理ファイルのようです。

```js:networks.js
module.exports = {
  networks: {
    development: {
      protocol: 'http',
      host: 'localhost',
      port: 8545,
      gas: 5000000,
      gasPrice: 5e9,
      networkId: '*',
    },
  },
};
```

```json:zos.json
{
  "zosversion": "2.2",
  "contracts": {},
  "dependencies": {},
  "name": "test",
  "version": "0.1.0"
}
```

truffleを使いたいのでtruffleを初期化。

```terminal
$npx truffle init
$tree -L 1
.
|-- contracts
|-- migrations
|-- networks.js
|-- node_modules
|-- package-lock.json
|-- test
|-- truffle-config.js
`-- zos.json
```

truffleのファイルが作成されました。

ZeppelinOSで作成したnetworks.jsと、
truffleで作成truffle-config.jsで接続先設定が複数存在することになりますが、どちらが優先されるのでしょうか？
あとあとデプロイするので、その時確認していきます。

## コントラクトを作る
コントラクトを作成します。
zos-libのInitializable.solを継承しinitializerを利用することで、デプロイ初回のみ稼働する処理を作成できるみたいです。

```js:MyContract.sol
pragma solidity ^0.5.0;

import "zos-lib/contracts/Initializable.sol";

contract MyContract is Initializable {
  uint256 public x;

  function initialize(uint256 _x) initializer public {
    x = _x;
  }

  function get() public view returns (uint256) {
    return x;
  }

  function set(uint256 _x) public {
    x = _x;
  }
}
```

## デプロイ
いよいよデプロイしていきます。
テストネットには[Ganache](https://www.trufflesuite.com/ganache)を利用します。

Ganacheを起動してワークスペース作成。
設定画面 > SERVER > HostNameでイーサネットを設定します。

truffle-config.jsに立ち上げたGanacheのRPC SERVER設定を追記します。

```js:truffle-config.js
  networks: {
    development: {
      host: 'XXX.XXX.XXX.XXX',
      port: 7545,
      network_id: '*'
    }
 }

```

念のため、truffleのコンソールを立ち上げてつながるか確認。

```terminal
$ npx truffle console
truffle(development)>
undefined
truffle(development)> .exit
```

準備が完了したので、デプロイしてみます。
zosプロジェクトにコントラクトをaddします。

```terminal
$ npx zos add MyContract
✓ Compiling contracts with Truffle, using settings from truffle.js file
Truffle output:

Compiling your contracts...
===========================
> Compiling ./contracts/MyContract.sol
> Compiling zos-lib/contracts/Initializable.sol
> Artifacts written to /share/test/build/contracts
> Compiled successfully using:
   - solc: 0.5.8+commit.23d335f2.Emscripten.clang


✓ Added contract MyContract
```

addすることで、コントラクトのコンパイル & zos.jsonにaddしたコントラクト情報が追加されるみたいです。

```json:zos.json
{
  "zosversion": "2.2",
  "contracts": {
    "MyContract": "MyContract"
  },
  "dependencies": {},
  "name": "test",
  "version": "0.1.0",
  "compiler": {
    "manager": "truffle",
    "compilerSettings": {
      "optimizer": {}
    }
  }
}
```

次にpushします。

```terminal
$ npx zos push
✓ Compiling contracts with Truffle, using settings from truffle.js file
Truffle output:

Compiling your contracts...
===========================
> Compiling ./contracts/MyContract.sol
> Compiling zos-lib/contracts/Initializable.sol
> Artifacts written to /share/test/build/contracts
> Compiled successfully using:
   - solc: 0.5.8+commit.23d335f2.Emscripten.clang


? Pick a network (Use arrow keys)
❯ development
Could not connect to the development Ethereum network on http://localhost:8545. Please check your networks.js configuration file. Error: Invalid JSON RPC response: "".
```

ネットワーク設定でdevelopmentを選択すると、localhost:8545でエラーになります。
truffle-config.jsの設定がnetworks.jsで上書きされているようにみえます。

truffle-config.jsのネットワーク名をdevelopment_trfに変更して再チャレンジ！

```
$ npx zos push
✓ Compiling contracts with Truffle, using settings from truffle.js file
Truffle output:

Compiling your contracts...
===========================
> Compiling ./contracts/MyContract.sol
> Compiling zos-lib/contracts/Initializable.sol
> Artifacts written to /share/test/build/contracts
> Compiled successfully using:
   - solc: 0.5.8+commit.23d335f2.Emscripten.clang


? Pick a network
❯ development
```

上書きというか、参照されてないみたいです。
truffleのネットワーク設定を参照させたいので、networks.jsを削除して再チャレンジ。

```
$ npx zos push
✓ Compiling contracts with Truffle, using settings from truffle.js file
Truffle output:

Compiling your contracts...
===========================
> Compiling ./contracts/MyContract.sol
> Compiling zos-lib/contracts/Initializable.sol
> Artifacts written to /share/test/build/contracts
> Compiled successfully using:
   - solc: 0.5.8+commit.23d335f2.Emscripten.clang


? Pick a network development_trf
✓ Contract MyContract deployed
All contracts have been deployed
```

上手くいきました！
development_trfを選択してデプロイ完了です。
デプロイすることでzosのデプロイ情報ファイルが作成されるみたいです。

```json:zos.dev-5777.json
{
  "contracts": {
    "MyContract": {
      "address": "0x6684f937f2182801bcDAF4E87b58A75C35D399Be",
      "constructorCode": "608060405234801561001057600080fd5b50610275806100206000396000f3fe",
      "bodyBytecodeHash": "e569853a7786790e009487234e007962c5a833f976699426916e9e62977381f4",
      "localBytecodeHash": "3b95e7a22280d4a0e2a6ed4a92d4bdfd244bdc0acd21db038f65bd0909cc3c2f",
      "deployedBytecodeHash": "3b95e7a22280d4a0e2a6ed4a92d4bdfd244bdc0acd21db038f65bd0909cc3c2f",
      "types": {
        "t_bool": {
          "id": "t_bool",
          "kind": "elementary",
          "label": "bool"
        },
        "t_uint256": {
          "id": "t_uint256",
          "kind": "elementary",
          "label": "uint256"
        },
      
      ===省略=============================================
      
      },
      "storage": [
        {
          "contract": "Initializable",
          "path": "zos-lib/contracts/Initializable.sol",
          "label": "initialized",
          "astId": 41,
          "type": "t_bool",
          "src": "757:24:1"
        },
        {
          "contract": "Initializable",
          "path": "zos-lib/contracts/Initializable.sol",
          "label": "initializing",
          "astId": 43,
          "type": "t_bool",
          "src": "876:25:1"
        },
      
      ===省略=============================================
      
      ],
      "warnings": {
        "hasConstructor": false,
        "hasSelfDestruct": false,
        "hasDelegateCall": false,
        "hasInitialValuesInDeclarations": false,
        "uninitializedBaseContracts": []
      }
    }
  },
  "solidityLibs": {},
  "proxies": {},
  "zosversion": "2.2",
  "version": "0.1.0"
}
```

proxiesが空なので、普通にコントラクトがデプロイされただけみたいです。
Gnacheに登録されていると思うので動作を見てみます。

```
npx truffle console --network development_trf
truffle(development_trf)> myContract = await MyContract.at('0x6684f937f2182801bcDAF4E87b58A75C35D399Be')
truffle(development_trf)> myContract.get()
<BN: 0>
truffle(development_trf)> myContract.set(2)
{ tx:
   '0xa21783ecb6fcc6d69d8707b293a394ec7c630ccb51df288becd8a282eccaa512',
  receipt:
   { transactionHash:
      '0xa21783ecb6fcc6d69d8707b293a394ec7c630ccb51df288becd8a282eccaa512',
     transactionIndex: 0,
     blockHash:
      '0x16beb8af590b0e27c1e260432ee7ce7c16674cbcf5735cfe7f78ec68d24099c4',
     blockNumber: 273,
     from: '0xf500dfd70aaea58cc75ee657e7cbdf7282cc92fc',
     to: '0x6684f937f2182801bcdaf4e87b58a75c35d399be',
     gasUsed: 41706,
     cumulativeGasUsed: 41706,
     contractAddress: null,
     logs: [],
     status: true,
     logsBloom:
      '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
     v: '0x1b',
     r:
      '0x6c8e0f2ba433796334322f54faa462487ba2d91030b40b323c21ae96253d0890',
     s:
      '0x7b7c0269b7e61e1d077ec39237c2da249384fce03e199f7dc4b9ea66736725a0',
     rawLogs: [] },
  logs: [] }
truffle(development_trf)> myContract.get()
<BN: 2>
```

登録されているみたいです。

次にcreateを実行してみます。
これでプロキシコントラクトが作成され、先ほどのコントラクトが参照されるのだと思います。

```terminal
$ npx zos create MyContract --init initialize --args 42
✓ Compiling contracts with Truffle, using settings from truffle.js file
Truffle output:

Compiling your contracts...
===========================
> Compiling ./contracts/MyContract.sol
> Compiling zos-lib/contracts/Initializable.sol
> Artifacts written to /share/test/build/contracts
> Compiled successfully using:
   - solc: 0.5.8+commit.23d335f2.Emscripten.clang


? Pick a network development_trf
All contracts are up to date
✓ Setting everything up to create contract instances
✓ Instance created at 0x9dcee86c9F0B308cE3d580391174f406a9369563
0x9dcee86c9F0B308cE3d580391174f406a9369563
```

デプロイ完了です。
zos.dev-5777.jsonの差分を見てみます。(※差分以外は省略しています。)

```json:zos.dev-5777.json
  "proxies": {
    "test/MyContract": [
      {
        "address": "0x9dcee86c9F0B308cE3d580391174f406a9369563",
        "version": "0.1.0",
        "implementation": "0x6684f937f2182801bcDAF4E87b58A75C35D399Be",
        "kind": "Upgradeable"
      }
    ]
  },
  "zosversion": "2.2",
  "version": "0.1.0",
  "proxyAdmin": {
    "address": "0x1374a26FF0cFCA967a3A9a8AC5EcB19520055De7"
  }
```
proxies以降の部分に値が追加されました。

addressがプロキシのアドレス。
implementationが先ほどデプロイしたコントラクトのアドレスみたいです。
proxyAdminがプロキシアドレス管理用のアカウントみたいです。[ZeppelinOS ProxyAdmin](https://docs.zeppelinos.org/docs/upgradeability_ProxyAdmin.html)

それでは実際に動かしてみます。
まずは、pushの時にデプロイしたコントラクトから。

```
truffle(development_trf)> myContract = await MyContract.at('0x6684f937f2182801bcDAF4E87b58A75C35D399Be')
undefined
truffle(development_trf)> myContract.get()
<BN: 2>
```

当たり前ですが、先ほどコンソールでsetした値が保持され続けています。
次にプロキシコントラクトを動かしてみます。

```
truffle(development_trf)> myContract2 = await MyContract.at('0x9dcee86c9F0B308cE3d580391174f406a9369563')
undefined
truffle(development_trf)> myContract2.get()
<BN: 2a>
```

initialize時に設定した値が設定されています。
プロキシアドレスの値を変えてみます。※set時のトランザクション部分は省略しています。

```
truffle(development_trf)> myContract2.set(111)
truffle(development_trf)> myContract2.get()
<BN: 6f>
```

上手く更新できました。
あたりまえですが、pushでデプロイしたコントラクトには影響はないです。

```
truffle(development_trf)> myContract.get()
<BN: 2>
```

##アップグレードしてみる

アップグレードしてみます。
アップグレード内容としては、Functionを増やしただけです。

```js:MyContract.sol
pragma solidity ^0.5.0;

import "zos-lib/contracts/Initializable.sol";

contract MyContract is Initializable {
  uint256 public x;

  function initialize(uint256 _x) initializer public {
    x = _x;
  }

  function get() public view returns (uint256) {
    return x;
  }

  function set(uint256 _x) public {
    x = _x;
  }

  function get2() public view returns (uint256) {
    return x;
  }

  function set2(uint256 _x) public {
    x = _x;
  }
}
```

まずはpush。

```terminal
npx zos push
✓ Compiling contracts with Truffle, using settings from truffle.js file
Truffle output:

Compiling your contracts...
===========================
> Compiling ./contracts/MyContract.sol
> Compiling zos-lib/contracts/Initializable.sol
> Artifacts written to /share/test/build/contracts
> Compiled successfully using:
   - solc: 0.5.8+commit.23d335f2.Emscripten.clang


? Pick a network development_trf
✓ Contract MyContract deployed
All contracts have been deployed
```

pushしたので、zos.dev-5777.jsonを見てみます。
※★マークが差分箇所

```json:zos.dev-5777.json
{
  "contracts": {
    "MyContract": {
★      "address": "0xEEBE33b05E2a254Cc9dD5c3DD53Cd3B2723F5FbF",
★      "constructorCode": "608060405234801561001057600080fd5b506102eb806100206000396000f3fe",
★      "bodyBytecodeHash": "bfd43f1f360ee66693f641cd11005eafc65d5f06246f2de800069565d523728b",
★      "localBytecodeHash": "bce1409ee0ff584a19c39e94b736cbc6a0e8bae6f4f846bfe326e3a4b72a071b",
★      "deployedBytecodeHash": "bce1409ee0ff584a19c39e94b736cbc6a0e8bae6f4f846bfe326e3a4b72a071b",
      "types": {
        "t_bool": {
          "id": "t_bool",
          "kind": "elementary",
          "label": "bool"
        },
        "t_uint256": {
          "id": "t_uint256",
          "kind": "elementary",
          "label": "uint256"
        },
        "t_array:50<t_uint256>": {
          "id": "t_array:50<t_uint256>",
          "valueType": "t_uint256",
          "length": "50",
          "kind": "array",
          "label": "uint256[50]"
        }
      },
      "storage": [
        {
          "contract": "Initializable",
          "path": "zos-lib/contracts/Initializable.sol",
          "label": "initialized",
★          "astId": 59,
          "type": "t_bool",
          "src": "757:24:1"
        },
        {
          "contract": "Initializable",
          "path": "zos-lib/contracts/Initializable.sol",
          "label": "initializing",
★          "astId": 61,
          "type": "t_bool",
          "src": "876:25:1"
        },
        {
          "contract": "Initializable",
          "path": "zos-lib/contracts/Initializable.sol",
          "label": "______gap",
★          "astId": 117,
          "type": "t_array:50<t_uint256>",
          "src": "1951:29:1"
        },
        {
          "contract": "MyContract",
          "path": "contracts/MyContract.sol",
          "label": "x",
          "astId": 6,
          "type": "t_uint256",
          "src": "118:16:0"
        }
      ],
      "warnings": {
        "hasConstructor": false,
        "hasSelfDestruct": false,
        "hasDelegateCall": false,
        "hasInitialValuesInDeclarations": false,
        "uninitializedBaseContracts": [],
★        "storageUncheckedVars": [],
★        "storageDiff": []
      }
    }
  },
  "solidityLibs": {},
  "proxies": {
    "test/MyContract": [
      {
        "address": "0x9dcee86c9F0B308cE3d580391174f406a9369563",
        "version": "0.1.0",
        "implementation": "0x6684f937f2182801bcDAF4E87b58A75C35D399Be",
        "kind": "Upgradeable"
      }
    ]
  },
  "zosversion": "2.2",
  "version": "0.1.0",
  "proxyAdmin": {
    "address": "0x1374a26FF0cFCA967a3A9a8AC5EcB19520055De7"
  }
}
```

新たにデプロイしたので、MyConstract部分が変更されました。
astId部分はStrageのIDっぽいですが、使われ方がよくわかりません。


次にupdateをしていきます。

```terminal
$ npx zos update MyContract
? Pick a network development_trf
✓ Compiling contracts with Truffle, using settings from truffle.js file
Truffle output:

Compiling your contracts...
===========================
> Compiling ./contracts/MyContract.sol
> Compiling zos-lib/contracts/Initializable.sol
> Artifacts written to /share/test/build/contracts
> Compiled successfully using:
   - solc: 0.5.8+commit.23d335f2.Emscripten.clang


All contracts are up to date
? Do you want to call a function on the instance after upgrading it? No
✓ Instance upgraded at 0x9dcee86c9F0B308cE3d580391174f406a9369563. Transaction receipt: 0x0076479db3f80f6ce8ea8fc683d475bfbfd3f4e6aa733ccd13635a582a8b0982
```

上手くアップデートできました。
アップデートの最後にアップデートしたインスタンスの動作確認もできるみたいです。(私はnoでしませんでした。)

zos.dev-5777.jsonの差分を見ていきます。

```json:zos.dev-5777.json
"implementation": "0xEEBE33b05E2a254Cc9dD5c3DD53Cd3B2723F5FbF",
```

一か所だけです。プロキシが呼び出すコントラクトがpushでデプロイしたコントラクトに変更されたみたいです。
では、実際に動作させていきます。

myContract1が初めにデプロイしたコントラクト
myContract2が今回update時にデプロイしたコントラクト
myContractproがプロキシコントラクト
です。

```terminal
npx truffle console --network development_trf
truffle(development_trf)> myContract1 = await MyContract.at('0x6684f937f2182801bcDAF4E87b58A75C35D399Be')
undefined
truffle(development_trf)> myContract2 = await MyContract.at('0xEEBE33b05E2a254Cc9dD5c3DD53Cd3B2723F5FbF')
undefined
truffle(development_trf)> myContractpro = await MyContract.at('0x9dcee86c9F0B308cE3d580391174f406a9369563')
undefined
truffle(development_trf)> myContract1.get()
<BN: 2>
truffle(development_trf)> myContract2.get()
<BN: 0>
truffle(development_trf)> myContractpro.get()
<BN: 6f>
```
プロキシコントラクト(myContractpro)を見ると、アップデート前に更新された値が正しく返却されていることがわかります。
myContract2については、setしていないため初期値です。

次にFunctionを見ていきます。

```terminal
truffle(development_trf)> myContract1.get2()
Error: Returned error: VM Exception while processing transaction: revert
    at XMLHttpRequest._onHttpResponseEnd (/share/test/node_modules/truffle/build/webpack:/~/xhr2-cookies/dist/xml-http-request.js:318:1)
    at XMLHttpRequest._setReadyState (/share/test/node_modules/truffle/build/webpack:/~/xhr2-cookies/dist/xml-http-request.js:208:1)
    at XMLHttpRequestEventTarget.dispatchEvent (/share/test/node_modules/truffle/build/webpack:/~/xhr2-cookies/dist/xml-http-request-event-target.js:34:1)
    at XMLHttpRequest.request.onreadystatechange (/share/test/node_modules/truffle/build/webpack:/~/web3-providers-http/src/index.js:96:1)
    at /share/test/node_modules/truffle/build/webpack:/packages/truffle-provider/wrapper.js:112:1
    at /share/test/node_modules/truffle/build/webpack:/~/web3-core-requestmanager/src/index.js:140:1
    at Object.ErrorResponse (/share/test/node_modules/truffle/build/webpack:/~/web3-core-requestmanager/~/web3-core-helpers/src/errors.js:29:1)
truffle(development_trf)> myContract2.get2()
<BN: 0>
truffle(development_trf)> myContractpro.get2()
<BN: 6f>
truffle(development_trf)>
```

strageの値を保持したままFunctionが追加されていること(アップデートされていること)が確認できました！

# トランザクション発行者を見てみる

外部コントラクトをCallするFunctionとCallされるコントラクトを作成して、発行者が誰か見てみます。
Proxyコントラクトがdelegatecallしてロジック呼び出してCallするので、発行者はProxyコントラクトアドレスになるはずです。

```js:MyContract.sol
pragma solidity ^0.5.0;

import "zos-lib/contracts/Initializable.sol";

contract MyContract is Initializable {

==省略==================

  function call2(address _address) public{
    _address.call(abi.encodeWithSignature("setSender()"));
  }
}
```

```js:CallContract.sol
pragma solidity ^0.5.0;

import "zos-lib/contracts/Initializable.sol";

contract CallContract is Initializable {

  address public msgSender;

  function setSender() public {
    msgSender = msg.sender;
  }

  function get() public view returns (address) {
    return msgSender;
  }
}
```

やってみます。確認に使うコントラクトはどちらもProxyコントラクトです。

```terminal
$ npx truffle console --network development_trf
truffle(development_trf)> Caller = await MyContract.at('0x9dcee86c9F0B308cE3d580391174f406a9369563')
undefined
truffle(development_trf)> Call = await CallContract.at('0xdD4Bf0c508fD2EfF2336056dd7d596726b865b81')
undefined
truffle(development_trf)> Call.get()
'0xF500dFd70aaEa58CC75eE657e7cBDF7282Cc92fc'
truffle(development_trf)> Caller.call2('0xdD4Bf0c508fD2EfF2336056dd7d596726b865b81')
{ tx:
   '0x431c2c0a612423be942362412ee6c4eb0bc5b958fef9945af744ac84174b4fb5',
  receipt:
   { transactionHash:
      '0x431c2c0a612423be942362412ee6c4eb0bc5b958fef9945af744ac84174b4fb5',
     transactionIndex: 0,
     blockHash:
      '0x978cb062f1e3536683c3c90607a22fb2c88dfc097681fa96e18998f41e96b798',
     blockNumber: 300,
     from: '0xf500dfd70aaea58cc75ee657e7cbdf7282cc92fc',
     to: '0x9dcee86c9f0b308ce3d580391174f406a9369563',
     gasUsed: 32593,
     cumulativeGasUsed: 32593,
     contractAddress: null,
     logs: [],
     status: true,
     logsBloom:
      '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
     v: '0x1b',
     r:
      '0x3a3adeb65f9faf1eb6971b6d3ee66f76695cbf836bae2e60396cee5ddb30d521',
     s:
      '0x68f0d8ec3f794a9221154caf66b72c748f44f610b8cc7b07a1c4040ed0353ed2',
     rawLogs: [] },
  logs: [] }
truffle(development_trf)> Call.get()
'0x9dcee86c9F0B308cE3d580391174f406a9369563'
```

想定していた通り、発行者はプロキシコントラクトになっていました。

# まとめ
アップグレード可能なZeppelinOSを試してみました。
導入自体は簡単にできましたが、
アップグレード前のコントラクトもブロックチェーン上では生き続けるので注意が必要だと感じました。