From 081a74eb9d77b213b78945debc9e9754559d5ba1 Mon Sep 17 00:00:00 2001 From: Jakub Stefanski Date: Sat, 4 Nov 2017 18:58:00 +0100 Subject: [PATCH 1/4] Do not autoformat package.json --- .prettierignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.prettierignore b/.prettierignore index 15813be..3c1caf8 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,2 +1,3 @@ +package.json package-lock.json node_modules/ From 60c14ff7faafbb810d1d0ce6f41d685b1c1edab4 Mon Sep 17 00:00:00 2001 From: Jakub Stefanski Date: Sat, 4 Nov 2017 19:12:29 +0100 Subject: [PATCH 2/4] Update truffle to 4.0.1 along with other packages --- package-lock.json | 443 ++++++++++++++++++++++------------------------ package.json | 33 ++-- 2 files changed, 229 insertions(+), 247 deletions(-) diff --git a/package-lock.json b/package-lock.json index a760eb6..eac52cb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,22 +17,17 @@ "dev": true }, "@types/mocha": { - "version": "2.2.43", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-2.2.43.tgz", - "integrity": "sha512-xNlAmH+lRJdUMXClMTI9Y0pRqIojdxfm7DHsIxoB2iTzu3fnPmSMEN8SsSx0cdwV36d02PWCWaDUoZPDSln+xw==", + "version": "2.2.44", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-2.2.44.tgz", + "integrity": "sha512-k2tWTQU8G4+iSMvqKi0Q9IIsWAp/n8xzdZS4Q4YVIltApoMA00wFBFdlJnmoaK1/z7B0Cy0yPe6GgXteSmdUNw==", "dev": true }, "@types/ramda": { - "version": "0.24.14", - "resolved": "https://registry.npmjs.org/@types/ramda/-/ramda-0.24.14.tgz", - "integrity": "sha512-kxdtZ1MiYjwZxGHSFgNxbnYWgv/kfyhB21gLBQwp6jwYyq1Bifk4TQ4C2wKxGEqYxMRAskyetl0BgPxfJfJbCA==", + "version": "0.24.18", + "resolved": "https://registry.npmjs.org/@types/ramda/-/ramda-0.24.18.tgz", + "integrity": "sha512-37umDB+zS6tK+3j0YJxsl7O8T4aYHYO6s1UpADJ/nxMHFjmuSd5XRQryC4IXX3HQ4XzstqAqhk/D+cdxwvqtEQ==", "dev": true }, - "@types/yargs": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-8.0.2.tgz", - "integrity": "sha512-Upj9YsBZRgjEVPvsaeGru48d2JiyzBNZkmkebHyoaQ+UM9wqj/rp5mkilRjSq/Ga45yfd/zwrNuML9f2gGfVpw==" - }, "acorn": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.2.1.tgz", @@ -537,12 +532,6 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, - "colors": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", - "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", - "dev": true - }, "commander": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", @@ -678,9 +667,9 @@ } }, "date-fns": { - "version": "1.28.5", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.28.5.tgz", - "integrity": "sha1-JXz8RdMi30XvVlhmWWfuhBzXP68=", + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.29.0.tgz", + "integrity": "sha512-lbTXWZ6M20cWH8N9S6afb0SBm6tMk+uUg6z3MqHPKE9atmsY3kJkTm8vKe93izJ2B2+q5MV990sM2CHgtAZaOw==", "dev": true }, "date-now": { @@ -1894,21 +1883,21 @@ } }, "jest-get-type": { - "version": "21.0.2", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-21.0.2.tgz", - "integrity": "sha512-4KvNzzXMXeapGaMWd+SL5e47zcMn8KTWjom6Fl3avxVXnbKS7abD1p4xWe4ToAZfgNoYNsQ9Av/mnWMnZK/Z4A==", + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-21.2.0.tgz", + "integrity": "sha512-y2fFw3C+D0yjNSDp7ab1kcd6NUYfy3waPTlD8yWkAtiocJdBRQqNoRqVfMNxgj+IjT0V5cBIHJO0z9vuSSZ43Q==", "dev": true }, "jest-validate": { - "version": "21.1.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-21.1.0.tgz", - "integrity": "sha512-xS0cyErNWpsLFlGkn/b87pk/Mv7J+mCTs8hQ4KmtOIIoM1sHYobXII8AtkoN8FC7E3+Ptxjo+/3xWk6LK1dKcw==", + "version": "21.2.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-21.2.1.tgz", + "integrity": "sha512-k4HLI1rZQjlU+EC682RlQ6oZvLrE5SCh3brseQc24vbZTxzT/k/3urar5QMCVgjadmSO7lECeGdc6YxnM3yEGg==", "dev": true, "requires": { - "chalk": "2.1.0", - "jest-get-type": "21.0.2", + "chalk": "2.3.0", + "jest-get-type": "21.2.0", "leven": "2.1.0", - "pretty-format": "21.1.0" + "pretty-format": "21.2.1" }, "dependencies": { "ansi-styles": { @@ -1921,14 +1910,14 @@ } }, "chalk": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", - "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", "dev": true, "requires": { "ansi-styles": "3.2.0", "escape-string-regexp": "1.0.5", - "supports-color": "4.4.0" + "supports-color": "4.5.0" } }, "has-flag": { @@ -1938,9 +1927,9 @@ "dev": true }, "supports-color": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", - "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", "dev": true, "requires": { "has-flag": "2.0.0" @@ -2059,17 +2048,18 @@ } }, "lint-staged": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-4.2.2.tgz", - "integrity": "sha512-29NaaMLV1vEKJsZQNSoskOQ4hBgVxNoS9+Jy0rKVlR9UXCpAqZbUxmPubc5B5PG29Eg/OxdwOQcfYMAFWrXjiA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-4.3.0.tgz", + "integrity": "sha512-C/Zxslg0VRbsxwmCu977iIs+QyrmW2cyRCPUV5NDFYOH/jtRFHH8ch7ua2fH0voI/nVC3Tpg7DykfgMZySliKw==", "dev": true, "requires": { "app-root-path": "2.0.1", - "chalk": "2.1.0", + "chalk": "2.3.0", + "commander": "2.11.0", "cosmiconfig": "1.1.0", "execa": "0.8.0", "is-glob": "4.0.0", - "jest-validate": "21.1.0", + "jest-validate": "21.2.1", "listr": "0.12.0", "lodash": "4.17.4", "log-symbols": "2.1.0", @@ -2090,16 +2080,22 @@ } }, "chalk": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", - "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", "dev": true, "requires": { "ansi-styles": "3.2.0", "escape-string-regexp": "1.0.5", - "supports-color": "4.4.0" + "supports-color": "4.5.0" } }, + "commander": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", + "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", + "dev": true + }, "execa": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/execa/-/execa-0.8.0.tgz", @@ -2137,9 +2133,9 @@ } }, "supports-color": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", - "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", "dev": true, "requires": { "has-flag": "2.0.0" @@ -2161,12 +2157,12 @@ "is-stream": "1.1.0", "listr-silent-renderer": "1.1.1", "listr-update-renderer": "0.2.0", - "listr-verbose-renderer": "0.4.0", + "listr-verbose-renderer": "0.4.1", "log-symbols": "1.0.2", "log-update": "1.0.2", "ora": "0.2.3", "p-map": "1.2.0", - "rxjs": "5.4.3", + "rxjs": "5.5.2", "stream-to-observable": "0.1.0", "strip-ansi": "3.0.1" }, @@ -2222,14 +2218,14 @@ } }, "listr-verbose-renderer": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/listr-verbose-renderer/-/listr-verbose-renderer-0.4.0.tgz", - "integrity": "sha1-RNwBuww0oDxXIVTU0Izemx3FYg8=", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/listr-verbose-renderer/-/listr-verbose-renderer-0.4.1.tgz", + "integrity": "sha1-ggb0z21S3cWCfl/RSYng6WWTOjU=", "dev": true, "requires": { "chalk": "1.1.3", "cli-cursor": "1.0.2", - "date-fns": "1.28.5", + "date-fns": "1.29.0", "figures": "1.7.0" } }, @@ -2350,7 +2346,7 @@ "integrity": "sha512-zLeLrzMA1A2vRF1e/0Mo+LNINzi6jzBylHj5WqvQ/WK/5WCZt8si9SyN4p9llr/HRYvVR1AoXHRHl4WTHyQAzQ==", "dev": true, "requires": { - "chalk": "2.1.0" + "chalk": "2.3.0" }, "dependencies": { "ansi-styles": { @@ -2363,14 +2359,14 @@ } }, "chalk": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", - "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", "dev": true, "requires": { "ansi-styles": "3.2.0", "escape-string-regexp": "1.0.5", - "supports-color": "4.4.0" + "supports-color": "4.5.0" } }, "has-flag": { @@ -2380,9 +2376,9 @@ "dev": true }, "supports-color": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", - "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", "dev": true, "requires": { "has-flag": "2.0.0" @@ -3039,15 +3035,15 @@ "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=" }, "prettier": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.7.0.tgz", - "integrity": "sha512-kIbA3UE9sYGiVCxlWg92EOHWZqte6EAkC7DS5je6NaL8g3Uw1rWe0eH+UX4Hy5OEiR9aql2vVMHeg6lR4YGxYg==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.7.4.tgz", + "integrity": "sha1-XoYkrpNjyA+V7GRFhOzfVddPk/o=", "dev": true }, "pretty-format": { - "version": "21.1.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-21.1.0.tgz", - "integrity": "sha512-041BVxr2pp7uGG8slfw43ysRXSaBIVqo5Li03BwI3K1/9oENlhkEEYWPkHpDzj7NlJ3GZte+Tv/DId5g2PLduA==", + "version": "21.2.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-21.2.1.tgz", + "integrity": "sha512-ZdWPGYAnYfcVP8yKA3zFjCn8s4/17TeYH28MXuC8vTp0o21eXjbFGcOAXZEaDaOFJjc3h2qa7HQNHNshhvoh2A==", "dev": true, "requires": { "ansi-regex": "3.0.0", @@ -3286,9 +3282,9 @@ } }, "resolve": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.4.0.tgz", - "integrity": "sha512-aW7sVKPufyHqOmyyLzg/J+8606v5nevBgaliIlV7nUpVMsDnoBGV/cbSLNjZAg9q0Cfd/+easKVKQ8vOu8fn1Q==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.5.0.tgz", + "integrity": "sha512-hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw==", "dev": true, "requires": { "path-parse": "1.0.5" @@ -3360,9 +3356,9 @@ } }, "rxjs": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.4.3.tgz", - "integrity": "sha512-fSNi+y+P9ss+EZuV0GcIIqPUK07DEaMRUtLJvdcvMyFjc9dizuDjere+A4V7JrLGnm9iCc+nagV/4QdMTkqC4A==", + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.2.tgz", + "integrity": "sha512-oRYoIKWBU3Ic37fLA5VJu31VqQO4bWubRntcHSJ+cwaDQBwdnZ9x4zmhJfm/nFQ2E82/I4loSioHnACamrKGgA==", "dev": true, "requires": { "symbol-observable": "1.0.4" @@ -3448,114 +3444,6 @@ "require-from-string": "1.2.1", "semver": "5.4.1", "yargs": "4.8.1" - }, - "dependencies": { - "camelcase": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=" - }, - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "requires": { - "path-exists": "2.1.0", - "pinkie-promise": "2.0.1" - } - }, - "load-json-file": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", - "requires": { - "graceful-fs": "4.1.11", - "parse-json": "2.2.0", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "strip-bom": "2.0.0" - } - }, - "os-locale": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", - "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", - "requires": { - "lcid": "1.0.0" - } - }, - "path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", - "requires": { - "graceful-fs": "4.1.11", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" - } - }, - "read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", - "requires": { - "load-json-file": "1.1.0", - "normalize-package-data": "2.4.0", - "path-type": "1.1.0" - } - }, - "read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", - "requires": { - "find-up": "1.1.2", - "read-pkg": "1.1.0" - } - }, - "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", - "requires": { - "is-utf8": "0.2.1" - } - }, - "which-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", - "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=" - }, - "yargs": { - "version": "4.8.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", - "integrity": "sha1-wMQpJMpKqmsObaFznfshZDn53cA=", - "requires": { - "cliui": "3.2.0", - "decamelize": "1.2.0", - "get-caller-file": "1.0.2", - "lodash.assign": "4.2.0", - "os-locale": "1.4.0", - "read-pkg-up": "1.0.1", - "require-directory": "2.1.1", - "require-main-filename": "1.0.1", - "set-blocking": "2.0.0", - "string-width": "1.0.2", - "which-module": "1.0.0", - "window-size": "0.2.0", - "y18n": "3.2.1", - "yargs-parser": "2.4.1" - } - }, - "yargs-parser": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz", - "integrity": "sha1-hVaN488VD/SfpRgl8DqMiA3cxcQ=", - "requires": { - "camelcase": "3.0.0", - "lodash.assign": "4.2.0" - } - } } }, "solhint": { @@ -3893,9 +3781,9 @@ "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=" }, "truffle": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/truffle/-/truffle-4.0.0.tgz", - "integrity": "sha512-EudgMeScNn53XMjrgIoa1f+g17gWazx/POb9YBcg74dX50AlrMSgIoOobyUMoTXVDj3lgQ/yW11u2vnUfGHmYQ==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/truffle/-/truffle-4.0.1.tgz", + "integrity": "sha512-PybO+GMq3AvsfCWfEx4sbuaJlDL19iR8Ff20cO0TtP599N5JbMLlhwlffvVInPgFjP+F11vjSOYj3hT8fONs5A==", "requires": { "mocha": "3.5.3", "original-require": "1.0.1", @@ -3909,36 +3797,74 @@ "dev": true }, "tslib": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.7.1.tgz", - "integrity": "sha1-vIAEFkaRkjp5/oN4u+s9ogF1OOw=", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.8.0.tgz", + "integrity": "sha512-ymKWWZJST0/CkgduC2qkzjMOWr4bouhuURNXCn/inEX0L57BnRG6FhX76o7FOnsjHazCjfU2LKeSrlS2sIKQJg==", "dev": true }, "tslint": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.7.0.tgz", - "integrity": "sha1-wl4NDJL6EgHCvDDoROCOaCtPNVI=", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.8.0.tgz", + "integrity": "sha1-H0mtWy53x2w69N3K5VKuTjYS6xM=", "dev": true, "requires": { "babel-code-frame": "6.26.0", - "colors": "1.1.2", + "builtin-modules": "1.1.1", + "chalk": "2.3.0", "commander": "2.9.0", "diff": "3.2.0", "glob": "7.1.1", "minimatch": "3.0.4", - "resolve": "1.4.0", + "resolve": "1.5.0", "semver": "5.4.1", - "tslib": "1.7.1", - "tsutils": "2.8.2" + "tslib": "1.8.0", + "tsutils": "2.12.2" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.5.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } } }, "tsutils": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.8.2.tgz", - "integrity": "sha1-LBSGukMSYIRbCsb5Aq/Z1wio6mo=", + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.12.2.tgz", + "integrity": "sha1-rVikhl0X7D3bZjG2ylO+FKVlb/M=", "dev": true, "requires": { - "tslib": "1.7.1" + "tslib": "1.8.0" } }, "tty-browserify": { @@ -3962,9 +3888,9 @@ "dev": true }, "typescript": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.5.2.tgz", - "integrity": "sha1-A4qV99m7tCCxvzW6MdTFwd0//jQ=", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.6.1.tgz", + "integrity": "sha1-7znN6ierrAtQAkLWcmq5DgyEZjE=", "dev": true }, "uglify-js": { @@ -4251,50 +4177,109 @@ "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" }, "yargs": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-9.0.1.tgz", - "integrity": "sha1-UqzCP+7Kw0BCB47njAwAf1CF20w=", + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", + "integrity": "sha1-wMQpJMpKqmsObaFznfshZDn53cA=", "requires": { - "camelcase": "4.1.0", "cliui": "3.2.0", "decamelize": "1.2.0", "get-caller-file": "1.0.2", - "os-locale": "2.1.0", - "read-pkg-up": "2.0.0", + "lodash.assign": "4.2.0", + "os-locale": "1.4.0", + "read-pkg-up": "1.0.1", "require-directory": "2.1.1", "require-main-filename": "1.0.1", "set-blocking": "2.0.0", - "string-width": "2.1.1", - "which-module": "2.0.0", + "string-width": "1.0.2", + "which-module": "1.0.0", + "window-size": "0.2.0", "y18n": "3.2.1", - "yargs-parser": "7.0.0" + "yargs-parser": "2.4.1" }, "dependencies": { - "ansi-regex": { + "camelcase": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=" }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" + } }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "strip-bom": "2.0.0" } }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", "requires": { - "ansi-regex": "3.0.0" + "lcid": "1.0.0" + } + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "requires": { + "graceful-fs": "4.1.11", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "requires": { + "load-json-file": "1.1.0", + "normalize-package-data": "2.4.0", + "path-type": "1.1.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "requires": { + "find-up": "1.1.2", + "read-pkg": "1.1.0" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "requires": { + "is-utf8": "0.2.1" + } + }, + "which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=" + }, + "yargs-parser": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz", + "integrity": "sha1-hVaN488VD/SfpRgl8DqMiA3cxcQ=", + "requires": { + "camelcase": "3.0.0", + "lodash.assign": "4.2.0" } } } diff --git a/package.json b/package.json index 2c929d1..6d14c5d 100644 --- a/package.json +++ b/package.json @@ -4,18 +4,14 @@ "description": "SignHash smart contracts", "scripts": { "compile": "run-s compile:ts compile:sol", - "compile:sol": - "truffle compile --contracts_build_directory .cache/contracts", + "compile:sol": "truffle compile --contracts_build_directory .cache/contracts", "compile:ts": "tsc", "test": "run-s compile:sol test:sol test:ts", "test:ts": "run-s compile:ts test:js", - "test:sol": - "truffle test --contracts_build_directory .cache/contracts test/*.sol", - "test:js": - "truffle test --contracts_build_directory .cache/contracts test/*.js", + "test:sol": "truffle test --contracts_build_directory .cache/contracts test/*.sol", + "test:js": "truffle test --contracts_build_directory .cache/contracts test/*.js", "migrate": "truffle migrate --reset --network testrpc", - "testrpc": - "testrpc --mnemonic \"try exile adapt shed width laugh similar duty neglect kick rug require\"", + "testrpc": "testrpc --mnemonic \"try exile adapt shed width laugh similar duty neglect kick rug require\"", "seed": "run-p testrpc migrate", "lint": "run-p -c --aggregate-output lint:solhint lint:tslint", "lint:tslint": "tslint *.ts migrations/*.ts test/*.ts", @@ -24,7 +20,10 @@ "precommit": "lint-staged" }, "lint-staged": { - "*.{ts,json}": ["format", "git add"] + "*.{ts,json}": [ + "format", + "git add" + ] }, "repository": { "type": "git", @@ -46,23 +45,21 @@ }, "homepage": "https://github.com/SignHash/signhash-contracts#readme", "dependencies": { - "@types/yargs": "^8.0.2", "ethereumjs-testrpc": "^4.1.3", - "truffle": "^4.0.0", - "yargs": "^9.0.1" + "truffle": "^4.0.1" }, "devDependencies": { "@types/bignumber.js": "^4.0.3", "@types/chai": "^4.0.4", - "@types/mocha": "^2.2.43", - "@types/ramda": "^0.24.14", + "@types/mocha": "^2.2.44", + "@types/ramda": "^0.24.18", "husky": "^0.14.3", - "lint-staged": "^4.2.2", + "lint-staged": "^4.3.0", "npm-run-all": "^4.1.1", - "prettier": "^1.7.0", + "prettier": "^1.7.4", "ramda": "^0.24.1", "solhint": "^1.1.7", - "tslint": "^5.7.0", - "typescript": "^2.5.2" + "tslint": "^5.8.0", + "typescript": "^2.6.1" } } From d351a93370ca859e506c31faaecb5bce3ed40a29 Mon Sep 17 00:00:00 2001 From: Jakub Stefanski Date: Sun, 5 Nov 2017 22:53:13 +0100 Subject: [PATCH 3/4] Implement basic tips wallet with settlement Also improve TypeScript typings. --- contracts/TipsWallet.sol | 92 ++++++++++++++++++ globals.d.ts | 156 ++---------------------------- index.d.ts | 126 ++++++++++++++++++++++++ migrations/1_initial_migration.ts | 2 + migrations/2_deploy_contracts.ts | 2 + package-lock.json | 6 ++ package.json | 1 + test/helpers.ts | 88 +++++++++++++++++ test/signhash.ts | 1 + test/tipswallet.ts | 143 +++++++++++++++++++++++++++ tsconfig.json | 14 ++- types/truffle/index.d.ts | 70 ++++++++++++++ types/web3/index.d.ts | 47 +++++++++ 13 files changed, 597 insertions(+), 151 deletions(-) create mode 100644 contracts/TipsWallet.sol create mode 100644 index.d.ts create mode 100644 test/tipswallet.ts create mode 100644 types/truffle/index.d.ts create mode 100644 types/web3/index.d.ts diff --git a/contracts/TipsWallet.sol b/contracts/TipsWallet.sol new file mode 100644 index 0000000..30961f8 --- /dev/null +++ b/contracts/TipsWallet.sol @@ -0,0 +1,92 @@ +pragma solidity 0.4.18; + +import "./AddressSet.sol"; + + +contract TipsWallet { + + //--- Definitions + using AddressSet for AddressSet.Data; + + //--- Storage + AddressSet.Data private owners; + + uint256 public lastSettledBalance; + mapping(address => uint256) public settledShares; + + //--- Constructor + function TipsWallet(address[] _owners) public { + require(_owners.length > 0); + + for (uint256 i = 0; i < _owners.length; i++) { + owners.add(_owners[i]); + } + } + + //--- Modifiers + modifier onlyOwners() { + require(owners.contains(msg.sender)); + _; + } + + //--- Fallback + /* solhint-disable no-empty-blocks */ + function() public payable { + // postpone distribution to settlement + // keep the gas usage as low as possible + } + /* solhint-enable no-empty-blocks */ + + //--- Public mutable functions + function withdraw(uint256 value) public { + require(value > 0); + uint256 balance = settledShares[msg.sender]; + + require(value <= balance); + + subShare(msg.sender, value); + msg.sender.transfer(balance); + } + + function settle() public onlyOwners { + if (this.balance > lastSettledBalance) { + uint256 share = (this.balance - lastSettledBalance) / owners.count; + + address owner = owners.head; + for (uint256 i = 0; i < owners.count; i++) { + addShare(owner, share); + owner = owners.getNext(owner); + } + + lastSettledBalance = this.balance; + } + } + + //--- Public view functions + function getOwners() public view returns (address[] result) { + result = new address[](owners.count); + + address current = owners.head; + for (uint256 i = 0; i < result.length; i++) { + result[i] = current; + current = owners.getNext(current); + } + } + + function getUnsettledBalance() public view returns (uint256) { + return this.balance - lastSettledBalance; + } + + //--- Private mutable functions + function addShare(address account, uint256 value) private { + uint256 current = settledShares[account]; + settledShares[account] += value; + assert(settledShares[account] >= current); // check overflow + } + + function subShare(address account, uint256 value) private { + uint256 current = settledShares[account]; + assert(value <= current); // check underflow + settledShares[account] -= value; + } +} diff --git a/globals.d.ts b/globals.d.ts index 6bc0ff7..f83dbe7 100644 --- a/globals.d.ts +++ b/globals.d.ts @@ -1,150 +1,10 @@ -declare interface Web3 { - toAscii(hex: string): string; - fromAscii(ascii: string, padding?: number): string; - sha3(str: string, options?: { encoding: 'hex' }): string; -} - -declare interface ContractBase { - address: string; -} - -declare interface Contract extends ContractBase { - deployed(): Promise; -} - -declare type TransactionOptions = { - from?: string; - gas?: number; - gasPrice?: number; -}; - -declare type TransactionReceipt = { - transactionHash: string; - transactionIndex: number; - blockHash: string; - blockNumber: number; - gasUsed: number; - cumulativeGasUsed: number; - contractAddress: string | null; - logs: [TransactionLog]; -}; - -declare type TransactionLog = { - logIndex: number; - transactionIndex: number; - transactionHash: string; - blockHash: string; - blockNumber: number; - address: string; - type: string; - event: string; - args: any; -}; - -declare type TransactionResult = { - tx: string; - receipt: TransactionReceipt; - logs: [TransactionLog]; -}; - -declare interface MigrationsContract extends Contract { - 'new'(options?: TransactionOptions): Promise; -} - -declare interface AddressSetLibrary extends Contract { - 'new'(options?: TransactionOptions): Promise; -} - -declare interface SignHashContract extends Contract { - 'new'(options?: TransactionOptions): Promise; -} - -declare interface SignHash { - sign(hash: string, options?: TransactionOptions): Promise; - revoke( - hash: string, - options?: TransactionOptions - ): Promise; - - addProof( - method: string, - value: string, - options?: TransactionOptions - ): Promise; - - removeProof( - method: string, - options?: TransactionOptions - ): Promise; - - getSigners(hash: string, maxCount: number): Promise; - - getProof(signer: string, method: string): Promise; -} +import { SignHashArtifacts } from 'signhash'; +import { ContractContextDefinition } from 'truffle'; +import { Web3 } from 'web3'; -declare interface Signed { - hash: string; - signer: string; +declare global { + const artifacts: SignHashArtifacts; + const web3: Web3; + const contract: ContractContextDefinition; + const assert: Chai.Assert; } - -declare interface Revoked { - hash: string; - signer: string; -} - -declare interface ProofAdded { - signer: string; - method: string; - value: string; -} - -declare interface ProofRemoved { - signer: string; - method: string; -} - -declare interface Migrations { - setCompleted( - completed: number, - options?: TransactionOptions - ): Promise; - - upgrade( - address: string, - options?: TransactionOptions - ): Promise; -} - -declare interface AddressSet { - get(): Promise; - - add( - element: string, - options?: TransactionOptions - ): Promise; -} - -declare interface Artifacts { - require(name: './Migrations.sol'): MigrationsContract; - require(name: './AddressSet.sol'): AddressSetLibrary; - require(name: './SignHash.sol'): SignHashContract; - require(name: string): ContractBase; -} - -declare interface Deployer extends Promise { - deploy(object: ContractBase): Promise; - - link( - library: ContractBase, - contracts: ContractBase | [ContractBase] - ): Promise; -} - -interface ContractContextDefinition extends Mocha.IContextDefinition { - (description: string, callback: (accounts: string[]) => void): Mocha.ISuite; -} - -declare const artifacts: Artifacts; -declare const contract: ContractContextDefinition; -declare const assert: Chai.Assert; -declare const web3: Web3; diff --git a/index.d.ts b/index.d.ts new file mode 100644 index 0000000..1672925 --- /dev/null +++ b/index.d.ts @@ -0,0 +1,126 @@ +declare module 'signhash' { + import { BigNumber } from 'bignumber.js'; + + import { + Artifacts, + Contract, + DeployedContractBase, + TransactionOptions, + TransactionResult + } from 'truffle'; + + import { Address } from 'web3'; + + interface MigrationsContract extends Contract { + 'new'(options?: TransactionOptions): Promise; + } + + interface AddressSetLibrary extends Contract { + 'new'(options?: TransactionOptions): Promise; + } + + interface SignHashContract extends Contract { + 'new'(options?: TransactionOptions): Promise; + } + + interface TipsWalletContract extends Contract { + 'new'( + developers: Address[], + options?: TransactionOptions + ): Promise; + } + + interface SignHash extends DeployedContractBase { + sign( + hash: string, + options?: TransactionOptions + ): Promise; + + revoke( + hash: string, + options?: TransactionOptions + ): Promise; + + addProof( + method: string, + value: string, + options?: TransactionOptions + ): Promise; + + removeProof( + method: string, + options?: TransactionOptions + ): Promise; + + getSigners( + hash: string, + maxCount: number | string | BigNumber + ): Promise; + + getProof(signer: Address, method: string): Promise; + } + + interface Signed { + hash: string; + signer: Address; + } + + interface Revoked { + hash: string; + signer: Address; + } + + interface ProofAdded { + signer: Address; + method: string; + value: string; + } + + interface ProofRemoved { + signer: Address; + method: string; + } + + interface TipsWallet extends DeployedContractBase { + getOwners(): Promise; + + getUnsettledBalance(): Promise; + + settledShares(account: Address): Promise; + + settle(options?: TransactionOptions): Promise; + + withdraw( + value: number | string | BigNumber, + options?: TransactionOptions + ): Promise; + } + + interface Migrations extends DeployedContractBase { + setCompleted( + completed: number | string | BigNumber, + options?: TransactionOptions + ): Promise; + + upgrade( + address: Address, + options?: TransactionOptions + ): Promise; + } + + interface AddressSet { + get(): Promise; + + add( + element: Address, + options?: TransactionOptions + ): Promise; + } + + interface SignHashArtifacts extends Artifacts { + require(name: './Migrations.sol'): MigrationsContract; + require(name: './AddressSet.sol'): AddressSetLibrary; + require(name: './SignHash.sol'): SignHashContract; + require(name: './TipsWallet.sol'): TipsWalletContract; + } +} diff --git a/migrations/1_initial_migration.ts b/migrations/1_initial_migration.ts index ba18c06..f8ca956 100644 --- a/migrations/1_initial_migration.ts +++ b/migrations/1_initial_migration.ts @@ -1,3 +1,5 @@ +import { Deployer } from 'truffle'; + const Migrations = artifacts.require('./Migrations.sol'); async function deploy(deployer: Deployer): Promise { diff --git a/migrations/2_deploy_contracts.ts b/migrations/2_deploy_contracts.ts index f93fff1..f63dc89 100644 --- a/migrations/2_deploy_contracts.ts +++ b/migrations/2_deploy_contracts.ts @@ -1,3 +1,5 @@ +import { Deployer } from 'truffle'; + const SignHash = artifacts.require('./SignHash.sol'); async function deploy(deployer: Deployer): Promise { diff --git a/package-lock.json b/package-lock.json index eac52cb..6e7799e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -252,6 +252,12 @@ "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==" }, + "bignumber.js": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-4.1.0.tgz", + "integrity": "sha512-eJzYkFYy9L4JzXsbymsFn3p54D+llV27oTQ+ziJG7WFRheJcNZilgVXMG0LoZtlQSKBsJdWtLFqOD0u+U0jZKA==", + "dev": true + }, "binary-extensions": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.10.0.tgz", diff --git a/package.json b/package.json index 6d14c5d..f816bd1 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "@types/chai": "^4.0.4", "@types/mocha": "^2.2.44", "@types/ramda": "^0.24.18", + "bignumber.js": "^4.1.0", "husky": "^0.14.3", "lint-staged": "^4.3.0", "npm-run-all": "^4.1.1", diff --git a/test/helpers.ts b/test/helpers.ts index de3ca58..28be50f 100644 --- a/test/helpers.ts +++ b/test/helpers.ts @@ -1,4 +1,10 @@ +import { BigNumber } from 'bignumber.js'; import { findLast, propEq } from 'ramda'; +import { TransactionLog, TransactionResult } from 'truffle'; +import { Address, Callback, TxData } from 'web3'; + +const ETH_DECIMALS = 18; +const DEFAULT_ACCEPTABLE_ERROR = web3.toWei(5, 'finney'); export async function assertThrowsInvalidOpcode(func: () => void) { try { @@ -24,9 +30,91 @@ export function assertInvalidOpcode(error: { message: string }) { } } +export function assertNumberEqual( + actual: number | string | BigNumber, + expect: number | string | BigNumber, + decimals: number +) { + const actualNum = new BigNumber(actual); + const expectNum = new BigNumber(expect); + + if (!actualNum.eq(expectNum)) { + const div = decimals ? Math.pow(10, decimals) : 1; + assert.fail( + actualNum.toFixed(), + expectNum.toFixed(), + `${actualNum.div(div).toFixed()} == ${expectNum.div(div).toFixed()}`, + '==' + ); + } +} + +export function assertEtherEqual(actual: any, expect: any) { + return assertNumberEqual(actual, expect, ETH_DECIMALS); +} + +export function assertNumberAlmostEqual( + actual: number | string | BigNumber, + expect: number | string | BigNumber, + epsilon: number | string | BigNumber, + decimals: number +) { + const actualNum = new BigNumber(actual); + const expectNum = new BigNumber(expect); + const epsilonNum = new BigNumber(epsilon); + + if ( + actualNum.lessThan(expectNum.sub(epsilonNum)) || + actualNum.greaterThan(expectNum.add(epsilonNum)) + ) { + const div = decimals ? Math.pow(10, decimals) : 1; + assert.fail( + actualNum.toFixed(), + expectNum.toFixed(), + `${actualNum.div(div).toFixed()} == ${expectNum + .div(div) + .toFixed()} (precision ${epsilonNum.div(div).toFixed()})`, + '==' + ); + } +} + +export function assertEtherAlmostEqual( + actual: number | string | BigNumber, + expect: number | string | BigNumber, + epsilon?: number | string | BigNumber +) { + epsilon = epsilon || DEFAULT_ACCEPTABLE_ERROR; + + return assertNumberAlmostEqual(actual, expect, epsilon, ETH_DECIMALS); +} + +export function toEther(num: number | string) { + return web3.toWei(num, 'ether'); +} + export function findLastLog( trans: TransactionResult, event: string ): TransactionLog { return findLast(propEq('event', event))(trans.logs); } + +export function sendTransaction(txData: TxData) { + return promisify(cb => web3.eth.sendTransaction(txData, cb)); +} + +export function getBalance(account: Address) { + return promisify(cb => web3.eth.getBalance(account, cb)); +} + +export function promisify(fn: (cb: Callback) => void): Promise { + return new Promise((resolve, reject) => + fn((err, res) => { + if (err) { + reject(err); + } + resolve(res); + }) + ); +} diff --git a/test/signhash.ts b/test/signhash.ts index 01f176a..789dc32 100644 --- a/test/signhash.ts +++ b/test/signhash.ts @@ -1,3 +1,4 @@ +import { ProofAdded, ProofRemoved, Revoked, Signed, SignHash } from 'signhash'; import { assertThrowsInvalidOpcode, findLastLog } from './helpers'; const SignHashContract = artifacts.require('./SignHash.sol'); diff --git a/test/tipswallet.ts b/test/tipswallet.ts new file mode 100644 index 0000000..e3ee8ad --- /dev/null +++ b/test/tipswallet.ts @@ -0,0 +1,143 @@ +import * as R from 'ramda'; +import { TipsWallet } from 'signhash'; + +import { + assertEtherAlmostEqual, + assertEtherEqual, + assertThrowsInvalidOpcode, + getBalance, + sendTransaction, + toEther +} from './helpers'; + +const TipsWalletContract = artifacts.require('./TipsWallet.sol'); + +contract('TipsWallet', accounts => { + const owners = accounts.slice(0, 2); + const deployerAccount = accounts[9]; + + let instance: TipsWallet; + + async function tip(value: number | string) { + await sendTransaction({ + from: deployerAccount, + to: instance.address, + value + }); + } + + async function assertSettledShares(expected: [number | string]) { + for (let i = 0; i < expected.length; i++) { + const share = await instance.settledShares(owners[i]); + assertEtherEqual(share, expected[i]); + } + } + + beforeEach(async () => { + instance = await TipsWalletContract.new(owners, { + from: deployerAccount + }); + }); + + describe('#ctor', () => { + it('should set owners', async () => { + assert.deepEqual(await instance.getOwners(), owners); + }); + + it('should not allow empty list of owners', async () => { + await assertThrowsInvalidOpcode(async () => { + await TipsWalletContract.new([], { + from: deployerAccount + }); + }); + }); + }); + + describe('#fallback', () => { + it('should accept deposit with 22000 gas limit', async () => { + const value = toEther(1); + await sendTransaction({ + from: deployerAccount, + gas: 22000, + to: instance.address, + value + }); + + assertEtherEqual(value, await getBalance(instance.address)); + }); + }); + + describe('#settle', () => { + it('should not modify shares if balance is zero', async () => { + await instance.settle({ from: owners[0] }); + await assertSettledShares([0, 0]); + assertEtherEqual(await instance.getUnsettledBalance(), 0); + }); + + it('should divide single tip amongst owners', async () => { + const amount = 1; + await tip(toEther(amount)); + await instance.settle({ from: owners[0] }); + const share = toEther(amount / owners.length); + + await assertSettledShares([share, share]); + assertEtherEqual(await instance.getUnsettledBalance(), 0); + }); + + it('should divide multiple tips amongst owners', async () => { + const tips = [1, 2, 3]; + await tips.forEach(async amount => await tip(toEther(amount))); + await instance.settle({ from: owners[0] }); + const share = toEther(R.sum(tips) / owners.length); + + await assertSettledShares([share, share]); + assertEtherEqual(await instance.getUnsettledBalance(), 0); + }); + + it('should not allow to settle already settled balance', async () => { + const amount = 1; + await tip(toEther(amount)); + await instance.settle({ from: owners[0] }); + await instance.settle({ from: owners[0] }); + const share = toEther(amount / owners.length); + + await assertSettledShares([share, share]); + assertEtherEqual(await instance.getUnsettledBalance(), 0); + }); + + it('should throw when called by non-owner', async () => { + await assertThrowsInvalidOpcode(async () => { + await instance.settle({ from: deployerAccount }); + }); + }); + }); + + describe('#withdraw', () => { + context('after settlement of 1 ether', () => { + const amount = 1; + + beforeEach(async () => { + await tip(toEther(amount)); + await instance.settle({ from: owners[0] }); + }); + + it('should transfer 0.5 ETH to sender', async () => { + const prevBalance = await getBalance(owners[0]); + + const share = await instance.settledShares(owners[0]); + await instance.withdraw(share.toFixed(), { from: owners[0] }); + + const balanceDiff = (await getBalance(owners[0])).sub(prevBalance); + assertEtherAlmostEqual(share, balanceDiff); + }); + + it('should leave 0.5 ETH for other owner', async () => { + const share = await instance.settledShares(owners[0]); + await instance.withdraw(share.toFixed(), { from: owners[0] }); + + const remainingShare = await instance.settledShares(owners[1]); + assertEtherEqual(remainingShare, await getBalance(instance.address)); + }); + }); + }); +}); diff --git a/tsconfig.json b/tsconfig.json index 04b5451..7b6f90f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,9 +7,17 @@ "target": "es2017", "baseUrl": ".", "strict": true, - "typeRoots": ["./node_modules/@types"], - "types": ["bignumber.js", "chai", "mocha"] + "typeRoots": ["./node_modules/@types", "types"], + "types": ["bignumber.js", "chai", "mocha", "web3", "truffle"], + "paths": { + "@*": ["./*"] + } }, "lib": ["es2015"], - "include": ["./globals.d.ts", "./test/**/*", "./migrations/**/*"] + "include": [ + "./index.d.ts", + "./globals.d.ts", + "./test/**/*", + "./migrations/**/*" + ] } diff --git a/types/truffle/index.d.ts b/types/truffle/index.d.ts new file mode 100644 index 0000000..508e9c1 --- /dev/null +++ b/types/truffle/index.d.ts @@ -0,0 +1,70 @@ +declare module 'truffle' { + import { BigNumber } from 'bignumber.js'; + import { Address } from 'web3'; + + interface ContractBase { + address: Address; + } + + interface DeployedContractBase extends ContractBase { + balance(): Promise; + } + + interface Contract extends ContractBase { + deployed(): Promise; + } + + interface Artifacts { + require(name: string): ContractBase; + } + + interface Deployer extends Promise { + deploy(object: ContractBase): Promise; + + link( + library: ContractBase, + contracts: ContractBase | [ContractBase] + ): Promise; + } + + interface ContractContextDefinition extends Mocha.IContextDefinition { + ( + description: string, + callback: (accounts: Address[]) => void + ): Mocha.ISuite; + } + type TransactionOptions = { + from?: Address; + gas?: number | string | BigNumber; + gasPrice?: number | string | BigNumber; + }; + + type TransactionReceipt = { + transactionHash: string; + transactionIndex: number; + blockHash: string; + blockNumber: number; + gasUsed: number; + cumulativeGasUsed: number; + contractAddress?: Address; + logs: [TransactionLog]; + }; + + type TransactionLog = { + logIndex: number; + transactionIndex: number; + transactionHash: string; + blockHash: string; + blockNumber: number; + address: Address; + type: string; + event: string; + args: any; + }; + + type TransactionResult = { + tx: string; + receipt: TransactionReceipt; + logs: [TransactionLog]; + }; +} diff --git a/types/web3/index.d.ts b/types/web3/index.d.ts new file mode 100644 index 0000000..522545f --- /dev/null +++ b/types/web3/index.d.ts @@ -0,0 +1,47 @@ +declare module 'web3' { + import { BigNumber } from 'bignumber.js'; + + type Callback = (err: Error | null, value: T) => void; + + type Address = string; + + type Unit = + | 'kwei' + | 'ada' + | 'mwei' + | 'babbage' + | 'gwei' + | 'shannon' + | 'szabo' + | 'finney' + | 'ether' + | 'kether' + | 'grand' + | 'einstein' + | 'mether' + | 'gether' + | 'tether'; + + interface TxData { + from: Address; + to?: Address; + value?: number | string | BigNumber; + gas?: number | string | BigNumber; + gasPrice?: number | string | BigNumber; + data?: string; + nonce?: number | string | BigNumber; + } + + interface Web3 { + toWei(amount: number | string, unit: Unit): string; + toAscii(hex: string): string; + fromAscii(ascii: string, padding?: number): string; + sha3(str: string, options?: { encoding: 'hex' }): string; + + eth: { + sendTransaction(txData: TxData, callback: Callback): void; + + getBalance(account: Address, callback: Callback): BigNumber; + }; + } +} From cf76560f5baa5f0280f35761de09d5df37f43b12 Mon Sep 17 00:00:00 2001 From: Jakub Stefanski Date: Sun, 5 Nov 2017 23:13:32 +0100 Subject: [PATCH 4/4] Remove obsolete bignumber.js typings --- package-lock.json | 6 ------ package.json | 1 - 2 files changed, 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6e7799e..a3a57bd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,12 +4,6 @@ "lockfileVersion": 1, "requires": true, "dependencies": { - "@types/bignumber.js": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@types/bignumber.js/-/bignumber.js-4.0.3.tgz", - "integrity": "sha512-KoJPKjhlWBry4fk8qcIufXFOU+zcZBfkHQWKbnAMQTMoe2GDeLpjSQHS+22gv+dg7gKdTP2WCjSeCVnfj8e+Gw==", - "dev": true - }, "@types/chai": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.0.4.tgz", diff --git a/package.json b/package.json index f816bd1..f2282a9 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,6 @@ "truffle": "^4.0.1" }, "devDependencies": { - "@types/bignumber.js": "^4.0.3", "@types/chai": "^4.0.4", "@types/mocha": "^2.2.44", "@types/ramda": "^0.24.18",