├── .editorconfig ├── .gitignore ├── .vscode └── launch.json ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── scripts ├── compile.ts ├── test.sh └── typings │ ├── ethereum │ └── index.d.ts │ └── solc │ └── index.d.ts ├── source └── deterministic-deployment-proxy.yul └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_size = unset 7 | indent_style = tab 8 | insert_final_newline = true 9 | tab_width = unset 10 | trim_trailing_whitespace = true 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | /output/ 3 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "type": "node", 6 | "request": "launch", 7 | "name": "compile", 8 | "cwd": "${workspaceFolder}", 9 | "runtimeArgs": [ "-r", "ts-node/register", ], 10 | "args": [ "${workspaceFolder}/scripts/compile.ts", ], 11 | "env": { 12 | "TS_NODE_PROJECT": "${workspaceFolder}/tsconfig.json", 13 | } 14 | }, 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Deterministic Deployment Proxy 2 | This is a proxy contract that can be deployed to any chain at the same address, and can then in turn deploy any contract at a deterministic location using CREATE2. To use, first deploy the contract using the one-time-account transaction specified in `output/deployment.json` (or grab last known good from bottom of readme), then submit a transaction `to` the address specified in `output/deployment.json` (or grab last known good from bottom of readme). The data should be the 32 byte 'salt' followed by your init code. 3 | 4 | ## Usage 5 | ```bash 6 | npm install 7 | npm run build 8 | ./scripts/test.sh 9 | ``` 10 | 11 | ### Details 12 | See `scripts/test.sh` (commented). Change `JSON_RPC` environment variable to the chain of your choice (requires an unlocked wallet with ETH). Notice that the script works against _any_ chain! If the chain already has the deployer contract deployed to it, then you can just comment out the deployment steps (line 20 and 23) and everything else will still function as normal. If you have already deployed your contract with it to the chain you are pointing at, the script will fail because your contract already exists at its address. 13 | 14 | ## Explanation 15 | This repository contains a simple contract that can deploy other contracts with a deterministic address on any chain using CREATE2. The CREATE2 call will deploy a contract (like CREATE opcode) but instead of the address being `keccak256(rlp([deployer_address, nonce]))` it instead uses the hash of the contract's bytecode and a salt. This means that a given deployer address will deploy the same code to the same address no matter _when_ or _where_ they issue the deployment. The deployer is deployed with a one-time-use-account, so no matter what chain the deployer is on, its address will always be the same. This means the only variables in determining the address of your contract are its bytecode hash and the provided salt. 16 | 17 | Between the use of CREATE2 opcode and the one-time-use-account for the deployer, we can ensure that a given contract will exist at the _exact_ same address on every chain, but without having to use the same gas pricing or limits every time. 18 | 19 | ---- 20 | 21 | ## Latest Outputs 22 | 23 | **Note:** as of last readme update; don't trust these to be latest! 24 | 25 | It is known to have been deployed to: [Ropsten test-net](https://ropsten.etherscan.io/tx/0xeddf9e61fb9d8f5111840daef55e5fde0041f5702856532cdbb5a02998033d26) 26 | 27 | ### Proxy Address 28 | ``` 29 | 0x4e59b44847b379578588920ca78fbf26c0b4956c 30 | ``` 31 | 32 | ### Deployment Transaction 33 | ``` 34 | 0xf8a58085174876e800830186a08080b853604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf31ba02222222222222222222222222222222222222222222222222222222222222222a02222222222222222222222222222222222222222222222222222222222222222 35 | ``` 36 | 37 | ### Deployment Signer Address 38 | ``` 39 | 0x3fab184622dc19b6109349b94811493bf2a45362 40 | ``` 41 | 42 | ### Deployment Gas Price 43 | ``` 44 | 100 nanoeth (gwei) 45 | ``` 46 | 47 | ### Deployment Gas Limit 48 | ``` 49 | 100000 50 | ``` 51 | 52 | **Note:** The actual gas used is 68131, but that can change if the cost of opcodes changes. To avoid having to move the proxy to a different address, we opted to give excess gas. Given the gas price, this may result in notable expenses, but since this only needs to be deployed once per chain that is acceptable. 53 | 54 | ### Taiko Deployment 55 | 56 | deterministicDeploymentProxy address 57 | ```solidity 58 | 0x4e59b44847b379578588920ca78fbf26c0b4956c 59 | ``` 60 | from: 61 | 62 | https://github.com/Arachnid/deterministic-deployment-proxy#proxy-address 63 | 64 | is produced by the following steps 65 | 1. Send ETH to signer 66 | ```solidity 67 | 0x3fab184622dc19b6109349b94811493bf2a45362 68 | ``` 69 | 2. L2 Taiko RPC node endpoint must disable EIP-155 by setting Geth flag 70 | ```sh 71 | --rpc.allow-unprotected-txs=true 72 | ``` 73 | using this pull request for reference 74 | https://github.com/taikoxyz/simple-taiko-node/pull/114 75 | 3. Forward their signed message in ethers.js 76 | ```solidity 77 | 0xf8a58085174876e800830186a08080b853604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf31ba02222222222222222222222222222222222222222222222222222222222222222a02222222222222222222222222222222222222222222222222222222222222222 78 | ``` 79 | example script: 80 | ```js 81 | const ethers = require("ethers") // npm i ethers@5.7.2 https://github.com/smartcontractkit/full-blockchain-solidity-course-js/discussions/5139#discussioncomment-5444517 82 | 83 | const rpcURL = "" // Your RPC URL goes here 84 | 85 | const provider = new ethers.providers.JsonRpcProvider(rpcURL) 86 | // const signer = new ethers.Wallet(Buffer.from(process.env.devTestnetPrivateKey, 'hex'), provider); 87 | 88 | createAndSendTx() 89 | 90 | 91 | async function createAndSendTx() { 92 | 93 | const connectedNetworkObject = await provider.getNetwork(); 94 | const chainIdConnected = connectedNetworkObject.chainId; 95 | console.log("chainIdConnected: "+ chainIdConnected) 96 | 97 | const txSigned = await provider.sendTransaction("0xf8a58085174876e800830186a08080b853604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf31ba02222222222222222222222222222222222222222222222222222222222222222a02222222222222222222222222222222222222222222222222222222222222222"); 98 | // const txSigned = await signer.sendTransaction("0xf8a58085174876e800830186a08080b853604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf31ba02222222222222222222222222222222222222222222222222222222222222222a02222222222222222222222222222222222222222222222222222222222222222"); 99 | 100 | console.log(txSigned) 101 | 102 | } 103 | ``` 104 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@zoltu/deterministic-deployment-proxy", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@types/bn.js": { 8 | "version": "4.11.5", 9 | "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.5.tgz", 10 | "integrity": "sha512-AEAZcIZga0JgVMHNtl1CprA/hXX7/wPt79AgR4XqaDt7jyj3QWYw6LPoOiznPtugDmlubUnAahMs2PFxGcQrng==", 11 | "dev": true, 12 | "requires": { 13 | "@types/node": "*" 14 | } 15 | }, 16 | "@types/elliptic": { 17 | "version": "6.4.9", 18 | "resolved": "https://registry.npmjs.org/@types/elliptic/-/elliptic-6.4.9.tgz", 19 | "integrity": "sha512-Mn+OyENd6YHwJKgUSyCTUDunEDFMaFpCXt52JCA00sxtzEa1ji6H0doZHL3iXhqMTo1Ob53X+Dv0s4PAJ+IVlA==", 20 | "dev": true, 21 | "requires": { 22 | "@types/bn.js": "*" 23 | } 24 | }, 25 | "@types/node": { 26 | "version": "12.6.8", 27 | "resolved": "https://registry.npmjs.org/@types/node/-/node-12.6.8.tgz", 28 | "integrity": "sha512-aX+gFgA5GHcDi89KG5keey2zf0WfZk/HAQotEamsK2kbey+8yGKcson0hbK8E+v0NArlCJQCqMP161YhV6ZXLg==", 29 | "dev": true 30 | }, 31 | "@zoltu/rlp-encoder": { 32 | "version": "1.0.1", 33 | "resolved": "https://registry.npmjs.org/@zoltu/rlp-encoder/-/rlp-encoder-1.0.1.tgz", 34 | "integrity": "sha512-S3Qx0SSbcbr3iZnVfSh0td8VX6zz1FsuTskDv/YyBZ0RY5u0Mou8dGmaNmZV733xkQvREAogrteR9UuCsxOtTA==", 35 | "dev": true 36 | }, 37 | "ansi-regex": { 38 | "version": "3.0.0", 39 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", 40 | "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", 41 | "dev": true 42 | }, 43 | "arg": { 44 | "version": "4.1.1", 45 | "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.1.tgz", 46 | "integrity": "sha512-SlmP3fEA88MBv0PypnXZ8ZfJhwmDeIE3SP71j37AiXQBXYosPV0x6uISAaHYSlSVhmHOVkomen0tbGk6Anlebw==", 47 | "dev": true 48 | }, 49 | "balanced-match": { 50 | "version": "1.0.0", 51 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 52 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 53 | "dev": true 54 | }, 55 | "bindings": { 56 | "version": "1.5.0", 57 | "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", 58 | "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", 59 | "dev": true, 60 | "requires": { 61 | "file-uri-to-path": "1.0.0" 62 | } 63 | }, 64 | "bn.js": { 65 | "version": "4.11.8", 66 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", 67 | "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", 68 | "dev": true 69 | }, 70 | "brace-expansion": { 71 | "version": "1.1.11", 72 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 73 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 74 | "dev": true, 75 | "requires": { 76 | "balanced-match": "^1.0.0", 77 | "concat-map": "0.0.1" 78 | } 79 | }, 80 | "brorand": { 81 | "version": "1.1.0", 82 | "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", 83 | "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", 84 | "dev": true 85 | }, 86 | "buffer-from": { 87 | "version": "1.1.1", 88 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", 89 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", 90 | "dev": true 91 | }, 92 | "camelcase": { 93 | "version": "4.1.0", 94 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", 95 | "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", 96 | "dev": true 97 | }, 98 | "cliui": { 99 | "version": "4.1.0", 100 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", 101 | "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", 102 | "dev": true, 103 | "requires": { 104 | "string-width": "^2.1.1", 105 | "strip-ansi": "^4.0.0", 106 | "wrap-ansi": "^2.0.0" 107 | } 108 | }, 109 | "code-point-at": { 110 | "version": "1.1.0", 111 | "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", 112 | "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", 113 | "dev": true 114 | }, 115 | "command-exists": { 116 | "version": "1.2.8", 117 | "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.8.tgz", 118 | "integrity": "sha512-PM54PkseWbiiD/mMsbvW351/u+dafwTJ0ye2qB60G1aGQP9j3xK2gmMDc+R34L3nDtx4qMCitXT75mkbkGJDLw==", 119 | "dev": true 120 | }, 121 | "concat-map": { 122 | "version": "0.0.1", 123 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 124 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 125 | "dev": true 126 | }, 127 | "cross-spawn": { 128 | "version": "5.1.0", 129 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", 130 | "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", 131 | "dev": true, 132 | "requires": { 133 | "lru-cache": "^4.0.1", 134 | "shebang-command": "^1.2.0", 135 | "which": "^1.2.9" 136 | } 137 | }, 138 | "decamelize": { 139 | "version": "1.2.0", 140 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", 141 | "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", 142 | "dev": true 143 | }, 144 | "diff": { 145 | "version": "4.0.1", 146 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz", 147 | "integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==", 148 | "dev": true 149 | }, 150 | "elliptic": { 151 | "version": "6.5.0", 152 | "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.0.tgz", 153 | "integrity": "sha512-eFOJTMyCYb7xtE/caJ6JJu+bhi67WCYNbkGSknu20pmM8Ke/bqOfdnZWxyoGN26JgfxTbXrsCkEw4KheCT/KGg==", 154 | "dev": true, 155 | "requires": { 156 | "bn.js": "^4.4.0", 157 | "brorand": "^1.0.1", 158 | "hash.js": "^1.0.0", 159 | "hmac-drbg": "^1.0.0", 160 | "inherits": "^2.0.1", 161 | "minimalistic-assert": "^1.0.0", 162 | "minimalistic-crypto-utils": "^1.0.0" 163 | } 164 | }, 165 | "execa": { 166 | "version": "0.7.0", 167 | "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", 168 | "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", 169 | "dev": true, 170 | "requires": { 171 | "cross-spawn": "^5.0.1", 172 | "get-stream": "^3.0.0", 173 | "is-stream": "^1.1.0", 174 | "npm-run-path": "^2.0.0", 175 | "p-finally": "^1.0.0", 176 | "signal-exit": "^3.0.0", 177 | "strip-eof": "^1.0.0" 178 | } 179 | }, 180 | "file-uri-to-path": { 181 | "version": "1.0.0", 182 | "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", 183 | "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", 184 | "dev": true 185 | }, 186 | "find-up": { 187 | "version": "2.1.0", 188 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", 189 | "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", 190 | "dev": true, 191 | "requires": { 192 | "locate-path": "^2.0.0" 193 | } 194 | }, 195 | "fs-extra": { 196 | "version": "0.30.0", 197 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", 198 | "integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=", 199 | "dev": true, 200 | "requires": { 201 | "graceful-fs": "^4.1.2", 202 | "jsonfile": "^2.1.0", 203 | "klaw": "^1.0.0", 204 | "path-is-absolute": "^1.0.0", 205 | "rimraf": "^2.2.8" 206 | } 207 | }, 208 | "fs.realpath": { 209 | "version": "1.0.0", 210 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 211 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 212 | "dev": true 213 | }, 214 | "get-caller-file": { 215 | "version": "1.0.3", 216 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", 217 | "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", 218 | "dev": true 219 | }, 220 | "get-stream": { 221 | "version": "3.0.0", 222 | "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", 223 | "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", 224 | "dev": true 225 | }, 226 | "glob": { 227 | "version": "7.1.4", 228 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", 229 | "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", 230 | "dev": true, 231 | "requires": { 232 | "fs.realpath": "^1.0.0", 233 | "inflight": "^1.0.4", 234 | "inherits": "2", 235 | "minimatch": "^3.0.4", 236 | "once": "^1.3.0", 237 | "path-is-absolute": "^1.0.0" 238 | } 239 | }, 240 | "graceful-fs": { 241 | "version": "4.1.15", 242 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", 243 | "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", 244 | "dev": true 245 | }, 246 | "hash.js": { 247 | "version": "1.1.7", 248 | "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", 249 | "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", 250 | "dev": true, 251 | "requires": { 252 | "inherits": "^2.0.3", 253 | "minimalistic-assert": "^1.0.1" 254 | } 255 | }, 256 | "hmac-drbg": { 257 | "version": "1.0.1", 258 | "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", 259 | "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", 260 | "dev": true, 261 | "requires": { 262 | "hash.js": "^1.0.3", 263 | "minimalistic-assert": "^1.0.0", 264 | "minimalistic-crypto-utils": "^1.0.1" 265 | } 266 | }, 267 | "inflight": { 268 | "version": "1.0.6", 269 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 270 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 271 | "dev": true, 272 | "requires": { 273 | "once": "^1.3.0", 274 | "wrappy": "1" 275 | } 276 | }, 277 | "inherits": { 278 | "version": "2.0.3", 279 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 280 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", 281 | "dev": true 282 | }, 283 | "invert-kv": { 284 | "version": "1.0.0", 285 | "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", 286 | "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", 287 | "dev": true 288 | }, 289 | "is-fullwidth-code-point": { 290 | "version": "2.0.0", 291 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", 292 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", 293 | "dev": true 294 | }, 295 | "is-stream": { 296 | "version": "1.1.0", 297 | "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", 298 | "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", 299 | "dev": true 300 | }, 301 | "isexe": { 302 | "version": "2.0.0", 303 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 304 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 305 | "dev": true 306 | }, 307 | "js-sha3": { 308 | "version": "0.8.0", 309 | "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", 310 | "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", 311 | "dev": true 312 | }, 313 | "jsonfile": { 314 | "version": "2.4.0", 315 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", 316 | "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", 317 | "dev": true, 318 | "requires": { 319 | "graceful-fs": "^4.1.6" 320 | } 321 | }, 322 | "keccak": { 323 | "version": "1.4.0", 324 | "resolved": "https://registry.npmjs.org/keccak/-/keccak-1.4.0.tgz", 325 | "integrity": "sha512-eZVaCpblK5formjPjeTBik7TAg+pqnDrMHIffSvi9Lh7PQgM1+hSzakUeZFCk9DVVG0dacZJuaz2ntwlzZUIBw==", 326 | "dev": true, 327 | "requires": { 328 | "bindings": "^1.2.1", 329 | "inherits": "^2.0.3", 330 | "nan": "^2.2.1", 331 | "safe-buffer": "^5.1.0" 332 | } 333 | }, 334 | "klaw": { 335 | "version": "1.3.1", 336 | "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", 337 | "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", 338 | "dev": true, 339 | "requires": { 340 | "graceful-fs": "^4.1.9" 341 | } 342 | }, 343 | "lcid": { 344 | "version": "1.0.0", 345 | "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", 346 | "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", 347 | "dev": true, 348 | "requires": { 349 | "invert-kv": "^1.0.0" 350 | } 351 | }, 352 | "locate-path": { 353 | "version": "2.0.0", 354 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", 355 | "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", 356 | "dev": true, 357 | "requires": { 358 | "p-locate": "^2.0.0", 359 | "path-exists": "^3.0.0" 360 | } 361 | }, 362 | "lru-cache": { 363 | "version": "4.1.5", 364 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", 365 | "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", 366 | "dev": true, 367 | "requires": { 368 | "pseudomap": "^1.0.2", 369 | "yallist": "^2.1.2" 370 | } 371 | }, 372 | "make-error": { 373 | "version": "1.3.5", 374 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz", 375 | "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==", 376 | "dev": true 377 | }, 378 | "mem": { 379 | "version": "1.1.0", 380 | "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", 381 | "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", 382 | "dev": true, 383 | "requires": { 384 | "mimic-fn": "^1.0.0" 385 | } 386 | }, 387 | "memorystream": { 388 | "version": "0.3.1", 389 | "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", 390 | "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=", 391 | "dev": true 392 | }, 393 | "mimic-fn": { 394 | "version": "1.2.0", 395 | "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", 396 | "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", 397 | "dev": true 398 | }, 399 | "minimalistic-assert": { 400 | "version": "1.0.1", 401 | "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", 402 | "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", 403 | "dev": true 404 | }, 405 | "minimalistic-crypto-utils": { 406 | "version": "1.0.1", 407 | "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", 408 | "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", 409 | "dev": true 410 | }, 411 | "minimatch": { 412 | "version": "3.0.4", 413 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 414 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 415 | "dev": true, 416 | "requires": { 417 | "brace-expansion": "^1.1.7" 418 | } 419 | }, 420 | "nan": { 421 | "version": "2.13.2", 422 | "resolved": "https://registry.npmjs.org/nan/-/nan-2.13.2.tgz", 423 | "integrity": "sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw==", 424 | "dev": true 425 | }, 426 | "npm-run-path": { 427 | "version": "2.0.2", 428 | "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", 429 | "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", 430 | "dev": true, 431 | "requires": { 432 | "path-key": "^2.0.0" 433 | } 434 | }, 435 | "number-is-nan": { 436 | "version": "1.0.1", 437 | "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", 438 | "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", 439 | "dev": true 440 | }, 441 | "once": { 442 | "version": "1.4.0", 443 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 444 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 445 | "dev": true, 446 | "requires": { 447 | "wrappy": "1" 448 | } 449 | }, 450 | "os-locale": { 451 | "version": "2.1.0", 452 | "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", 453 | "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", 454 | "dev": true, 455 | "requires": { 456 | "execa": "^0.7.0", 457 | "lcid": "^1.0.0", 458 | "mem": "^1.1.0" 459 | } 460 | }, 461 | "os-tmpdir": { 462 | "version": "1.0.2", 463 | "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", 464 | "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", 465 | "dev": true 466 | }, 467 | "p-finally": { 468 | "version": "1.0.0", 469 | "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", 470 | "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", 471 | "dev": true 472 | }, 473 | "p-limit": { 474 | "version": "1.3.0", 475 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", 476 | "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", 477 | "dev": true, 478 | "requires": { 479 | "p-try": "^1.0.0" 480 | } 481 | }, 482 | "p-locate": { 483 | "version": "2.0.0", 484 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", 485 | "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", 486 | "dev": true, 487 | "requires": { 488 | "p-limit": "^1.1.0" 489 | } 490 | }, 491 | "p-try": { 492 | "version": "1.0.0", 493 | "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", 494 | "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", 495 | "dev": true 496 | }, 497 | "path-exists": { 498 | "version": "3.0.0", 499 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", 500 | "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", 501 | "dev": true 502 | }, 503 | "path-is-absolute": { 504 | "version": "1.0.1", 505 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 506 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 507 | "dev": true 508 | }, 509 | "path-key": { 510 | "version": "2.0.1", 511 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", 512 | "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", 513 | "dev": true 514 | }, 515 | "pseudomap": { 516 | "version": "1.0.2", 517 | "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", 518 | "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", 519 | "dev": true 520 | }, 521 | "require-directory": { 522 | "version": "2.1.1", 523 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 524 | "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", 525 | "dev": true 526 | }, 527 | "require-from-string": { 528 | "version": "2.0.2", 529 | "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", 530 | "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", 531 | "dev": true 532 | }, 533 | "require-main-filename": { 534 | "version": "1.0.1", 535 | "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", 536 | "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", 537 | "dev": true 538 | }, 539 | "rimraf": { 540 | "version": "2.6.3", 541 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", 542 | "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", 543 | "dev": true, 544 | "requires": { 545 | "glob": "^7.1.3" 546 | } 547 | }, 548 | "safe-buffer": { 549 | "version": "5.1.2", 550 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 551 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", 552 | "dev": true 553 | }, 554 | "semver": { 555 | "version": "5.7.0", 556 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", 557 | "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", 558 | "dev": true 559 | }, 560 | "set-blocking": { 561 | "version": "2.0.0", 562 | "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", 563 | "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", 564 | "dev": true 565 | }, 566 | "shebang-command": { 567 | "version": "1.2.0", 568 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", 569 | "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", 570 | "dev": true, 571 | "requires": { 572 | "shebang-regex": "^1.0.0" 573 | } 574 | }, 575 | "shebang-regex": { 576 | "version": "1.0.0", 577 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", 578 | "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", 579 | "dev": true 580 | }, 581 | "signal-exit": { 582 | "version": "3.0.2", 583 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", 584 | "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", 585 | "dev": true 586 | }, 587 | "solc": { 588 | "version": "0.5.8", 589 | "resolved": "https://registry.npmjs.org/solc/-/solc-0.5.8.tgz", 590 | "integrity": "sha512-RQ2SlwPBOBSV7ktNQJkvbiQks3t+3V9dsqD014EdstxnJzSxBuOvbt3P5QXpNPYW1DsEmF7dhOaT3JL7yEae/A==", 591 | "dev": true, 592 | "requires": { 593 | "command-exists": "^1.2.8", 594 | "fs-extra": "^0.30.0", 595 | "keccak": "^1.0.2", 596 | "memorystream": "^0.3.1", 597 | "require-from-string": "^2.0.0", 598 | "semver": "^5.5.0", 599 | "tmp": "0.0.33", 600 | "yargs": "^11.0.0" 601 | } 602 | }, 603 | "source-map": { 604 | "version": "0.6.1", 605 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 606 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 607 | "dev": true 608 | }, 609 | "source-map-support": { 610 | "version": "0.5.12", 611 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.12.tgz", 612 | "integrity": "sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==", 613 | "dev": true, 614 | "requires": { 615 | "buffer-from": "^1.0.0", 616 | "source-map": "^0.6.0" 617 | } 618 | }, 619 | "string-width": { 620 | "version": "2.1.1", 621 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", 622 | "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", 623 | "dev": true, 624 | "requires": { 625 | "is-fullwidth-code-point": "^2.0.0", 626 | "strip-ansi": "^4.0.0" 627 | } 628 | }, 629 | "strip-ansi": { 630 | "version": "4.0.0", 631 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", 632 | "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", 633 | "dev": true, 634 | "requires": { 635 | "ansi-regex": "^3.0.0" 636 | } 637 | }, 638 | "strip-eof": { 639 | "version": "1.0.0", 640 | "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", 641 | "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", 642 | "dev": true 643 | }, 644 | "tmp": { 645 | "version": "0.0.33", 646 | "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", 647 | "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", 648 | "dev": true, 649 | "requires": { 650 | "os-tmpdir": "~1.0.2" 651 | } 652 | }, 653 | "ts-node": { 654 | "version": "8.3.0", 655 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.3.0.tgz", 656 | "integrity": "sha512-dyNS/RqyVTDcmNM4NIBAeDMpsAdaQ+ojdf0GOLqE6nwJOgzEkdRNzJywhDfwnuvB10oa6NLVG1rUJQCpRN7qoQ==", 657 | "dev": true, 658 | "requires": { 659 | "arg": "^4.1.0", 660 | "diff": "^4.0.1", 661 | "make-error": "^1.1.1", 662 | "source-map-support": "^0.5.6", 663 | "yn": "^3.0.0" 664 | } 665 | }, 666 | "typescript": { 667 | "version": "3.5.3", 668 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz", 669 | "integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==", 670 | "dev": true 671 | }, 672 | "which": { 673 | "version": "1.3.1", 674 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", 675 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", 676 | "dev": true, 677 | "requires": { 678 | "isexe": "^2.0.0" 679 | } 680 | }, 681 | "which-module": { 682 | "version": "2.0.0", 683 | "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", 684 | "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", 685 | "dev": true 686 | }, 687 | "wrap-ansi": { 688 | "version": "2.1.0", 689 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", 690 | "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", 691 | "dev": true, 692 | "requires": { 693 | "string-width": "^1.0.1", 694 | "strip-ansi": "^3.0.1" 695 | }, 696 | "dependencies": { 697 | "ansi-regex": { 698 | "version": "2.1.1", 699 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", 700 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", 701 | "dev": true 702 | }, 703 | "is-fullwidth-code-point": { 704 | "version": "1.0.0", 705 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", 706 | "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", 707 | "dev": true, 708 | "requires": { 709 | "number-is-nan": "^1.0.0" 710 | } 711 | }, 712 | "string-width": { 713 | "version": "1.0.2", 714 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", 715 | "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", 716 | "dev": true, 717 | "requires": { 718 | "code-point-at": "^1.0.0", 719 | "is-fullwidth-code-point": "^1.0.0", 720 | "strip-ansi": "^3.0.0" 721 | } 722 | }, 723 | "strip-ansi": { 724 | "version": "3.0.1", 725 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", 726 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", 727 | "dev": true, 728 | "requires": { 729 | "ansi-regex": "^2.0.0" 730 | } 731 | } 732 | } 733 | }, 734 | "wrappy": { 735 | "version": "1.0.2", 736 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 737 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 738 | "dev": true 739 | }, 740 | "y18n": { 741 | "version": "3.2.1", 742 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", 743 | "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", 744 | "dev": true 745 | }, 746 | "yallist": { 747 | "version": "2.1.2", 748 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", 749 | "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", 750 | "dev": true 751 | }, 752 | "yargs": { 753 | "version": "11.1.0", 754 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz", 755 | "integrity": "sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==", 756 | "dev": true, 757 | "requires": { 758 | "cliui": "^4.0.0", 759 | "decamelize": "^1.1.1", 760 | "find-up": "^2.1.0", 761 | "get-caller-file": "^1.0.1", 762 | "os-locale": "^2.0.0", 763 | "require-directory": "^2.1.1", 764 | "require-main-filename": "^1.0.1", 765 | "set-blocking": "^2.0.0", 766 | "string-width": "^2.0.0", 767 | "which-module": "^2.0.0", 768 | "y18n": "^3.2.1", 769 | "yargs-parser": "^9.0.2" 770 | } 771 | }, 772 | "yargs-parser": { 773 | "version": "9.0.2", 774 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", 775 | "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", 776 | "dev": true, 777 | "requires": { 778 | "camelcase": "^4.1.0" 779 | } 780 | }, 781 | "yn": { 782 | "version": "3.1.0", 783 | "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.0.tgz", 784 | "integrity": "sha512-kKfnnYkbTfrAdd0xICNFw7Atm8nKpLcLv9AZGEt+kczL/WQVai4e2V6ZN8U/O+iI6WrNuJjNNOyu4zfhl9D3Hg==", 785 | "dev": true 786 | } 787 | } 788 | } 789 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@zoltu/deterministic-deployment-proxy", 3 | "description": "An Ethereum proxy contract that can be used for deploying contracts to a deterministic address on any chain.", 4 | "version": "1.0.0", 5 | "license": "Unlicense", 6 | "repository": { 7 | "type": "git", 8 | "url": "git@github.com:Zoltu/deterministic-deployment-proxy.git" 9 | }, 10 | "dependencies": {}, 11 | "devDependencies": { 12 | "@types/elliptic": "6.4.9", 13 | "@types/node": "12.6.8", 14 | "@zoltu/rlp-encoder": "1.0.1", 15 | "elliptic": "6.5.0", 16 | "js-sha3": "0.8.0", 17 | "solc": "0.5.8", 18 | "ts-node": "8.3.0", 19 | "typescript": "3.5.3" 20 | }, 21 | "scripts": { 22 | "build": "ts-node scripts/compile.ts" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /scripts/compile.ts: -------------------------------------------------------------------------------- 1 | import { promises as filesystem } from 'fs' 2 | import * as path from 'path' 3 | import { CompilerOutput, CompilerInput, compileStandardWrapper, CompilerOutputContract } from 'solc' 4 | import { rlpEncode } from '@zoltu/rlp-encoder' 5 | import { keccak256 } from 'js-sha3' 6 | import { ec as EllipticCurve } from 'elliptic' 7 | const secp256k1 = new EllipticCurve('secp256k1') 8 | 9 | export async function ensureDirectoryExists(absoluteDirectoryPath: string) { 10 | try { 11 | await filesystem.mkdir(absoluteDirectoryPath) 12 | } catch (error) { 13 | if (error.code === 'EEXIST') return 14 | throw error 15 | } 16 | } 17 | 18 | async function doStuff() { 19 | const compilerOutput = await compileContracts() 20 | const contract = compilerOutput.contracts['deterministic-deployment-proxy.yul']['Proxy'] 21 | await ensureDirectoryExists(path.join(__dirname, '..', '/output/')) 22 | await writeBytecode(contract.evm.bytecode.object) 23 | await writeFactoryDeployerTransaction(contract) 24 | } 25 | 26 | async function compileContracts(): Promise { 27 | const solidityFilePath = path.join(__dirname, '..', 'source', 'deterministic-deployment-proxy.yul') 28 | const soliditySourceCode = await filesystem.readFile(solidityFilePath, 'utf8') 29 | const compilerInput: CompilerInput = { 30 | language: "Yul", 31 | settings: { 32 | optimizer: { 33 | enabled: true, 34 | details: { 35 | yul: true, 36 | }, 37 | }, 38 | outputSelection: { 39 | "*": { 40 | "*": [ "abi", "evm.bytecode.object", "evm.gasEstimates" ] 41 | }, 42 | }, 43 | }, 44 | sources: { 45 | 'deterministic-deployment-proxy.yul': { 46 | content: soliditySourceCode, 47 | }, 48 | }, 49 | } 50 | const compilerInputJson = JSON.stringify(compilerInput) 51 | const compilerOutputJson = compileStandardWrapper(compilerInputJson) 52 | const compilerOutput = JSON.parse(compilerOutputJson) as CompilerOutput 53 | const errors = compilerOutput.errors 54 | if (errors) { 55 | let concatenatedErrors = ""; 56 | 57 | for (let error of errors) { 58 | if (/Yul is still experimental/.test(error.message)) continue 59 | concatenatedErrors += error.formattedMessage + "\n"; 60 | } 61 | 62 | if (concatenatedErrors.length > 0) { 63 | throw new Error("The following errors/warnings were returned by solc:\n\n" + concatenatedErrors); 64 | } 65 | } 66 | 67 | return compilerOutput 68 | } 69 | 70 | async function writeBytecode(bytecode: string) { 71 | const filePath = path.join(__dirname, '..', 'output', `bytecode.txt`) 72 | await filesystem.writeFile(filePath, bytecode, { encoding: 'utf8', flag: 'w' }) 73 | } 74 | 75 | async function writeFactoryDeployerTransaction(contract: CompilerOutputContract) { 76 | const deploymentGas = 100000 // actual gas costs last measure: 59159; we don't want to run too close though because gas costs can change in forks and we want our address to be retained 77 | const deploymentBytecode = contract.evm.bytecode.object 78 | 79 | const nonce = new Uint8Array(0) 80 | const gasPrice = arrayFromNumber(100*10**9) 81 | const gasLimit = arrayFromNumber(deploymentGas) 82 | const to = new Uint8Array(0) 83 | const value = new Uint8Array(0) 84 | const data = arrayFromHexString(deploymentBytecode) 85 | const v = arrayFromNumber(27) 86 | const r = arrayFromHexString('2222222222222222222222222222222222222222222222222222222222222222') 87 | const s = arrayFromHexString('2222222222222222222222222222222222222222222222222222222222222222') 88 | 89 | const unsignedEncodedTransaction = rlpEncode([nonce, gasPrice, gasLimit, to, value, data]) 90 | const signedEncodedTransaction = rlpEncode([nonce, gasPrice, gasLimit, to, value, data, v, r, s]) 91 | const hashedSignedEncodedTransaction = new Uint8Array(keccak256.arrayBuffer(unsignedEncodedTransaction)) 92 | const signerAddress = arrayFromHexString(keccak256(secp256k1.recoverPubKey(hashedSignedEncodedTransaction, { r: r, s: s}, 0).encode('array').slice(1)).slice(-40)) 93 | const contractAddress = arrayFromHexString(keccak256(rlpEncode([signerAddress, nonce])).slice(-40)) 94 | 95 | const filePath = path.join(__dirname, '../output/deployment.json') 96 | const fileContents = `{ 97 | "gasPrice": 100000000000, 98 | "gasLimit": ${deploymentGas}, 99 | "signerAddress": "${signerAddress.reduce((x,y)=>x+=y.toString(16).padStart(2, '0'), '')}", 100 | "transaction": "${signedEncodedTransaction.reduce((x,y)=>x+=y.toString(16).padStart(2, '0'), '')}", 101 | "address": "${contractAddress.reduce((x,y)=>x+=y.toString(16).padStart(2, '0'), '')}" 102 | } 103 | ` 104 | await filesystem.writeFile(filePath, fileContents, { encoding: 'utf8', flag: 'w' }) 105 | } 106 | 107 | doStuff().then(() => { 108 | process.exit(0) 109 | }).catch(error => { 110 | console.error(error) 111 | process.exit(1) 112 | }) 113 | 114 | function arrayFromNumber(value: number): Uint8Array { 115 | return arrayFromHexString(value.toString(16)) 116 | } 117 | 118 | function arrayFromHexString(value: string): Uint8Array { 119 | const normalized = (value.length % 2) ? `0${value}` : value 120 | const bytes = [] 121 | for (let i = 0; i < normalized.length; i += 2) { 122 | bytes.push(Number.parseInt(`${normalized[i]}${normalized[i+1]}`, 16)) 123 | } 124 | return new Uint8Array(bytes) 125 | } 126 | -------------------------------------------------------------------------------- /scripts/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -x 4 | 5 | JSON_RPC="http://localhost:1234" 6 | 7 | # start geth in a local container 8 | docker container run --rm -d --name deployment-proxy-geth -p 1234:8545 -e GETH_VERBOSITY=3 keydonix/geth-clique 9 | # wait for geth to become responsive 10 | until curl --silent --fail $JSON_RPC -X 'POST' -H 'Content-Type: application/json' --data "{\"jsonrpc\":\"2.0\", \"id\":1, \"method\": \"net_version\", \"params\": []}"; do sleep 1; done 11 | 12 | # extract the variables we need from json output 13 | MY_ADDRESS="0x913dA4198E6bE1D5f5E4a40D0667f70C0B5430Eb" 14 | ONE_TIME_SIGNER_ADDRESS="0x$(cat output/deployment.json | jq --raw-output '.signerAddress')" 15 | GAS_COST="0x$(printf '%x' $(($(cat output/deployment.json | jq --raw-output '.gasPrice') * $(cat output/deployment.json | jq --raw-output '.gasLimit'))))" 16 | TRANSACTION="0x$(cat output/deployment.json | jq --raw-output '.transaction')" 17 | DEPLOYER_ADDRESS="0x$(cat output/deployment.json | jq --raw-output '.address')" 18 | 19 | # send gas money to signer 20 | curl $JSON_RPC -X 'POST' -H 'Content-Type: application/json' --data "{\"jsonrpc\":\"2.0\", \"id\":1, \"method\": \"eth_sendTransaction\", \"params\": [{\"from\":\"$MY_ADDRESS\",\"to\":\"$ONE_TIME_SIGNER_ADDRESS\",\"value\":\"$GAS_COST\"}]}" 21 | 22 | # deploy the deployer contract 23 | curl $JSON_RPC -X 'POST' -H 'Content-Type: application/json' --data "{\"jsonrpc\":\"2.0\", \"id\":1, \"method\": \"eth_sendRawTransaction\", \"params\": [\"$TRANSACTION\"]}" 24 | 25 | # deploy our contract 26 | # contract: pragma solidity 0.5.8; contract Apple {function banana() external pure returns (uint8) {return 42;}} 27 | BYTECODE="6080604052348015600f57600080fd5b5060848061001e6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063c3cafc6f14602d575b600080fd5b6033604f565b604051808260ff1660ff16815260200191505060405180910390f35b6000602a90509056fea165627a7a72305820ab7651cb86b8c1487590004c2444f26ae30077a6b96c6bc62dda37f1328539250029" 28 | MY_CONTRACT_ADDRESS=$(curl $JSON_RPC -X 'POST' -H 'Content-Type: application/json' --silent --data "{\"jsonrpc\":\"2.0\", \"id\":1, \"method\": \"eth_call\", \"params\": [{\"from\":\"$MY_ADDRESS\",\"to\":\"$DEPLOYER_ADDRESS\", \"data\":\"0x0000000000000000000000000000000000000000000000000000000000000000$BYTECODE\"}, \"latest\"]}" | jq --raw-output '.result') 29 | curl $JSON_RPC -X 'POST' -H 'Content-Type: application/json' --data "{\"jsonrpc\":\"2.0\", \"id\":1, \"method\": \"eth_sendTransaction\", \"params\": [{\"from\":\"$MY_ADDRESS\",\"to\":\"$DEPLOYER_ADDRESS\", \"gas\":\"0xf4240\", \"data\":\"0x0000000000000000000000000000000000000000000000000000000000000000$BYTECODE\"}]}" 30 | 31 | # call our contract (NOTE: MY_CONTRACT_ADDRESS is the same no matter what chain we deploy to!) 32 | MY_CONTRACT_METHOD_SIGNATURE="c3cafc6f" 33 | curl $JSON_RPC -X 'POST' -H 'Content-Type: application/json' --data "{\"jsonrpc\":\"2.0\", \"id\":1, \"method\": \"eth_call\", \"params\": [{\"to\":\"$MY_CONTRACT_ADDRESS\", \"data\":\"0x$MY_CONTRACT_METHOD_SIGNATURE\"}, \"latest\"]}" 34 | # expected result is 0x000000000000000000000000000000000000000000000000000000000000002a (hex encoded 42) 35 | 36 | # shutdown Parity 37 | docker container stop deployment-proxy-geth 38 | -------------------------------------------------------------------------------- /scripts/typings/ethereum/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'ethereum' { 2 | export type Primitive = 'uint8' | 'uint64' | 'uint256' | 'bool' | 'string' | 'address' | 'bytes20' | 'bytes32' | 'bytes' | 'int256' | 'tuple' | 'address[]' | 'uint256[]' | 'bytes32[]' | 'tuple[]'; 3 | 4 | export interface AbiParameter { 5 | name: string, 6 | type: Primitive, 7 | components?: Array 8 | } 9 | 10 | export interface AbiEventParameter extends AbiParameter { 11 | indexed: boolean, 12 | } 13 | 14 | export interface AbiFunction { 15 | name: string, 16 | type: 'function' | 'constructor' | 'fallback', 17 | stateMutability: 'pure' | 'view' | 'payable' | 'nonpayable', 18 | constant: boolean, 19 | payable: boolean, 20 | inputs: Array, 21 | outputs: Array, 22 | } 23 | 24 | export interface AbiEvent { 25 | name: string, 26 | type: 'event', 27 | inputs: Array, 28 | anonymous: boolean, 29 | } 30 | 31 | export type Abi = Array; 32 | } 33 | -------------------------------------------------------------------------------- /scripts/typings/solc/index.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'solc' { 2 | import { Abi, Primitive } from 'ethereum'; 3 | 4 | interface CompilerInputSourceFile { 5 | keccak256?: string; 6 | urls: string[]; 7 | } 8 | interface CompilerInputSourceCode { 9 | keccak256?: string; 10 | content: string; 11 | } 12 | interface CompilerInput { 13 | language: "Solidity" | "serpent" | "lll" | "assembly" | "Yul"; 14 | settings?: any, 15 | sources: { 16 | [globalName: string]: CompilerInputSourceFile|CompilerInputSourceCode, 17 | }; 18 | } 19 | interface CompilerOutputError { 20 | sourceLocation?: { 21 | file: string; 22 | start: number; 23 | end: number; 24 | }; 25 | type: "TypeError" | "InternalCompilerError" | "Exception"; 26 | component: "general" | "ewasm"; 27 | severity: "error" | "warning"; 28 | message: string; 29 | formattedMessage?: string; 30 | } 31 | interface CompilerOutputEvmBytecode { 32 | object: string; 33 | opcodes?: string; 34 | sourceMap?: string; 35 | linkReferences?: {} | { 36 | [globalName: string]: { 37 | [name: string]: {start: number, length: number}[]; 38 | }; 39 | }; 40 | } 41 | interface CompilerOutputSources { 42 | [globalName: string]: { 43 | id: number; 44 | ast: any; 45 | legacyAST: any; 46 | }, 47 | } 48 | interface CompilerOutputContract { 49 | abi: Abi; 50 | metadata?: string; 51 | userdoc?: any; 52 | devdoc?: any; 53 | ir?: string; 54 | evm: { 55 | assembly?: string; 56 | legacyAssembly?: any; 57 | bytecode: CompilerOutputEvmBytecode; 58 | deployedBytecode?: CompilerOutputEvmBytecode; 59 | methodIdentifiers?: { 60 | [methodName: string]: string; 61 | }; 62 | gasEstimates?: { 63 | creation: { 64 | codeDepositCost: string; 65 | executionCost: string; 66 | totalCost: string; 67 | }; 68 | external: { 69 | [functionSignature: string]: string; 70 | }; 71 | internal: { 72 | [functionSignature: string]: string; 73 | }; 74 | }; 75 | }; 76 | ewasm?: { 77 | wast: string; 78 | wasm: string; 79 | } 80 | } 81 | interface CompilerOutputContractFile { 82 | [contractName: string]: CompilerOutputContract 83 | } 84 | interface CompilerOutputContracts { 85 | [globalName: string]: CompilerOutputContractFile 86 | } 87 | interface CompilerOutput { 88 | errors?: CompilerOutputError[]; 89 | sources?: CompilerOutputSources; 90 | contracts: CompilerOutputContracts; 91 | } 92 | type ReadCallback = (path: string) => { contents?: string, error?: string}; 93 | function compileStandardWrapper(input: string, readCallback?: ReadCallback): string; 94 | } 95 | -------------------------------------------------------------------------------- /source/deterministic-deployment-proxy.yul: -------------------------------------------------------------------------------- 1 | object "Proxy" { 2 | // deployment code 3 | code { 4 | let size := datasize("runtime") 5 | datacopy(0, dataoffset("runtime"), size) 6 | return(0, size) 7 | } 8 | object "runtime" { 9 | // deployed code 10 | code { 11 | calldatacopy(0, 32, sub(calldatasize(), 32)) 12 | let result := create2(callvalue(), 0, sub(calldatasize(), 32), calldataload(0)) 13 | if iszero(result) { revert(0, 0) } 14 | mstore(0, result) 15 | return(12, 20) 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2018", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "noEmit": true, 7 | "strict": true, 8 | "noImplicitAny": true, 9 | "noImplicitThis": true, 10 | "noImplicitReturns": true, 11 | "noUnusedLocals": true, 12 | "noUnusedParameters": false, 13 | "lib": [ "es2018" ], 14 | "typeRoots": [ "./node_modules/@types", "./scripts/typings" ], 15 | "rootDir": "scripts", 16 | } 17 | } 18 | --------------------------------------------------------------------------------