├── .gitattributes ├── .gitignore ├── .npmignore ├── .soliumignore ├── .soliumrc.json ├── .travis.yml ├── LICENSE ├── README.md ├── assets └── doppelganger-logo-512w.png ├── contracts └── Doppelganger.sol ├── lib └── index.ts ├── package.json ├── test ├── helpers │ ├── contracts │ │ ├── Cap.sol │ │ └── Counter.sol │ └── interfaces │ │ ├── Cap.json │ │ └── Counter.json ├── integrations │ ├── direct.ts │ └── proxied.ts ├── mocha.opts └── units │ ├── doppelganger_contract.ts │ └── doppelganger_tool.ts ├── tsconfig.json ├── tslint.json ├── waffle_lib.json ├── waffle_test.json └── yarn.lock /.gitattributes: -------------------------------------------------------------------------------- 1 | package-lock.json binary 2 | yarn.lock binary 3 | *.sol linguist-language=Solidity 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | yarn-error.log 4 | lib/Doppelganger.json 5 | test_cli_head.env 6 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .idea 3 | .vscode 4 | .travis.yml 5 | .soliumrc.json 6 | .soliumignore 7 | yarn-error.log 8 | test 9 | waffle_lib.json 10 | waffle_test.json 11 | assets -------------------------------------------------------------------------------- /.soliumignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /.soliumrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "solium:all", 3 | "plugins": [ 4 | "security" 5 | ], 6 | "rules": { 7 | "max-len": [ 8 | "error", 9 | 160 10 | ], 11 | "quotes": [ 12 | "error", 13 | "double" 14 | ], 15 | "indentation": [ 16 | "error", 17 | 4 18 | ], 19 | "operator-whitespace": [ 20 | "error" 21 | ], 22 | "arg-overflow": 0, 23 | "security/no-block-members": [ 24 | "error", 25 | ["blockhash"] 26 | ], 27 | "operator-whitespace": [ 28 | "error" 29 | ] 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: trusty 2 | language: node_js 3 | cache: 4 | yarn: true 5 | directories: 6 | - node_modules 7 | node_js: 8 | - '10' 9 | install: 10 | - yarn install 11 | script: 12 | - yarn build 13 | - yarn dev:lint 14 | - yarn test -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2018 Ethworks - Antoni Kędracki 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Depreciation notice 2 | This npm is deprecated and not supported anymore. 3 | For smart contract mocking functionality use [@ethereum-waffle/mock-contract](https://github.com/EthWorks/Waffle/tree/master/waffle-mock-contract). 4 | 5 | ![Doppelganger](https://raw.githubusercontent.com/EthWorks/Doppelganger/master/assets/doppelganger-logo-512w.png "Doppelganger") 6 | 7 | _doppelgänger /ˈdɒp(ə)lˌɡaŋə,ˈdɒp(ə)lˌɡɛŋə/ - an apparition or double of a living person_ 8 | 9 | 10 | [![Build Status](https://travis-ci.com/EthWorks/Doppelganger.svg?branch=master)](https://travis-ci.com/EthWorks/Doppelganger) 11 | 12 | 13 | Library for mocking smart contract dependencies during unit testing. 14 | 15 | ## Install 16 | To start using with npm, type: 17 | ```sh 18 | npm i -D ethereum-doppelganger 19 | ``` 20 | 21 | or with Yarn: 22 | ```sh 23 | yarn add --dev ethereum-doppelganger 24 | ``` 25 | 26 | Doppelganger is currently developed to work with [ethers-js](https://github.com/ethers-io/ethers.js/) exclusively. Support for other framework will be added in a future version. 27 | 28 | ## Usage 29 | 30 | Create a instance of `Doppelganger` providing the ABI/interface of the smart contract you want to mock: 31 | 32 | ```js 33 | import Doppelganger from 'ethereum-doppelganger'; 34 | 35 | ... 36 | 37 | const doppelganger = new Doppelganger(abi); 38 | ``` 39 | 40 | Deploy a instance of the Doppelganger smart contract: 41 | 42 | ```js 43 | await doppelganger.deploy(wallet); 44 | ``` 45 | 46 | Doppelganger can now be passed into other contracts by using the `address` attribute. 47 | 48 | Return values for mocked functions can be set using: 49 | 50 | ```js 51 | await doppelganger..returns() 52 | ``` 53 | 54 | ## Example 55 | 56 | Below example illustrates how Doppelganger can be used to test the very simple `AmIRichAlready` contract. 57 | 58 | ```Solidity 59 | pragma solidity ^0.4.24; 60 | 61 | import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol"; 62 | 63 | contract AmIRichAlready { 64 | IERC20 private tokenContract; 65 | address private wallet; 66 | uint private constant RICHNESS = 1000000 * 10 ** 18; 67 | 68 | constructor (IERC20 _tokenContract) public { 69 | tokenContract = _tokenContract; 70 | wallet = msg.sender; 71 | } 72 | 73 | function check() public view returns(bool) { 74 | uint balance = tokenContract.balanceOf(wallet); 75 | return balance > RICHNESS; 76 | } 77 | } 78 | ``` 79 | 80 | We are mostly interested in the `tokenContract.balanceOf` call. Doppelganger will be used to mock exactly this call with values that are significant for the return of the `check()` method. 81 | 82 | ```js 83 | import chai, {expect} from 'chai'; 84 | import chaiAsPromised from 'chai-as-promised'; 85 | import ethers from 'ethers'; 86 | import {createMockProvider, deployContract, getWallets} from 'ethereum-waffle'; 87 | import Doppelganger from 'ethereum-doppelganger'; 88 | 89 | import IERC20 from '../../build/IERC20'; 90 | import AmIRichAlready from '../../build/AmIRichAlready'; 91 | 92 | chai.use(chaiAsPromised); 93 | 94 | describe('Am I Rich Already?', () => { 95 | let provider; // connector to the ethereum network - in our case a Ganache instance 96 | let user; // the account issuing interactions on the network 97 | let contract; // an instance of the AmIRichAlready contract 98 | let doppelganger; // an instance of doppelganger for the ERC20 token we want to observe 99 | 100 | before(async () => { 101 | provider = createMockProvider(); 102 | [user] = await getWallets(provider); 103 | }); 104 | 105 | beforeEach(async () => { 106 | doppelganger = new Doppelganger(IERC20.interface); // say doppelganger what it should pretend to be 107 | await doppelganger.deploy(user); // deploy the doppelganger to the chain 108 | contract = await deployContract(user, AmIRichAlready, [doppelganger.address]); // deploy the contract under test to the chain 109 | }); 110 | 111 | describe('check method', () => { 112 | it('returns false if the wallet has less then 1000000 DAI', async () => { 113 | await doppelganger.balanceOf.returns(ethers.utils.parseEther('999999')); // configure doppelganger to return 999999 when balanceOf is called 114 | await expect(contract.check()).to.eventually.be.fulfilled.and.equal(false); 115 | }); 116 | 117 | it('returns false if the wallet has exactly 1000000 DAI', async () => { 118 | await doppelganger.balanceOf.returns(ethers.utils.parseEther('1000000')); // subsequent calls override the previous config 119 | await expect(contract.check()).to.eventually.be.fulfilled.and.equal(false); 120 | }); 121 | 122 | it('returns true if the wallet has more then 1000000 DAI', async () => { 123 | await doppelganger.balanceOf.returns(ethers.utils.parseEther('1000001')); 124 | await expect(contract.check()).to.eventually.be.fulfilled.and.equal(true); 125 | }); 126 | }); 127 | }); 128 | ``` 129 | -------------------------------------------------------------------------------- /assets/doppelganger-logo-512w.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EthWorks/Doppelganger/d7aa72180bc00a117da66d9f989c498af9f9243d/assets/doppelganger-logo-512w.png -------------------------------------------------------------------------------- /contracts/Doppelganger.sol: -------------------------------------------------------------------------------- 1 | /* solium-disable security/no-inline-assembly */ 2 | pragma solidity ^0.4.24; 3 | 4 | 5 | contract Doppelganger { 6 | mapping (bytes4 => bytes) mockConfig; 7 | 8 | function() public { 9 | bytes memory ret = mockConfig[msg.sig]; 10 | assembly { 11 | return(add(ret, 0x20), mload(ret)) 12 | } 13 | } 14 | 15 | function mockReturns(bytes4 key, bytes value) public { 16 | mockConfig[key] = value; 17 | } 18 | } -------------------------------------------------------------------------------- /lib/index.ts: -------------------------------------------------------------------------------- 1 | import { utils, Contract, Wallet } from 'ethers'; 2 | import DoppelgangerContract from './Doppelganger.json'; 3 | import { deployContract } from 'ethereum-waffle'; 4 | 5 | const prepareAbi = (abiOrString: any) => (typeof abiOrString === 'string' 6 | ? JSON.parse(abiOrString) 7 | : abiOrString 8 | ); 9 | 10 | export default class Doppelganger { 11 | abi: any; 12 | contractInstance?: Contract; 13 | [key: string]: any; 14 | 15 | constructor(abiOrString: any, contractInstance?: Contract) { 16 | this.abi = prepareAbi(abiOrString); // This is not needed and untested 17 | this.contractInstance = contractInstance; 18 | 19 | const { functions } = new utils.Interface(this.abi); 20 | const encoder = new utils.AbiCoder(); 21 | for (const funcName of Object.keys(functions)) { 22 | const func = functions[funcName]; 23 | // This will override properties like abi, address or contractInstance! 24 | this[funcName] = { 25 | returns: async (...args: any) => { 26 | const encoded = encoder.encode(func.outputs, args); 27 | // This will throw an exception when instance is undefined! 28 | await this.contractInstance!.mockReturns(func.sighash, encoded); 29 | }, 30 | }; 31 | } 32 | } 33 | 34 | pretendedContract(wallet: Wallet) { 35 | // This will throw an exception when instance is undefined! 36 | return new Contract(this.contractInstance!.address, this.abi, wallet); 37 | } 38 | 39 | get address() { 40 | // This will throw an exception when instance is undefined! 41 | return this.contractInstance!.address; 42 | } 43 | 44 | async deploy(wallet: Wallet) { 45 | this.contractInstance = await deployContract(wallet, DoppelgangerContract); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ethereum-doppelganger", 3 | "version": "0.0.7", 4 | "description": "Smart contract mocking library", 5 | "repository": "https://github.com/EthWorks/Doppelganger.git", 6 | "author": "Antoni Kedracki (http://ethworks.io)", 7 | "license": "MIT", 8 | "private": false, 9 | "main": "dist/lib/index.js", 10 | "types": "dist/lib/index.d.ts", 11 | "scripts": { 12 | "prepublishOnly": "yarn build", 13 | "build": "rm -rf dist && yarn build:sol && yarn build:ts", 14 | "build:sol": "yarn waffle ./waffle_lib.json", 15 | "build:ts": "tsc", 16 | "test": "mocha \"test/**/*.ts\"", 17 | "test:build:sol": "yarn waffle ./waffle_test.json", 18 | "dev:lint": "tslint lib/**/*.ts test/**/*.ts && solium -d contracts/" 19 | }, 20 | "dependencies": { 21 | "@types/ganache-core": "^2.1.2", 22 | "ethereum-waffle": "^2.0.12", 23 | "ethers": "^4.0.18" 24 | }, 25 | "devDependencies": { 26 | "@types/chai": "^4.1.7", 27 | "@types/chai-as-promised": "^7.1.0", 28 | "@types/mocha": "^5.2.5", 29 | "@types/sinon": "^7.0.0", 30 | "@types/sinon-chai": "^3.2.2", 31 | "chai": "^4.2.0", 32 | "chai-as-promised": "^7.1.1", 33 | "sinon": "^6", 34 | "sinon-chai": "^3.2.0", 35 | "solium": "^1.1.8", 36 | "ts-node": "^7.0.1", 37 | "tslint": "^5.11.0", 38 | "tslint-config-airbnb": "^5.11.1", 39 | "typescript": "^3.2.2" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /test/helpers/contracts/Cap.sol: -------------------------------------------------------------------------------- 1 | /* solium-disable security/no-inline-assembly */ 2 | pragma solidity ^0.4.24; 3 | 4 | import "./Counter.sol"; 5 | 6 | contract Cap { 7 | Counter private counter; 8 | 9 | constructor (Counter _counter) public { 10 | counter = _counter; 11 | } 12 | 13 | function read() public view returns (uint) { 14 | uint a = counter.read(); 15 | if (a > 10) { 16 | return 10; 17 | } 18 | return a; 19 | } 20 | } -------------------------------------------------------------------------------- /test/helpers/contracts/Counter.sol: -------------------------------------------------------------------------------- 1 | /* solium-disable security/no-inline-assembly */ 2 | pragma solidity ^0.4.24; 3 | 4 | contract Counter { 5 | uint private value; 6 | 7 | function increment() public { 8 | value += 1; 9 | } 10 | 11 | function read() public view returns (uint) { 12 | return value; 13 | } 14 | } -------------------------------------------------------------------------------- /test/helpers/interfaces/Cap.json: -------------------------------------------------------------------------------- 1 | { 2 | "assembly": { 3 | ".code": [ 4 | { 5 | "begin": 100, 6 | "end": 386, 7 | "name": "PUSH", 8 | "value": "80" 9 | }, 10 | { 11 | "begin": 100, 12 | "end": 386, 13 | "name": "PUSH", 14 | "value": "40" 15 | }, 16 | { 17 | "begin": 100, 18 | "end": 386, 19 | "name": "MSTORE" 20 | }, 21 | { 22 | "begin": 149, 23 | "end": 222, 24 | "name": "CALLVALUE" 25 | }, 26 | { 27 | "begin": 8, 28 | "end": 17, 29 | "name": "DUP1" 30 | }, 31 | { 32 | "begin": 5, 33 | "end": 7, 34 | "name": "ISZERO" 35 | }, 36 | { 37 | "begin": 5, 38 | "end": 7, 39 | "name": "PUSH [tag]", 40 | "value": "1" 41 | }, 42 | { 43 | "begin": 5, 44 | "end": 7, 45 | "name": "JUMPI" 46 | }, 47 | { 48 | "begin": 30, 49 | "end": 31, 50 | "name": "PUSH", 51 | "value": "0" 52 | }, 53 | { 54 | "begin": 27, 55 | "end": 28, 56 | "name": "DUP1" 57 | }, 58 | { 59 | "begin": 20, 60 | "end": 32, 61 | "name": "REVERT" 62 | }, 63 | { 64 | "begin": 5, 65 | "end": 7, 66 | "name": "tag", 67 | "value": "1" 68 | }, 69 | { 70 | "begin": 5, 71 | "end": 7, 72 | "name": "JUMPDEST" 73 | }, 74 | { 75 | "begin": 149, 76 | "end": 222, 77 | "name": "POP" 78 | }, 79 | { 80 | "begin": 149, 81 | "end": 222, 82 | "name": "PUSH", 83 | "value": "40" 84 | }, 85 | { 86 | "begin": 149, 87 | "end": 222, 88 | "name": "MLOAD" 89 | }, 90 | { 91 | "begin": 149, 92 | "end": 222, 93 | "name": "PUSH", 94 | "value": "20" 95 | }, 96 | { 97 | "begin": 149, 98 | "end": 222, 99 | "name": "DUP1" 100 | }, 101 | { 102 | "begin": 149, 103 | "end": 222, 104 | "name": "PUSHSIZE" 105 | }, 106 | { 107 | "begin": 149, 108 | "end": 222, 109 | "name": "DUP4" 110 | }, 111 | { 112 | "begin": 149, 113 | "end": 222, 114 | "name": "CODECOPY" 115 | }, 116 | { 117 | "begin": 149, 118 | "end": 222, 119 | "name": "DUP2" 120 | }, 121 | { 122 | "begin": 149, 123 | "end": 222, 124 | "name": "ADD" 125 | }, 126 | { 127 | "begin": 149, 128 | "end": 222, 129 | "name": "PUSH", 130 | "value": "40" 131 | }, 132 | { 133 | "begin": 149, 134 | "end": 222, 135 | "name": "MSTORE" 136 | }, 137 | { 138 | "begin": 149, 139 | "end": 222, 140 | "name": "MLOAD" 141 | }, 142 | { 143 | "begin": 197, 144 | "end": 204, 145 | "name": "PUSH", 146 | "value": "0" 147 | }, 148 | { 149 | "begin": 197, 150 | "end": 215, 151 | "name": "DUP1" 152 | }, 153 | { 154 | "begin": 197, 155 | "end": 215, 156 | "name": "SLOAD" 157 | }, 158 | { 159 | "begin": -1, 160 | "end": -1, 161 | "name": "PUSH", 162 | "value": "1" 163 | }, 164 | { 165 | "begin": -1, 166 | "end": -1, 167 | "name": "PUSH", 168 | "value": "A0" 169 | }, 170 | { 171 | "begin": -1, 172 | "end": -1, 173 | "name": "PUSH", 174 | "value": "2" 175 | }, 176 | { 177 | "begin": -1, 178 | "end": -1, 179 | "name": "EXP" 180 | }, 181 | { 182 | "begin": -1, 183 | "end": -1, 184 | "name": "SUB" 185 | }, 186 | { 187 | "begin": 197, 188 | "end": 215, 189 | "name": "SWAP1" 190 | }, 191 | { 192 | "begin": 197, 193 | "end": 215, 194 | "name": "SWAP3" 195 | }, 196 | { 197 | "begin": 197, 198 | "end": 215, 199 | "name": "AND" 200 | }, 201 | { 202 | "begin": -1, 203 | "end": -1, 204 | "name": "PUSH", 205 | "value": "1" 206 | }, 207 | { 208 | "begin": -1, 209 | "end": -1, 210 | "name": "PUSH", 211 | "value": "A0" 212 | }, 213 | { 214 | "begin": -1, 215 | "end": -1, 216 | "name": "PUSH", 217 | "value": "2" 218 | }, 219 | { 220 | "begin": -1, 221 | "end": -1, 222 | "name": "EXP" 223 | }, 224 | { 225 | "begin": -1, 226 | "end": -1, 227 | "name": "SUB" 228 | }, 229 | { 230 | "begin": -1, 231 | "end": -1, 232 | "name": "NOT" 233 | }, 234 | { 235 | "begin": 197, 236 | "end": 215, 237 | "name": "SWAP1" 238 | }, 239 | { 240 | "begin": 197, 241 | "end": 215, 242 | "name": "SWAP3" 243 | }, 244 | { 245 | "begin": 197, 246 | "end": 215, 247 | "name": "AND" 248 | }, 249 | { 250 | "begin": 197, 251 | "end": 215, 252 | "name": "SWAP2" 253 | }, 254 | { 255 | "begin": 197, 256 | "end": 215, 257 | "name": "SWAP1" 258 | }, 259 | { 260 | "begin": 197, 261 | "end": 215, 262 | "name": "SWAP2" 263 | }, 264 | { 265 | "begin": 197, 266 | "end": 215, 267 | "name": "OR" 268 | }, 269 | { 270 | "begin": 197, 271 | "end": 215, 272 | "name": "SWAP1" 273 | }, 274 | { 275 | "begin": 197, 276 | "end": 215, 277 | "name": "SSTORE" 278 | }, 279 | { 280 | "begin": 100, 281 | "end": 386, 282 | "name": "PUSH #[$]", 283 | "value": "0000000000000000000000000000000000000000000000000000000000000000" 284 | }, 285 | { 286 | "begin": 100, 287 | "end": 386, 288 | "name": "DUP1" 289 | }, 290 | { 291 | "begin": 100, 292 | "end": 386, 293 | "name": "PUSH [$]", 294 | "value": "0000000000000000000000000000000000000000000000000000000000000000" 295 | }, 296 | { 297 | "begin": 100, 298 | "end": 386, 299 | "name": "PUSH", 300 | "value": "0" 301 | }, 302 | { 303 | "begin": 100, 304 | "end": 386, 305 | "name": "CODECOPY" 306 | }, 307 | { 308 | "begin": 100, 309 | "end": 386, 310 | "name": "PUSH", 311 | "value": "0" 312 | }, 313 | { 314 | "begin": 100, 315 | "end": 386, 316 | "name": "RETURN" 317 | } 318 | ], 319 | ".data": { 320 | "0": { 321 | ".auxdata": "a165627a7a72305820ed5b48640649e0ac8c1c23fa80c842deb85b6b9c3f8e20cfa12a8fa94c8f58b30029", 322 | ".code": [ 323 | { 324 | "begin": 100, 325 | "end": 386, 326 | "name": "PUSH", 327 | "value": "80" 328 | }, 329 | { 330 | "begin": 100, 331 | "end": 386, 332 | "name": "PUSH", 333 | "value": "40" 334 | }, 335 | { 336 | "begin": 100, 337 | "end": 386, 338 | "name": "MSTORE" 339 | }, 340 | { 341 | "begin": 100, 342 | "end": 386, 343 | "name": "PUSH", 344 | "value": "4" 345 | }, 346 | { 347 | "begin": 100, 348 | "end": 386, 349 | "name": "CALLDATASIZE" 350 | }, 351 | { 352 | "begin": 100, 353 | "end": 386, 354 | "name": "LT" 355 | }, 356 | { 357 | "begin": 100, 358 | "end": 386, 359 | "name": "PUSH [tag]", 360 | "value": "1" 361 | }, 362 | { 363 | "begin": 100, 364 | "end": 386, 365 | "name": "JUMPI" 366 | }, 367 | { 368 | "begin": 100, 369 | "end": 386, 370 | "name": "PUSH", 371 | "value": "FFFFFFFF" 372 | }, 373 | { 374 | "begin": 100, 375 | "end": 386, 376 | "name": "PUSH", 377 | "value": "100000000000000000000000000000000000000000000000000000000" 378 | }, 379 | { 380 | "begin": 100, 381 | "end": 386, 382 | "name": "PUSH", 383 | "value": "0" 384 | }, 385 | { 386 | "begin": 100, 387 | "end": 386, 388 | "name": "CALLDATALOAD" 389 | }, 390 | { 391 | "begin": 100, 392 | "end": 386, 393 | "name": "DIV" 394 | }, 395 | { 396 | "begin": 100, 397 | "end": 386, 398 | "name": "AND" 399 | }, 400 | { 401 | "begin": 100, 402 | "end": 386, 403 | "name": "PUSH", 404 | "value": "57DE26A4" 405 | }, 406 | { 407 | "begin": 100, 408 | "end": 386, 409 | "name": "DUP2" 410 | }, 411 | { 412 | "begin": 100, 413 | "end": 386, 414 | "name": "EQ" 415 | }, 416 | { 417 | "begin": 100, 418 | "end": 386, 419 | "name": "PUSH [tag]", 420 | "value": "2" 421 | }, 422 | { 423 | "begin": 100, 424 | "end": 386, 425 | "name": "JUMPI" 426 | }, 427 | { 428 | "begin": 100, 429 | "end": 386, 430 | "name": "tag", 431 | "value": "1" 432 | }, 433 | { 434 | "begin": 100, 435 | "end": 386, 436 | "name": "JUMPDEST" 437 | }, 438 | { 439 | "begin": 100, 440 | "end": 386, 441 | "name": "PUSH", 442 | "value": "0" 443 | }, 444 | { 445 | "begin": 100, 446 | "end": 386, 447 | "name": "DUP1" 448 | }, 449 | { 450 | "begin": 100, 451 | "end": 386, 452 | "name": "REVERT" 453 | }, 454 | { 455 | "begin": 228, 456 | "end": 384, 457 | "name": "tag", 458 | "value": "2" 459 | }, 460 | { 461 | "begin": 228, 462 | "end": 384, 463 | "name": "JUMPDEST" 464 | }, 465 | { 466 | "begin": 228, 467 | "end": 384, 468 | "name": "CALLVALUE" 469 | }, 470 | { 471 | "begin": 8, 472 | "end": 17, 473 | "name": "DUP1" 474 | }, 475 | { 476 | "begin": 5, 477 | "end": 7, 478 | "name": "ISZERO" 479 | }, 480 | { 481 | "begin": 5, 482 | "end": 7, 483 | "name": "PUSH [tag]", 484 | "value": "3" 485 | }, 486 | { 487 | "begin": 5, 488 | "end": 7, 489 | "name": "JUMPI" 490 | }, 491 | { 492 | "begin": 30, 493 | "end": 31, 494 | "name": "PUSH", 495 | "value": "0" 496 | }, 497 | { 498 | "begin": 27, 499 | "end": 28, 500 | "name": "DUP1" 501 | }, 502 | { 503 | "begin": 20, 504 | "end": 32, 505 | "name": "REVERT" 506 | }, 507 | { 508 | "begin": 5, 509 | "end": 7, 510 | "name": "tag", 511 | "value": "3" 512 | }, 513 | { 514 | "begin": 5, 515 | "end": 7, 516 | "name": "JUMPDEST" 517 | }, 518 | { 519 | "begin": 228, 520 | "end": 384, 521 | "name": "POP" 522 | }, 523 | { 524 | "begin": 228, 525 | "end": 384, 526 | "name": "PUSH [tag]", 527 | "value": "4" 528 | }, 529 | { 530 | "begin": 228, 531 | "end": 384, 532 | "name": "PUSH [tag]", 533 | "value": "5" 534 | }, 535 | { 536 | "begin": 228, 537 | "end": 384, 538 | "name": "JUMP" 539 | }, 540 | { 541 | "begin": 228, 542 | "end": 384, 543 | "name": "tag", 544 | "value": "4" 545 | }, 546 | { 547 | "begin": 228, 548 | "end": 384, 549 | "name": "JUMPDEST" 550 | }, 551 | { 552 | "begin": 228, 553 | "end": 384, 554 | "name": "PUSH", 555 | "value": "40" 556 | }, 557 | { 558 | "begin": 228, 559 | "end": 384, 560 | "name": "DUP1" 561 | }, 562 | { 563 | "begin": 228, 564 | "end": 384, 565 | "name": "MLOAD" 566 | }, 567 | { 568 | "begin": 228, 569 | "end": 384, 570 | "name": "SWAP2" 571 | }, 572 | { 573 | "begin": 228, 574 | "end": 384, 575 | "name": "DUP3" 576 | }, 577 | { 578 | "begin": 228, 579 | "end": 384, 580 | "name": "MSTORE" 581 | }, 582 | { 583 | "begin": 228, 584 | "end": 384, 585 | "name": "MLOAD" 586 | }, 587 | { 588 | "begin": 228, 589 | "end": 384, 590 | "name": "SWAP1" 591 | }, 592 | { 593 | "begin": 228, 594 | "end": 384, 595 | "name": "DUP2" 596 | }, 597 | { 598 | "begin": 228, 599 | "end": 384, 600 | "name": "SWAP1" 601 | }, 602 | { 603 | "begin": 228, 604 | "end": 384, 605 | "name": "SUB" 606 | }, 607 | { 608 | "begin": 228, 609 | "end": 384, 610 | "name": "PUSH", 611 | "value": "20" 612 | }, 613 | { 614 | "begin": 228, 615 | "end": 384, 616 | "name": "ADD" 617 | }, 618 | { 619 | "begin": 228, 620 | "end": 384, 621 | "name": "SWAP1" 622 | }, 623 | { 624 | "begin": 228, 625 | "end": 384, 626 | "name": "RETURN" 627 | }, 628 | { 629 | "begin": 228, 630 | "end": 384, 631 | "name": "tag", 632 | "value": "5" 633 | }, 634 | { 635 | "begin": 228, 636 | "end": 384, 637 | "name": "JUMPDEST" 638 | }, 639 | { 640 | "begin": 265, 641 | "end": 269, 642 | "name": "PUSH", 643 | "value": "0" 644 | }, 645 | { 646 | "begin": 290, 647 | "end": 297, 648 | "name": "DUP1" 649 | }, 650 | { 651 | "begin": 290, 652 | "end": 297, 653 | "name": "SLOAD" 654 | }, 655 | { 656 | "begin": 290, 657 | "end": 304, 658 | "name": "PUSH", 659 | "value": "40" 660 | }, 661 | { 662 | "begin": 290, 663 | "end": 304, 664 | "name": "DUP1" 665 | }, 666 | { 667 | "begin": 290, 668 | "end": 304, 669 | "name": "MLOAD" 670 | }, 671 | { 672 | "begin": 290, 673 | "end": 304, 674 | "name": "PUSH", 675 | "value": "57DE26A400000000000000000000000000000000000000000000000000000000" 676 | }, 677 | { 678 | "begin": 290, 679 | "end": 304, 680 | "name": "DUP2" 681 | }, 682 | { 683 | "begin": 290, 684 | "end": 304, 685 | "name": "MSTORE" 686 | }, 687 | { 688 | "begin": 290, 689 | "end": 304, 690 | "name": "SWAP1" 691 | }, 692 | { 693 | "begin": 290, 694 | "end": 304, 695 | "name": "MLOAD" 696 | }, 697 | { 698 | "begin": 265, 699 | "end": 269, 700 | "name": "DUP4" 701 | }, 702 | { 703 | "begin": 265, 704 | "end": 269, 705 | "name": "SWAP3" 706 | }, 707 | { 708 | "begin": 290, 709 | "end": 297, 710 | "name": "PUSH", 711 | "value": "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" 712 | }, 713 | { 714 | "begin": 290, 715 | "end": 297, 716 | "name": "AND" 717 | }, 718 | { 719 | "begin": 290, 720 | "end": 297, 721 | "name": "SWAP2" 722 | }, 723 | { 724 | "begin": 290, 725 | "end": 302, 726 | "name": "PUSH", 727 | "value": "57DE26A4" 728 | }, 729 | { 730 | "begin": 290, 731 | "end": 302, 732 | "name": "SWAP2" 733 | }, 734 | { 735 | "begin": 290, 736 | "end": 304, 737 | "name": "PUSH", 738 | "value": "4" 739 | }, 740 | { 741 | "begin": 290, 742 | "end": 304, 743 | "name": "DUP1" 744 | }, 745 | { 746 | "begin": 290, 747 | "end": 304, 748 | "name": "DUP4" 749 | }, 750 | { 751 | "begin": 290, 752 | "end": 304, 753 | "name": "ADD" 754 | }, 755 | { 756 | "begin": 290, 757 | "end": 304, 758 | "name": "SWAP3" 759 | }, 760 | { 761 | "begin": 290, 762 | "end": 304, 763 | "name": "PUSH", 764 | "value": "20" 765 | }, 766 | { 767 | "begin": 290, 768 | "end": 304, 769 | "name": "SWAP3" 770 | }, 771 | { 772 | "begin": 290, 773 | "end": 304, 774 | "name": "SWAP2" 775 | }, 776 | { 777 | "begin": 290, 778 | "end": 304, 779 | "name": "SWAP1" 780 | }, 781 | { 782 | "begin": 290, 783 | "end": 304, 784 | "name": "DUP3" 785 | }, 786 | { 787 | "begin": 290, 788 | "end": 304, 789 | "name": "SWAP1" 790 | }, 791 | { 792 | "begin": 290, 793 | "end": 304, 794 | "name": "SUB" 795 | }, 796 | { 797 | "begin": 290, 798 | "end": 304, 799 | "name": "ADD" 800 | }, 801 | { 802 | "begin": 290, 803 | "end": 304, 804 | "name": "DUP2" 805 | }, 806 | { 807 | "begin": 265, 808 | "end": 269, 809 | "name": "DUP8" 810 | }, 811 | { 812 | "begin": 290, 813 | "end": 297, 814 | "name": "DUP8" 815 | }, 816 | { 817 | "begin": 290, 818 | "end": 304, 819 | "name": "DUP1" 820 | }, 821 | { 822 | "begin": 290, 823 | "end": 304, 824 | "name": "EXTCODESIZE" 825 | }, 826 | { 827 | "begin": 290, 828 | "end": 304, 829 | "name": "ISZERO" 830 | }, 831 | { 832 | "begin": 5, 833 | "end": 7, 834 | "name": "DUP1" 835 | }, 836 | { 837 | "begin": 5, 838 | "end": 7, 839 | "name": "ISZERO" 840 | }, 841 | { 842 | "begin": 5, 843 | "end": 7, 844 | "name": "PUSH [tag]", 845 | "value": "7" 846 | }, 847 | { 848 | "begin": 5, 849 | "end": 7, 850 | "name": "JUMPI" 851 | }, 852 | { 853 | "begin": 30, 854 | "end": 31, 855 | "name": "PUSH", 856 | "value": "0" 857 | }, 858 | { 859 | "begin": 27, 860 | "end": 28, 861 | "name": "DUP1" 862 | }, 863 | { 864 | "begin": 20, 865 | "end": 32, 866 | "name": "REVERT" 867 | }, 868 | { 869 | "begin": 5, 870 | "end": 7, 871 | "name": "tag", 872 | "value": "7" 873 | }, 874 | { 875 | "begin": 5, 876 | "end": 7, 877 | "name": "JUMPDEST" 878 | }, 879 | { 880 | "begin": 290, 881 | "end": 304, 882 | "name": "POP" 883 | }, 884 | { 885 | "begin": 290, 886 | "end": 304, 887 | "name": "GAS" 888 | }, 889 | { 890 | "begin": 290, 891 | "end": 304, 892 | "name": "CALL" 893 | }, 894 | { 895 | "begin": 290, 896 | "end": 304, 897 | "name": "ISZERO" 898 | }, 899 | { 900 | "begin": 8, 901 | "end": 17, 902 | "name": "DUP1" 903 | }, 904 | { 905 | "begin": 5, 906 | "end": 7, 907 | "name": "ISZERO" 908 | }, 909 | { 910 | "begin": 5, 911 | "end": 7, 912 | "name": "PUSH [tag]", 913 | "value": "8" 914 | }, 915 | { 916 | "begin": 5, 917 | "end": 7, 918 | "name": "JUMPI" 919 | }, 920 | { 921 | "begin": 45, 922 | "end": 61, 923 | "name": "RETURNDATASIZE" 924 | }, 925 | { 926 | "begin": 42, 927 | "end": 43, 928 | "name": "PUSH", 929 | "value": "0" 930 | }, 931 | { 932 | "begin": 39, 933 | "end": 40, 934 | "name": "DUP1" 935 | }, 936 | { 937 | "begin": 24, 938 | "end": 62, 939 | "name": "RETURNDATACOPY" 940 | }, 941 | { 942 | "begin": 77, 943 | "end": 93, 944 | "name": "RETURNDATASIZE" 945 | }, 946 | { 947 | "begin": 74, 948 | "end": 75, 949 | "name": "PUSH", 950 | "value": "0" 951 | }, 952 | { 953 | "begin": 67, 954 | "end": 94, 955 | "name": "REVERT" 956 | }, 957 | { 958 | "begin": 5, 959 | "end": 7, 960 | "name": "tag", 961 | "value": "8" 962 | }, 963 | { 964 | "begin": 5, 965 | "end": 7, 966 | "name": "JUMPDEST" 967 | }, 968 | { 969 | "begin": 290, 970 | "end": 304, 971 | "name": "POP" 972 | }, 973 | { 974 | "begin": 290, 975 | "end": 304, 976 | "name": "POP" 977 | }, 978 | { 979 | "begin": 290, 980 | "end": 304, 981 | "name": "POP" 982 | }, 983 | { 984 | "begin": 290, 985 | "end": 304, 986 | "name": "POP" 987 | }, 988 | { 989 | "begin": 290, 990 | "end": 304, 991 | "name": "PUSH", 992 | "value": "40" 993 | }, 994 | { 995 | "begin": 290, 996 | "end": 304, 997 | "name": "MLOAD" 998 | }, 999 | { 1000 | "begin": 290, 1001 | "end": 304, 1002 | "name": "RETURNDATASIZE" 1003 | }, 1004 | { 1005 | "begin": 13, 1006 | "end": 15, 1007 | "name": "PUSH", 1008 | "value": "20" 1009 | }, 1010 | { 1011 | "begin": 8, 1012 | "end": 11, 1013 | "name": "DUP2" 1014 | }, 1015 | { 1016 | "begin": 5, 1017 | "end": 16, 1018 | "name": "LT" 1019 | }, 1020 | { 1021 | "begin": 2, 1022 | "end": 4, 1023 | "name": "ISZERO" 1024 | }, 1025 | { 1026 | "begin": 2, 1027 | "end": 4, 1028 | "name": "PUSH [tag]", 1029 | "value": "9" 1030 | }, 1031 | { 1032 | "begin": 2, 1033 | "end": 4, 1034 | "name": "JUMPI" 1035 | }, 1036 | { 1037 | "begin": 29, 1038 | "end": 30, 1039 | "name": "PUSH", 1040 | "value": "0" 1041 | }, 1042 | { 1043 | "begin": 26, 1044 | "end": 27, 1045 | "name": "DUP1" 1046 | }, 1047 | { 1048 | "begin": 19, 1049 | "end": 31, 1050 | "name": "REVERT" 1051 | }, 1052 | { 1053 | "begin": 2, 1054 | "end": 4, 1055 | "name": "tag", 1056 | "value": "9" 1057 | }, 1058 | { 1059 | "begin": 2, 1060 | "end": 4, 1061 | "name": "JUMPDEST" 1062 | }, 1063 | { 1064 | "begin": -1, 1065 | "end": -1, 1066 | "name": "POP" 1067 | }, 1068 | { 1069 | "begin": 290, 1070 | "end": 304, 1071 | "name": "MLOAD" 1072 | }, 1073 | { 1074 | "begin": 290, 1075 | "end": 304, 1076 | "name": "SWAP1" 1077 | }, 1078 | { 1079 | "begin": -1, 1080 | "end": -1, 1081 | "name": "POP" 1082 | }, 1083 | { 1084 | "begin": 322, 1085 | "end": 324, 1086 | "name": "PUSH", 1087 | "value": "A" 1088 | }, 1089 | { 1090 | "begin": 318, 1091 | "end": 324, 1092 | "name": "DUP2" 1093 | }, 1094 | { 1095 | "begin": 318, 1096 | "end": 324, 1097 | "name": "GT" 1098 | }, 1099 | { 1100 | "begin": 314, 1101 | "end": 360, 1102 | "name": "ISZERO" 1103 | }, 1104 | { 1105 | "begin": 314, 1106 | "end": 360, 1107 | "name": "PUSH [tag]", 1108 | "value": "10" 1109 | }, 1110 | { 1111 | "begin": 314, 1112 | "end": 360, 1113 | "name": "JUMPI" 1114 | }, 1115 | { 1116 | "begin": 347, 1117 | "end": 349, 1118 | "name": "PUSH", 1119 | "value": "A" 1120 | }, 1121 | { 1122 | "begin": 340, 1123 | "end": 349, 1124 | "name": "SWAP2" 1125 | }, 1126 | { 1127 | "begin": 340, 1128 | "end": 349, 1129 | "name": "POP" 1130 | }, 1131 | { 1132 | "begin": 340, 1133 | "end": 349, 1134 | "name": "PUSH [tag]", 1135 | "value": "6" 1136 | }, 1137 | { 1138 | "begin": 340, 1139 | "end": 349, 1140 | "name": "JUMP" 1141 | }, 1142 | { 1143 | "begin": 314, 1144 | "end": 360, 1145 | "name": "tag", 1146 | "value": "10" 1147 | }, 1148 | { 1149 | "begin": 314, 1150 | "end": 360, 1151 | "name": "JUMPDEST" 1152 | }, 1153 | { 1154 | "begin": 376, 1155 | "end": 377, 1156 | "name": "DUP1" 1157 | }, 1158 | { 1159 | "begin": 369, 1160 | "end": 377, 1161 | "name": "SWAP2" 1162 | }, 1163 | { 1164 | "begin": 369, 1165 | "end": 377, 1166 | "name": "POP" 1167 | }, 1168 | { 1169 | "begin": 228, 1170 | "end": 384, 1171 | "name": "tag", 1172 | "value": "6" 1173 | }, 1174 | { 1175 | "begin": 228, 1176 | "end": 384, 1177 | "name": "JUMPDEST" 1178 | }, 1179 | { 1180 | "begin": 228, 1181 | "end": 384, 1182 | "name": "POP" 1183 | }, 1184 | { 1185 | "begin": 228, 1186 | "end": 384, 1187 | "name": "SWAP1" 1188 | }, 1189 | { 1190 | "begin": 228, 1191 | "end": 384, 1192 | "name": "JUMP", 1193 | "value": "[out]" 1194 | } 1195 | ] 1196 | } 1197 | } 1198 | }, 1199 | "bytecode": "608060405234801561001057600080fd5b5060405160208061019e833981016040525160008054600160a060020a03909216600160a060020a031990921691909117905561014c806100526000396000f3006080604052600436106100405763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166357de26a48114610045575b600080fd5b34801561005157600080fd5b5061005a61006c565b60408051918252519081900360200190f35b60008054604080517f57de26a40000000000000000000000000000000000000000000000000000000081529051839273ffffffffffffffffffffffffffffffffffffffff16916357de26a491600480830192602092919082900301818787803b1580156100d857600080fd5b505af11580156100ec573d6000803e3d6000fd5b505050506040513d602081101561010257600080fd5b50519050600a81111561011857600a915061011c565b8091505b50905600a165627a7a72305820ed5b48640649e0ac8c1c23fa80c842deb85b6b9c3f8e20cfa12a8fa94c8f58b30029", 1200 | "functionHashes": { 1201 | "read()": "57de26a4" 1202 | }, 1203 | "gasEstimates": { 1204 | "creation": [ 1205 | 20542, 1206 | 66400 1207 | ], 1208 | "external": { 1209 | "read()": null 1210 | }, 1211 | "internal": {} 1212 | }, 1213 | "interface": "[{\"constant\":true,\"inputs\":[],\"name\":\"read\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"_counter\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"}]", 1214 | "metadata": "{\"compiler\":{\"version\":\"0.4.25+commit.59dbf8f1\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"constant\":true,\"inputs\":[],\"name\":\"read\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"_counter\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"}],\"devdoc\":{\"methods\":{}},\"userdoc\":{\"methods\":{}}},\"settings\":{\"compilationTarget\":{\"test/helpers/contracts/Cap.sol\":\"Cap\"},\"evmVersion\":\"byzantium\",\"libraries\":{},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"test/helpers/contracts/Cap.sol\":{\"keccak256\":\"0xb74022286547978464c3f15bf6744692ef54a136d8438a0581551ae1e3eebefd\",\"urls\":[\"bzzr://494b71a5e26c3cee6c37141a2d73b335e593535f4303c1093349ae4819a7703b\"]},\"test/helpers/contracts/Counter.sol\":{\"keccak256\":\"0xd405ecc088a6401ecdafb1b038f56388e00813d6d9fd2903b2ac29f11b219130\",\"urls\":[\"bzzr://0556211efc4694d6123601f5ccd38d11d4afa3339a156f4bda0ef0e42d697862\"]}},\"version\":1}", 1215 | "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x40 MLOAD PUSH1 0x20 DUP1 PUSH2 0x19E DUP4 CODECOPY DUP2 ADD PUSH1 0x40 MSTORE MLOAD PUSH1 0x0 DUP1 SLOAD PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB SWAP1 SWAP3 AND PUSH1 0x1 PUSH1 0xA0 PUSH1 0x2 EXP SUB NOT SWAP1 SWAP3 AND SWAP2 SWAP1 SWAP2 OR SWAP1 SSTORE PUSH2 0x14C DUP1 PUSH2 0x52 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN STOP PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x4 CALLDATASIZE LT PUSH2 0x40 JUMPI PUSH4 0xFFFFFFFF PUSH29 0x100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 CALLDATALOAD DIV AND PUSH4 0x57DE26A4 DUP2 EQ PUSH2 0x45 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST CALLVALUE DUP1 ISZERO PUSH2 0x51 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x5A PUSH2 0x6C JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD SWAP2 DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH1 0x40 DUP1 MLOAD PUSH32 0x57DE26A400000000000000000000000000000000000000000000000000000000 DUP2 MSTORE SWAP1 MLOAD DUP4 SWAP3 PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND SWAP2 PUSH4 0x57DE26A4 SWAP2 PUSH1 0x4 DUP1 DUP4 ADD SWAP3 PUSH1 0x20 SWAP3 SWAP2 SWAP1 DUP3 SWAP1 SUB ADD DUP2 DUP8 DUP8 DUP1 EXTCODESIZE ISZERO DUP1 ISZERO PUSH2 0xD8 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP GAS CALL ISZERO DUP1 ISZERO PUSH2 0xEC JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP POP POP PUSH1 0x40 MLOAD RETURNDATASIZE PUSH1 0x20 DUP2 LT ISZERO PUSH2 0x102 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP MLOAD SWAP1 POP PUSH1 0xA DUP2 GT ISZERO PUSH2 0x118 JUMPI PUSH1 0xA SWAP2 POP PUSH2 0x11C JUMP JUMPDEST DUP1 SWAP2 POP JUMPDEST POP SWAP1 JUMP STOP LOG1 PUSH6 0x627A7A723058 KECCAK256 0xed JUMPDEST 0x48 PUSH5 0x649E0AC8C SHR 0x23 STATICCALL DUP1 0xc8 TIMESTAMP 0xde 0xb8 JUMPDEST PUSH12 0x9C3F8E20CFA12A8FA94C8F58 0xb3 STOP 0x29 ", 1216 | "runtimeBytecode": "6080604052600436106100405763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166357de26a48114610045575b600080fd5b34801561005157600080fd5b5061005a61006c565b60408051918252519081900360200190f35b60008054604080517f57de26a40000000000000000000000000000000000000000000000000000000081529051839273ffffffffffffffffffffffffffffffffffffffff16916357de26a491600480830192602092919082900301818787803b1580156100d857600080fd5b505af11580156100ec573d6000803e3d6000fd5b505050506040513d602081101561010257600080fd5b50519050600a81111561011857600a915061011c565b8091505b50905600a165627a7a72305820ed5b48640649e0ac8c1c23fa80c842deb85b6b9c3f8e20cfa12a8fa94c8f58b30029", 1217 | "srcmap": "100:286:0:-;;;149:73;8:9:-1;5:2;;;30:1;27;20:12;5:2;149:73:0;;;;;;;;;;;;;197:7;:18;;-1:-1:-1;;;;;197:18:0;;;-1:-1:-1;;;;;;197:18:0;;;;;;;;;100:286;;;;;;", 1218 | "srcmapRuntime": "100:286:0:-;;;;;;;;;;;;;;;;;;;;;;;228:156;;8:9:-1;5:2;;;30:1;27;20:12;5:2;228:156:0;;;;;;;;;;;;;;;;;;;;;265:4;290:7;;:14;;;;;;;;265:4;;290:7;;;:12;;:14;;;;;;;;;;;;;;265:4;290:7;:14;;;5:2:-1;;;;30:1;27;20:12;5:2;290:14:0;;;;8:9:-1;5:2;;;45:16;42:1;39;24:38;77:16;74:1;67:27;5:2;290:14:0;;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;-1:-1;290:14:0;;-1:-1:-1;322:2:0;318:6;;314:46;;;347:2;340:9;;;;314:46;376:1;369:8;;228:156;;;:::o" 1219 | } -------------------------------------------------------------------------------- /test/helpers/interfaces/Counter.json: -------------------------------------------------------------------------------- 1 | { 2 | "assembly": { 3 | ".code": [ 4 | { 5 | "begin": 75, 6 | "end": 258, 7 | "name": "PUSH", 8 | "value": "80" 9 | }, 10 | { 11 | "begin": 75, 12 | "end": 258, 13 | "name": "PUSH", 14 | "value": "40" 15 | }, 16 | { 17 | "begin": 75, 18 | "end": 258, 19 | "name": "MSTORE" 20 | }, 21 | { 22 | "begin": 75, 23 | "end": 258, 24 | "name": "CALLVALUE" 25 | }, 26 | { 27 | "begin": 8, 28 | "end": 17, 29 | "name": "DUP1" 30 | }, 31 | { 32 | "begin": 5, 33 | "end": 7, 34 | "name": "ISZERO" 35 | }, 36 | { 37 | "begin": 5, 38 | "end": 7, 39 | "name": "PUSH [tag]", 40 | "value": "1" 41 | }, 42 | { 43 | "begin": 5, 44 | "end": 7, 45 | "name": "JUMPI" 46 | }, 47 | { 48 | "begin": 30, 49 | "end": 31, 50 | "name": "PUSH", 51 | "value": "0" 52 | }, 53 | { 54 | "begin": 27, 55 | "end": 28, 56 | "name": "DUP1" 57 | }, 58 | { 59 | "begin": 20, 60 | "end": 32, 61 | "name": "REVERT" 62 | }, 63 | { 64 | "begin": 5, 65 | "end": 7, 66 | "name": "tag", 67 | "value": "1" 68 | }, 69 | { 70 | "begin": 5, 71 | "end": 7, 72 | "name": "JUMPDEST" 73 | }, 74 | { 75 | "begin": 75, 76 | "end": 258, 77 | "name": "POP" 78 | }, 79 | { 80 | "begin": 75, 81 | "end": 258, 82 | "name": "PUSH #[$]", 83 | "value": "0000000000000000000000000000000000000000000000000000000000000000" 84 | }, 85 | { 86 | "begin": 75, 87 | "end": 258, 88 | "name": "DUP1" 89 | }, 90 | { 91 | "begin": 75, 92 | "end": 258, 93 | "name": "PUSH [$]", 94 | "value": "0000000000000000000000000000000000000000000000000000000000000000" 95 | }, 96 | { 97 | "begin": 75, 98 | "end": 258, 99 | "name": "PUSH", 100 | "value": "0" 101 | }, 102 | { 103 | "begin": 75, 104 | "end": 258, 105 | "name": "CODECOPY" 106 | }, 107 | { 108 | "begin": 75, 109 | "end": 258, 110 | "name": "PUSH", 111 | "value": "0" 112 | }, 113 | { 114 | "begin": 75, 115 | "end": 258, 116 | "name": "RETURN" 117 | } 118 | ], 119 | ".data": { 120 | "0": { 121 | ".auxdata": "a165627a7a723058206863fba086f11735a0330d4a2136e2432ba41033ca7b2d5af6cbe42e8ffa34bd0029", 122 | ".code": [ 123 | { 124 | "begin": 75, 125 | "end": 258, 126 | "name": "PUSH", 127 | "value": "80" 128 | }, 129 | { 130 | "begin": 75, 131 | "end": 258, 132 | "name": "PUSH", 133 | "value": "40" 134 | }, 135 | { 136 | "begin": 75, 137 | "end": 258, 138 | "name": "MSTORE" 139 | }, 140 | { 141 | "begin": 75, 142 | "end": 258, 143 | "name": "PUSH", 144 | "value": "4" 145 | }, 146 | { 147 | "begin": 75, 148 | "end": 258, 149 | "name": "CALLDATASIZE" 150 | }, 151 | { 152 | "begin": 75, 153 | "end": 258, 154 | "name": "LT" 155 | }, 156 | { 157 | "begin": 75, 158 | "end": 258, 159 | "name": "PUSH [tag]", 160 | "value": "1" 161 | }, 162 | { 163 | "begin": 75, 164 | "end": 258, 165 | "name": "JUMPI" 166 | }, 167 | { 168 | "begin": 75, 169 | "end": 258, 170 | "name": "PUSH", 171 | "value": "FFFFFFFF" 172 | }, 173 | { 174 | "begin": 75, 175 | "end": 258, 176 | "name": "PUSH", 177 | "value": "100000000000000000000000000000000000000000000000000000000" 178 | }, 179 | { 180 | "begin": 75, 181 | "end": 258, 182 | "name": "PUSH", 183 | "value": "0" 184 | }, 185 | { 186 | "begin": 75, 187 | "end": 258, 188 | "name": "CALLDATALOAD" 189 | }, 190 | { 191 | "begin": 75, 192 | "end": 258, 193 | "name": "DIV" 194 | }, 195 | { 196 | "begin": 75, 197 | "end": 258, 198 | "name": "AND" 199 | }, 200 | { 201 | "begin": 75, 202 | "end": 258, 203 | "name": "PUSH", 204 | "value": "57DE26A4" 205 | }, 206 | { 207 | "begin": 75, 208 | "end": 258, 209 | "name": "DUP2" 210 | }, 211 | { 212 | "begin": 75, 213 | "end": 258, 214 | "name": "EQ" 215 | }, 216 | { 217 | "begin": 75, 218 | "end": 258, 219 | "name": "PUSH [tag]", 220 | "value": "2" 221 | }, 222 | { 223 | "begin": 75, 224 | "end": 258, 225 | "name": "JUMPI" 226 | }, 227 | { 228 | "begin": 75, 229 | "end": 258, 230 | "name": "DUP1" 231 | }, 232 | { 233 | "begin": 75, 234 | "end": 258, 235 | "name": "PUSH", 236 | "value": "D09DE08A" 237 | }, 238 | { 239 | "begin": 75, 240 | "end": 258, 241 | "name": "EQ" 242 | }, 243 | { 244 | "begin": 75, 245 | "end": 258, 246 | "name": "PUSH [tag]", 247 | "value": "3" 248 | }, 249 | { 250 | "begin": 75, 251 | "end": 258, 252 | "name": "JUMPI" 253 | }, 254 | { 255 | "begin": 75, 256 | "end": 258, 257 | "name": "tag", 258 | "value": "1" 259 | }, 260 | { 261 | "begin": 75, 262 | "end": 258, 263 | "name": "JUMPDEST" 264 | }, 265 | { 266 | "begin": 75, 267 | "end": 258, 268 | "name": "PUSH", 269 | "value": "0" 270 | }, 271 | { 272 | "begin": 75, 273 | "end": 258, 274 | "name": "DUP1" 275 | }, 276 | { 277 | "begin": 75, 278 | "end": 258, 279 | "name": "REVERT" 280 | }, 281 | { 282 | "begin": 184, 283 | "end": 256, 284 | "name": "tag", 285 | "value": "2" 286 | }, 287 | { 288 | "begin": 184, 289 | "end": 256, 290 | "name": "JUMPDEST" 291 | }, 292 | { 293 | "begin": 184, 294 | "end": 256, 295 | "name": "CALLVALUE" 296 | }, 297 | { 298 | "begin": 8, 299 | "end": 17, 300 | "name": "DUP1" 301 | }, 302 | { 303 | "begin": 5, 304 | "end": 7, 305 | "name": "ISZERO" 306 | }, 307 | { 308 | "begin": 5, 309 | "end": 7, 310 | "name": "PUSH [tag]", 311 | "value": "4" 312 | }, 313 | { 314 | "begin": 5, 315 | "end": 7, 316 | "name": "JUMPI" 317 | }, 318 | { 319 | "begin": 30, 320 | "end": 31, 321 | "name": "PUSH", 322 | "value": "0" 323 | }, 324 | { 325 | "begin": 27, 326 | "end": 28, 327 | "name": "DUP1" 328 | }, 329 | { 330 | "begin": 20, 331 | "end": 32, 332 | "name": "REVERT" 333 | }, 334 | { 335 | "begin": 5, 336 | "end": 7, 337 | "name": "tag", 338 | "value": "4" 339 | }, 340 | { 341 | "begin": 5, 342 | "end": 7, 343 | "name": "JUMPDEST" 344 | }, 345 | { 346 | "begin": 184, 347 | "end": 256, 348 | "name": "POP" 349 | }, 350 | { 351 | "begin": 184, 352 | "end": 256, 353 | "name": "PUSH [tag]", 354 | "value": "5" 355 | }, 356 | { 357 | "begin": 184, 358 | "end": 256, 359 | "name": "PUSH [tag]", 360 | "value": "6" 361 | }, 362 | { 363 | "begin": 184, 364 | "end": 256, 365 | "name": "JUMP" 366 | }, 367 | { 368 | "begin": 184, 369 | "end": 256, 370 | "name": "tag", 371 | "value": "5" 372 | }, 373 | { 374 | "begin": 184, 375 | "end": 256, 376 | "name": "JUMPDEST" 377 | }, 378 | { 379 | "begin": 184, 380 | "end": 256, 381 | "name": "PUSH", 382 | "value": "40" 383 | }, 384 | { 385 | "begin": 184, 386 | "end": 256, 387 | "name": "DUP1" 388 | }, 389 | { 390 | "begin": 184, 391 | "end": 256, 392 | "name": "MLOAD" 393 | }, 394 | { 395 | "begin": 184, 396 | "end": 256, 397 | "name": "SWAP2" 398 | }, 399 | { 400 | "begin": 184, 401 | "end": 256, 402 | "name": "DUP3" 403 | }, 404 | { 405 | "begin": 184, 406 | "end": 256, 407 | "name": "MSTORE" 408 | }, 409 | { 410 | "begin": 184, 411 | "end": 256, 412 | "name": "MLOAD" 413 | }, 414 | { 415 | "begin": 184, 416 | "end": 256, 417 | "name": "SWAP1" 418 | }, 419 | { 420 | "begin": 184, 421 | "end": 256, 422 | "name": "DUP2" 423 | }, 424 | { 425 | "begin": 184, 426 | "end": 256, 427 | "name": "SWAP1" 428 | }, 429 | { 430 | "begin": 184, 431 | "end": 256, 432 | "name": "SUB" 433 | }, 434 | { 435 | "begin": 184, 436 | "end": 256, 437 | "name": "PUSH", 438 | "value": "20" 439 | }, 440 | { 441 | "begin": 184, 442 | "end": 256, 443 | "name": "ADD" 444 | }, 445 | { 446 | "begin": 184, 447 | "end": 256, 448 | "name": "SWAP1" 449 | }, 450 | { 451 | "begin": 184, 452 | "end": 256, 453 | "name": "RETURN" 454 | }, 455 | { 456 | "begin": 123, 457 | "end": 178, 458 | "name": "tag", 459 | "value": "3" 460 | }, 461 | { 462 | "begin": 123, 463 | "end": 178, 464 | "name": "JUMPDEST" 465 | }, 466 | { 467 | "begin": 123, 468 | "end": 178, 469 | "name": "CALLVALUE" 470 | }, 471 | { 472 | "begin": 8, 473 | "end": 17, 474 | "name": "DUP1" 475 | }, 476 | { 477 | "begin": 5, 478 | "end": 7, 479 | "name": "ISZERO" 480 | }, 481 | { 482 | "begin": 5, 483 | "end": 7, 484 | "name": "PUSH [tag]", 485 | "value": "7" 486 | }, 487 | { 488 | "begin": 5, 489 | "end": 7, 490 | "name": "JUMPI" 491 | }, 492 | { 493 | "begin": 30, 494 | "end": 31, 495 | "name": "PUSH", 496 | "value": "0" 497 | }, 498 | { 499 | "begin": 27, 500 | "end": 28, 501 | "name": "DUP1" 502 | }, 503 | { 504 | "begin": 20, 505 | "end": 32, 506 | "name": "REVERT" 507 | }, 508 | { 509 | "begin": 5, 510 | "end": 7, 511 | "name": "tag", 512 | "value": "7" 513 | }, 514 | { 515 | "begin": 5, 516 | "end": 7, 517 | "name": "JUMPDEST" 518 | }, 519 | { 520 | "begin": 123, 521 | "end": 178, 522 | "name": "POP" 523 | }, 524 | { 525 | "begin": 123, 526 | "end": 178, 527 | "name": "PUSH [tag]", 528 | "value": "8" 529 | }, 530 | { 531 | "begin": 123, 532 | "end": 178, 533 | "name": "PUSH [tag]", 534 | "value": "9" 535 | }, 536 | { 537 | "begin": 123, 538 | "end": 178, 539 | "name": "JUMP" 540 | }, 541 | { 542 | "begin": 123, 543 | "end": 178, 544 | "name": "tag", 545 | "value": "8" 546 | }, 547 | { 548 | "begin": 123, 549 | "end": 178, 550 | "name": "JUMPDEST" 551 | }, 552 | { 553 | "begin": 123, 554 | "end": 178, 555 | "name": "STOP" 556 | }, 557 | { 558 | "begin": 184, 559 | "end": 256, 560 | "name": "tag", 561 | "value": "6" 562 | }, 563 | { 564 | "begin": 184, 565 | "end": 256, 566 | "name": "JUMPDEST" 567 | }, 568 | { 569 | "begin": 221, 570 | "end": 225, 571 | "name": "PUSH", 572 | "value": "0" 573 | }, 574 | { 575 | "begin": 244, 576 | "end": 249, 577 | "name": "SLOAD" 578 | }, 579 | { 580 | "begin": 184, 581 | "end": 256, 582 | "name": "SWAP1" 583 | }, 584 | { 585 | "begin": 184, 586 | "end": 256, 587 | "name": "JUMP", 588 | "value": "[out]" 589 | }, 590 | { 591 | "begin": 123, 592 | "end": 178, 593 | "name": "tag", 594 | "value": "9" 595 | }, 596 | { 597 | "begin": 123, 598 | "end": 178, 599 | "name": "JUMPDEST" 600 | }, 601 | { 602 | "begin": 161, 603 | "end": 166, 604 | "name": "PUSH", 605 | "value": "0" 606 | }, 607 | { 608 | "begin": 161, 609 | "end": 171, 610 | "name": "DUP1" 611 | }, 612 | { 613 | "begin": 161, 614 | "end": 171, 615 | "name": "SLOAD" 616 | }, 617 | { 618 | "begin": 170, 619 | "end": 171, 620 | "name": "PUSH", 621 | "value": "1" 622 | }, 623 | { 624 | "begin": 161, 625 | "end": 171, 626 | "name": "ADD" 627 | }, 628 | { 629 | "begin": 161, 630 | "end": 171, 631 | "name": "SWAP1" 632 | }, 633 | { 634 | "begin": 161, 635 | "end": 171, 636 | "name": "SSTORE" 637 | }, 638 | { 639 | "begin": 123, 640 | "end": 178, 641 | "name": "JUMP", 642 | "value": "[out]" 643 | } 644 | ] 645 | } 646 | } 647 | }, 648 | "bytecode": "608060405234801561001057600080fd5b5060c28061001f6000396000f30060806040526004361060485763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166357de26a48114604d578063d09de08a146071575b600080fd5b348015605857600080fd5b50605f6085565b60408051918252519081900360200190f35b348015607c57600080fd5b506083608b565b005b60005490565b6000805460010190555600a165627a7a723058206863fba086f11735a0330d4a2136e2432ba41033ca7b2d5af6cbe42e8ffa34bd0029", 649 | "functionHashes": { 650 | "increment()": "d09de08a", 651 | "read()": "57de26a4" 652 | }, 653 | "gasEstimates": { 654 | "creation": [ 655 | 93, 656 | 38800 657 | ], 658 | "external": { 659 | "increment()": 20367, 660 | "read()": 384 661 | }, 662 | "internal": {} 663 | }, 664 | "interface": "[{\"constant\":true,\"inputs\":[],\"name\":\"read\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"increment\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", 665 | "metadata": "{\"compiler\":{\"version\":\"0.4.25+commit.59dbf8f1\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"constant\":true,\"inputs\":[],\"name\":\"read\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"increment\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"methods\":{}},\"userdoc\":{\"methods\":{}}},\"settings\":{\"compilationTarget\":{\"test/helpers/contracts/Counter.sol\":\"Counter\"},\"evmVersion\":\"byzantium\",\"libraries\":{},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"test/helpers/contracts/Counter.sol\":{\"keccak256\":\"0xd405ecc088a6401ecdafb1b038f56388e00813d6d9fd2903b2ac29f11b219130\",\"urls\":[\"bzzr://0556211efc4694d6123601f5ccd38d11d4afa3339a156f4bda0ef0e42d697862\"]}},\"version\":1}", 666 | "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0xC2 DUP1 PUSH2 0x1F PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN STOP PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x4 CALLDATASIZE LT PUSH1 0x48 JUMPI PUSH4 0xFFFFFFFF PUSH29 0x100000000000000000000000000000000000000000000000000000000 PUSH1 0x0 CALLDATALOAD DIV AND PUSH4 0x57DE26A4 DUP2 EQ PUSH1 0x4D JUMPI DUP1 PUSH4 0xD09DE08A EQ PUSH1 0x71 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST CALLVALUE DUP1 ISZERO PUSH1 0x58 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x5F PUSH1 0x85 JUMP JUMPDEST PUSH1 0x40 DUP1 MLOAD SWAP2 DUP3 MSTORE MLOAD SWAP1 DUP2 SWAP1 SUB PUSH1 0x20 ADD SWAP1 RETURN JUMPDEST CALLVALUE DUP1 ISZERO PUSH1 0x7C JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x83 PUSH1 0x8B JUMP JUMPDEST STOP JUMPDEST PUSH1 0x0 SLOAD SWAP1 JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD PUSH1 0x1 ADD SWAP1 SSTORE JUMP STOP LOG1 PUSH6 0x627A7A723058 KECCAK256 PUSH9 0x63FBA086F11735A033 0xd 0x4a 0x21 CALLDATASIZE 0xe2 NUMBER 0x2b LOG4 LT CALLER 0xca PUSH28 0x2D5AF6CBE42E8FFA34BD002900000000000000000000000000000000 ", 667 | "runtimeBytecode": "60806040526004361060485763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166357de26a48114604d578063d09de08a146071575b600080fd5b348015605857600080fd5b50605f6085565b60408051918252519081900360200190f35b348015607c57600080fd5b506083608b565b005b60005490565b6000805460010190555600a165627a7a723058206863fba086f11735a0330d4a2136e2432ba41033ca7b2d5af6cbe42e8ffa34bd0029", 668 | "srcmap": "75:183:1:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;75:183:1;;;;;;;", 669 | "srcmapRuntime": "75:183:1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;184:72;;8:9:-1;5:2;;;30:1;27;20:12;5:2;184:72:1;;;;;;;;;;;;;;;;;;;;123:55;;8:9:-1;5:2;;;30:1;27;20:12;5:2;123:55:1;;;;;;184:72;221:4;244:5;184:72;:::o;123:55::-;161:5;:10;;170:1;161:10;;;123:55::o" 670 | } -------------------------------------------------------------------------------- /test/integrations/direct.ts: -------------------------------------------------------------------------------- 1 | import { use, expect } from 'chai'; 2 | import chaiAsPromised from 'chai-as-promised'; 3 | import { createMockProvider, getWallets } from 'ethereum-waffle'; 4 | 5 | import Doppelganger from '../../lib'; 6 | import Counter from '../helpers/interfaces/Counter.json'; 7 | 8 | use(chaiAsPromised); 9 | 10 | describe('Doppelganger - Integration (called directly)', () => { 11 | const provider = createMockProvider(); 12 | const [wallet] = getWallets(provider); 13 | 14 | it('mocking mechanism works', async () => { 15 | const doppelganger = new Doppelganger(Counter.interface); 16 | await doppelganger.deploy(wallet); 17 | await doppelganger.read.returns(45291); 18 | const contract = doppelganger.pretendedContract(wallet); 19 | 20 | const ret = await expect(contract.read()).to.be.eventually.fulfilled; 21 | expect(ret.toNumber()).to.be.equal(45291); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /test/integrations/proxied.ts: -------------------------------------------------------------------------------- 1 | import { use, expect } from 'chai'; 2 | import chaiAsPromised from 'chai-as-promised'; 3 | import { createMockProvider, deployContract, getWallets } from 'ethereum-waffle'; 4 | 5 | import Doppelganger from '../../lib'; 6 | import Counter from '../helpers/interfaces/Counter.json'; 7 | import Cap from '../helpers/interfaces/Cap.json'; 8 | 9 | use(chaiAsPromised); 10 | 11 | describe('Doppelganger - Integration (called by other contract)', () => { 12 | const provider = createMockProvider(); 13 | const [wallet] = getWallets(provider); 14 | 15 | it('mocking mechanism works', async () => { 16 | const doppelganger = new Doppelganger(Counter.interface); 17 | await doppelganger.deploy(wallet); 18 | const capContract = await deployContract( 19 | wallet, 20 | { 21 | abi: Cap.interface, 22 | evm: { 23 | bytecode: { 24 | object: Cap.bytecode, 25 | }, 26 | }, 27 | }, 28 | [doppelganger.address], 29 | ); 30 | 31 | await doppelganger.read.returns(5); 32 | const ret1 = await expect(capContract.read()).to.be.eventually.fulfilled; 33 | expect(ret1.toNumber()).to.be.equal(5); 34 | 35 | await doppelganger.read.returns(12); 36 | const ret2 = await expect(capContract.read()).to.be.eventually.fulfilled; 37 | expect(ret2.toNumber()).to.be.equal(10); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /test/mocha.opts: -------------------------------------------------------------------------------- 1 | --require ts-node/register 2 | --timeout 10000 3 | -------------------------------------------------------------------------------- /test/units/doppelganger_contract.ts: -------------------------------------------------------------------------------- 1 | import { use, expect } from 'chai'; 2 | import chaiAsPromised from 'chai-as-promised'; 3 | import { createMockProvider, getWallets, deployContract } from 'ethereum-waffle'; 4 | import { Contract, utils } from 'ethers'; 5 | 6 | import DoppelgangerContract from '../../lib/Doppelganger.json'; 7 | import Counter from '../helpers/interfaces/Counter.json'; 8 | 9 | use(chaiAsPromised); 10 | 11 | describe('Doppelganger - Contract', () => { 12 | const provider = createMockProvider(); 13 | const [wallet] = getWallets(provider); 14 | let contract: Contract; 15 | 16 | beforeEach(async () => { 17 | contract = await deployContract(wallet, DoppelgangerContract); 18 | }); 19 | 20 | describe('mocking mechanism', () => { 21 | let pretender: Contract; 22 | const readSignature = '0x57de26a4'; 23 | 24 | beforeEach(async () => { 25 | pretender = new Contract(contract.address, Counter.interface, wallet); 26 | }); 27 | 28 | it('returns preprogrammed return values for mocked functions', async () => { 29 | const value = '0x1000000000000000000000000000000000000000000000000000000000004234'; 30 | await contract.mockReturns(readSignature, value); 31 | const ret = await expect(pretender.read()).to.eventually.be.fulfilled; 32 | expect(utils.hexlify(ret)).to.equal(value); 33 | }); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /test/units/doppelganger_tool.ts: -------------------------------------------------------------------------------- 1 | import { use, expect } from 'chai'; 2 | import chaiAsPromised from 'chai-as-promised'; 3 | import sinon from 'sinon'; 4 | import sinonChai from 'sinon-chai'; 5 | import { Contract } from 'ethers'; 6 | 7 | import Doppelganger from '../../lib'; 8 | import Counter from '../helpers/interfaces/Counter.json'; 9 | 10 | use(chaiAsPromised); 11 | use(sinonChai); 12 | 13 | describe('Doppelganger - Tool', () => { 14 | let doppelganger: Doppelganger; 15 | let contractStub: Contract; 16 | 17 | beforeEach(async () => { 18 | contractStub = { 19 | mockReturns: sinon.stub(), 20 | address: '0xABCD', 21 | }; 22 | doppelganger = new Doppelganger(JSON.parse(Counter.interface), contractStub); 23 | }); 24 | 25 | it('address property proxies the contract instance address', () => { 26 | expect(doppelganger.address).to.equal('0xABCD'); 27 | }); 28 | 29 | describe('behavior controls', () => { 30 | it('are created for all abi defined functions', () => { 31 | expect(doppelganger.read).to.be.an('object'); 32 | }); 33 | 34 | it('each containing a returns method', () => { 35 | expect(doppelganger.read.returns).to.be.a('function'); 36 | }); 37 | 38 | describe('setter method', () => { 39 | it('calls the mockReturns method of the mock contract', async () => { 40 | await expect(doppelganger.read.returns(1234)).to.eventually.be.fulfilled; 41 | expect(contractStub.mockReturns).to.have.been.calledOnceWith( 42 | '0x57de26a4', 43 | '0x00000000000000000000000000000000000000000000000000000000000004d2', 44 | ); 45 | }); 46 | }); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "dist", 4 | "lib": [ 5 | "es2015" 6 | ], 7 | "target": "es5", 8 | "strict": true, 9 | "declaration": true, 10 | "moduleResolution": "node", 11 | "resolveJsonModule": true, 12 | "esModuleInterop": true, 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "error", 3 | "extends": [ 4 | "tslint-config-airbnb" 5 | ], 6 | "jsRules": {}, 7 | "rules": { 8 | "variable-name": [true, "check-format", "allow-pascal-case"], 9 | "import-name": false 10 | }, 11 | "rulesDirectory": [] 12 | } -------------------------------------------------------------------------------- /waffle_lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "sourcesPath": "./contracts", 3 | "targetPath": "./lib", 4 | "solcVersion": "v0.4.24+commit.e67f0147", 5 | "compilerOptions": { 6 | "optimizer": { 7 | "enabled": true 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /waffle_test.json: -------------------------------------------------------------------------------- 1 | { 2 | "sourcesPath": "./test/helpers/contracts", 3 | "targetPath": "./test/helpers/interfaces", 4 | "solcVersion": "v0.4.24+commit.e67f0147" 5 | } 6 | --------------------------------------------------------------------------------