Compare commits
1 Commits
spencer/re
...
spencer/ac
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9e293b822c |
315
package-lock.json
generated
315
package-lock.json
generated
@@ -19,8 +19,6 @@
|
||||
"@angular/platform-browser-dynamic": "~10.2.0",
|
||||
"@angular/router": "~10.2.0",
|
||||
"@angular/service-worker": "~10.2.0",
|
||||
"@cicnet/cic-client-meta": "^0.0.11",
|
||||
"@cicnet/crdt-meta": "^0.0.10",
|
||||
"@cicnet/schemas-data-validator": "*",
|
||||
"@popperjs/core": "^2.5.4",
|
||||
"bootstrap": "^4.5.3",
|
||||
@@ -1976,178 +1974,6 @@
|
||||
"to-fast-properties": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@cicnet/cic-client-meta": {
|
||||
"version": "0.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@cicnet/cic-client-meta/-/cic-client-meta-0.0.11.tgz",
|
||||
"integrity": "sha512-RL9CPXkWQBQzaqMoldnENC/xqinIMyWNSsejs9+qkFOWbAvC4inLdpjjCaooyvLpIZGHF9cLjxHiAdBMR9L8sQ==",
|
||||
"dependencies": {
|
||||
"@cicnet/crdt-meta": "^0.0.10",
|
||||
"@ethereumjs/tx": "^3.0.0-beta.1",
|
||||
"automerge": "^0.14.1",
|
||||
"colors": "^1.4.0",
|
||||
"ethereumjs-wallet": "^1.0.1",
|
||||
"ini": "^1.3.8",
|
||||
"openpgp": "^4.10.8",
|
||||
"pg": "^8.4.2",
|
||||
"sqlite3": "^5.0.0",
|
||||
"yargs": "^16.1.0"
|
||||
},
|
||||
"bin": {
|
||||
"meta-get": "bin/get.js",
|
||||
"meta-set": "bin/set.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.16.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@cicnet/cic-client-meta/node_modules/ansi-regex": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
|
||||
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@cicnet/cic-client-meta/node_modules/ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dependencies": {
|
||||
"color-convert": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/@cicnet/cic-client-meta/node_modules/cliui": {
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
|
||||
"integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
|
||||
"dependencies": {
|
||||
"string-width": "^4.2.0",
|
||||
"strip-ansi": "^6.0.0",
|
||||
"wrap-ansi": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@cicnet/cic-client-meta/node_modules/color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dependencies": {
|
||||
"color-name": "~1.1.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@cicnet/cic-client-meta/node_modules/color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||
},
|
||||
"node_modules/@cicnet/cic-client-meta/node_modules/emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
|
||||
},
|
||||
"node_modules/@cicnet/cic-client-meta/node_modules/is-fullwidth-code-point": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@cicnet/cic-client-meta/node_modules/string-width": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
|
||||
"integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==",
|
||||
"dependencies": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@cicnet/cic-client-meta/node_modules/strip-ansi": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
|
||||
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@cicnet/cic-client-meta/node_modules/wrap-ansi": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
"string-width": "^4.1.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/@cicnet/cic-client-meta/node_modules/y18n": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@cicnet/cic-client-meta/node_modules/yargs": {
|
||||
"version": "16.2.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
|
||||
"integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
|
||||
"dependencies": {
|
||||
"cliui": "^7.0.2",
|
||||
"escalade": "^3.1.1",
|
||||
"get-caller-file": "^2.0.5",
|
||||
"require-directory": "^2.1.1",
|
||||
"string-width": "^4.2.0",
|
||||
"y18n": "^5.0.5",
|
||||
"yargs-parser": "^20.2.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@cicnet/cic-client-meta/node_modules/yargs-parser": {
|
||||
"version": "20.2.7",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.7.tgz",
|
||||
"integrity": "sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw==",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@cicnet/crdt-meta": {
|
||||
"version": "0.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@cicnet/crdt-meta/-/crdt-meta-0.0.10.tgz",
|
||||
"integrity": "sha512-f+H6BQA2tE718KuNYiNzrDJN4wY00zeuhXM6aPKJUX6nryzX9g2r0yf8iDhkz+Fts1R6M7Riz73MfFEa8fgvsw==",
|
||||
"dependencies": {
|
||||
"automerge": "^0.14.2",
|
||||
"ini": "^1.3.8",
|
||||
"openpgp": "^4.10.8",
|
||||
"readline-sync": "^1.4.10"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.16.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@cicnet/schemas-data-validator": {
|
||||
"version": "1.0.0-alpha.3",
|
||||
"resolved": "https://registry.npmjs.org/@cicnet/schemas-data-validator/-/schemas-data-validator-1.0.0-alpha.3.tgz",
|
||||
@@ -15174,14 +15000,6 @@
|
||||
"node": ">=8.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/readline-sync": {
|
||||
"version": "1.4.10",
|
||||
"resolved": "https://registry.npmjs.org/readline-sync/-/readline-sync-1.4.10.tgz",
|
||||
"integrity": "sha512-gNva8/6UAe8QYepIQH/jQ2qn91Qj0B9sYjMBBs3QOB8F2CXcKgLxQaJRP76sWVRQt+QU+8fAkCbCvjjMFu7Ycw==",
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/reflect-metadata": {
|
||||
"version": "0.1.13",
|
||||
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz",
|
||||
@@ -22010,134 +21828,6 @@
|
||||
"to-fast-properties": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"@cicnet/cic-client-meta": {
|
||||
"version": "0.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@cicnet/cic-client-meta/-/cic-client-meta-0.0.11.tgz",
|
||||
"integrity": "sha512-RL9CPXkWQBQzaqMoldnENC/xqinIMyWNSsejs9+qkFOWbAvC4inLdpjjCaooyvLpIZGHF9cLjxHiAdBMR9L8sQ==",
|
||||
"requires": {
|
||||
"@cicnet/crdt-meta": "^0.0.10",
|
||||
"@ethereumjs/tx": "^3.0.0-beta.1",
|
||||
"automerge": "^0.14.1",
|
||||
"colors": "^1.4.0",
|
||||
"ethereumjs-wallet": "^1.0.1",
|
||||
"ini": "^1.3.8",
|
||||
"openpgp": "^4.10.8",
|
||||
"pg": "^8.4.2",
|
||||
"sqlite3": "^5.0.0",
|
||||
"yargs": "^16.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-regex": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
|
||||
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg=="
|
||||
},
|
||||
"ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"requires": {
|
||||
"color-convert": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"cliui": {
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
|
||||
"integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
|
||||
"requires": {
|
||||
"string-width": "^4.2.0",
|
||||
"strip-ansi": "^6.0.0",
|
||||
"wrap-ansi": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"requires": {
|
||||
"color-name": "~1.1.4"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||
},
|
||||
"emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
|
||||
},
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
|
||||
},
|
||||
"string-width": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
|
||||
"integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==",
|
||||
"requires": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
|
||||
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
|
||||
"requires": {
|
||||
"ansi-regex": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"wrap-ansi": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
||||
"requires": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
"string-width": "^4.1.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"y18n": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="
|
||||
},
|
||||
"yargs": {
|
||||
"version": "16.2.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
|
||||
"integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
|
||||
"requires": {
|
||||
"cliui": "^7.0.2",
|
||||
"escalade": "^3.1.1",
|
||||
"get-caller-file": "^2.0.5",
|
||||
"require-directory": "^2.1.1",
|
||||
"string-width": "^4.2.0",
|
||||
"y18n": "^5.0.5",
|
||||
"yargs-parser": "^20.2.2"
|
||||
}
|
||||
},
|
||||
"yargs-parser": {
|
||||
"version": "20.2.7",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.7.tgz",
|
||||
"integrity": "sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@cicnet/crdt-meta": {
|
||||
"version": "0.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@cicnet/crdt-meta/-/crdt-meta-0.0.10.tgz",
|
||||
"integrity": "sha512-f+H6BQA2tE718KuNYiNzrDJN4wY00zeuhXM6aPKJUX6nryzX9g2r0yf8iDhkz+Fts1R6M7Riz73MfFEa8fgvsw==",
|
||||
"requires": {
|
||||
"automerge": "^0.14.2",
|
||||
"ini": "^1.3.8",
|
||||
"openpgp": "^4.10.8",
|
||||
"readline-sync": "^1.4.10"
|
||||
}
|
||||
},
|
||||
"@cicnet/schemas-data-validator": {
|
||||
"version": "1.0.0-alpha.3",
|
||||
"resolved": "https://registry.npmjs.org/@cicnet/schemas-data-validator/-/schemas-data-validator-1.0.0-alpha.3.tgz",
|
||||
@@ -33212,11 +32902,6 @@
|
||||
"picomatch": "^2.2.1"
|
||||
}
|
||||
},
|
||||
"readline-sync": {
|
||||
"version": "1.4.10",
|
||||
"resolved": "https://registry.npmjs.org/readline-sync/-/readline-sync-1.4.10.tgz",
|
||||
"integrity": "sha512-gNva8/6UAe8QYepIQH/jQ2qn91Qj0B9sYjMBBs3QOB8F2CXcKgLxQaJRP76sWVRQt+QU+8fAkCbCvjjMFu7Ycw=="
|
||||
},
|
||||
"reflect-metadata": {
|
||||
"version": "0.1.13",
|
||||
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz",
|
||||
|
||||
@@ -33,8 +33,6 @@
|
||||
"@angular/platform-browser-dynamic": "~10.2.0",
|
||||
"@angular/router": "~10.2.0",
|
||||
"@angular/service-worker": "~10.2.0",
|
||||
"@cicnet/cic-client-meta": "^0.0.11",
|
||||
"@cicnet/crdt-meta": "^0.0.10",
|
||||
"@cicnet/schemas-data-validator": "*",
|
||||
"@popperjs/core": "^2.5.4",
|
||||
"bootstrap": "^4.5.3",
|
||||
@@ -87,8 +85,5 @@
|
||||
"hooks": {
|
||||
"pre-commit": "pretty-quick --staged & ng lint"
|
||||
}
|
||||
},
|
||||
"browser":{
|
||||
"child_process": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ export const environment = {
|
||||
function setConfigs(configs): void {
|
||||
writeFile(targetPath, configs, err => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
throw console.error(err);
|
||||
} else {
|
||||
console.log(colors.green(`Wrote variables to '${targetPath}`));
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { environment } from '@src/environments/environment';
|
||||
import Web3 from 'web3';
|
||||
import { Web3Service } from '@app/_services/web3.service';
|
||||
|
||||
const abi: Array<any> = require('@src/assets/js/block-sync/data/AccountsIndex.json');
|
||||
const web3: Web3 = Web3Service.getInstance();
|
||||
const web3: Web3 = new Web3(environment.web3Provider);
|
||||
|
||||
export class AccountIndex {
|
||||
contractAddress: string;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import Web3 from 'web3';
|
||||
import { Web3Service } from '@app/_services/web3.service';
|
||||
import { environment } from '@src/environments/environment';
|
||||
|
||||
const abi: Array<any> = require('@src/assets/js/block-sync/data/TokenUniqueSymbolIndex.json');
|
||||
const web3: Web3 = Web3Service.getInstance();
|
||||
const web3: Web3 = new Web3(environment.web3Provider);
|
||||
|
||||
export class TokenRegistry {
|
||||
contractAddress: string;
|
||||
|
||||
@@ -1151,7 +1151,7 @@ export class MockBackendInterceptor implements HttpInterceptor {
|
||||
const queriedCategory: Category = categories.find((category) =>
|
||||
category.products.includes(stringFromUrl())
|
||||
);
|
||||
return ok(queriedCategory.name || 'other');
|
||||
return ok(queriedCategory.name);
|
||||
}
|
||||
|
||||
function getAreaNames(): Observable<HttpResponse<any>> {
|
||||
@@ -1163,7 +1163,7 @@ export class MockBackendInterceptor implements HttpInterceptor {
|
||||
const queriedAreaName: AreaName = areaNames.find((areaName) =>
|
||||
areaName.locations.includes(stringFromUrl())
|
||||
);
|
||||
return ok(queriedAreaName.name || 'other');
|
||||
return ok(queriedAreaName.name);
|
||||
}
|
||||
|
||||
function getAreaTypes(): Observable<HttpResponse<any>> {
|
||||
@@ -1175,7 +1175,7 @@ export class MockBackendInterceptor implements HttpInterceptor {
|
||||
const queriedAreaType: AreaType = areaTypes.find((areaType) =>
|
||||
areaType.area.includes(stringFromUrl())
|
||||
);
|
||||
return ok(queriedAreaType.name || 'other');
|
||||
return ok(queriedAreaType.name);
|
||||
}
|
||||
|
||||
function getAccountTypes(): Observable<HttpResponse<any>> {
|
||||
|
||||
@@ -4,7 +4,7 @@ async function personValidation(person: any): Promise<void> {
|
||||
const personValidationErrors: any = await validatePerson(person);
|
||||
|
||||
if (personValidationErrors) {
|
||||
personValidationErrors.map((error) => console.error(`${error.message}`, person, error));
|
||||
personValidationErrors.map((error) => console.error(`${error.message}`));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ async function vcardValidation(vcard: any): Promise<void> {
|
||||
const vcardValidationErrors: any = await validateVcard(vcard);
|
||||
|
||||
if (vcardValidationErrors) {
|
||||
vcardValidationErrors.map((error) => console.error(`${error.message}`, vcard, error));
|
||||
vcardValidationErrors.map((error) => console.error(`${error.message}`));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ interface Token {
|
||||
address: string;
|
||||
supply: string;
|
||||
decimals: string;
|
||||
reserves?: {
|
||||
reserves: {
|
||||
'0xa686005CE37Dce7738436256982C3903f2E4ea8E'?: {
|
||||
weight: string;
|
||||
balance: string;
|
||||
|
||||
2
src/app/_pgp/index.ts
Normal file
2
src/app/_pgp/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from '@app/_pgp/pgp-key-store';
|
||||
export * from '@app/_pgp/pgp-signer';
|
||||
7
src/app/_pgp/pgp-key-store.spec.ts
Normal file
7
src/app/_pgp/pgp-key-store.spec.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { MutablePgpKeyStore } from '@app/_pgp/pgp-key-store';
|
||||
|
||||
describe('PgpKeyStore', () => {
|
||||
it('should create an instance', () => {
|
||||
expect(new MutablePgpKeyStore()).toBeTruthy();
|
||||
});
|
||||
});
|
||||
169
src/app/_pgp/pgp-key-store.ts
Normal file
169
src/app/_pgp/pgp-key-store.ts
Normal file
@@ -0,0 +1,169 @@
|
||||
import { KeyStore } from 'cic-client-meta';
|
||||
// TODO should we put this on the mutable key store object
|
||||
import * as openpgp from 'openpgp';
|
||||
const keyring = new openpgp.Keyring();
|
||||
|
||||
interface MutableKeyStore extends KeyStore {
|
||||
loadKeyring(): void;
|
||||
importKeyPair(publicKey: any, privateKey: any): Promise<void>;
|
||||
importPublicKey(publicKey: any): void;
|
||||
importPrivateKey(privateKey: any): Promise<void>;
|
||||
getPublicKeys(): Array<any>;
|
||||
getTrustedKeys(): Array<any>;
|
||||
getTrustedActiveKeys(): Array<any>;
|
||||
getEncryptKeys(): Array<any>;
|
||||
getPrivateKeys(): Array<any>;
|
||||
getPrivateKey(): any;
|
||||
isValidKey(key: any): Promise<boolean>;
|
||||
isEncryptedPrivateKey(privateKey: any): Promise<boolean>;
|
||||
getFingerprint(): string;
|
||||
getKeyId(key: any): string;
|
||||
getPrivateKeyId(): string;
|
||||
getKeysForId(keyId: string): Array<any>;
|
||||
getPublicKeyForId(keyId: string): any;
|
||||
getPrivateKeyForId(keyId: string): any;
|
||||
getPublicKeyForSubkeyId(subkeyId: string): any;
|
||||
getPublicKeysForAddress(address: string): Array<any>;
|
||||
removeKeysForId(keyId: string): Array<any>;
|
||||
removePublicKeyForId(keyId: string): any;
|
||||
removePublicKey(publicKey: any): any;
|
||||
clearKeysInKeyring(): void;
|
||||
sign(plainText: string): Promise<any>;
|
||||
}
|
||||
|
||||
class MutablePgpKeyStore implements MutableKeyStore {
|
||||
async loadKeyring(): Promise<void> {
|
||||
await keyring.load();
|
||||
await keyring.store();
|
||||
}
|
||||
|
||||
async importKeyPair(publicKey: any, privateKey: any): Promise<void> {
|
||||
await keyring.publicKeys.importKey(publicKey);
|
||||
await keyring.privateKeys.importKey(privateKey);
|
||||
}
|
||||
|
||||
importPublicKey(publicKey: any): void {
|
||||
keyring.publicKeys.importKey(publicKey);
|
||||
}
|
||||
|
||||
async importPrivateKey(privateKey: any): Promise<void> {
|
||||
await keyring.privateKeys.importKey(privateKey);
|
||||
}
|
||||
|
||||
getPublicKeys(): Array<any> {
|
||||
return keyring.publicKeys.keys;
|
||||
}
|
||||
|
||||
getTrustedKeys(): Array<any> {
|
||||
return keyring.publicKeys.keys;
|
||||
}
|
||||
|
||||
getTrustedActiveKeys(): Array<any> {
|
||||
return keyring.publicKeys.keys;
|
||||
}
|
||||
|
||||
getEncryptKeys(): Array<any> {
|
||||
return [];
|
||||
}
|
||||
|
||||
getPrivateKeys(): Array<any> {
|
||||
return keyring.privateKeys.keys;
|
||||
}
|
||||
|
||||
getPrivateKey(): any {
|
||||
return keyring.privateKeys && keyring.privateKeys.keys[0];
|
||||
}
|
||||
|
||||
async isValidKey(key): Promise<boolean> {
|
||||
// There is supposed to be an openpgp.readKey() method but I can't find it?
|
||||
const testKey = await openpgp.key.readArmored(key);
|
||||
return !testKey.err;
|
||||
}
|
||||
|
||||
async isEncryptedPrivateKey(privateKey: any): Promise<boolean> {
|
||||
const imported = await openpgp.key.readArmored(privateKey);
|
||||
for (const key of imported.keys) {
|
||||
if (key.isDecrypted()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
getFingerprint(): string {
|
||||
// TODO Handle multiple keys
|
||||
return (
|
||||
keyring.privateKeys &&
|
||||
keyring.privateKeys.keys[0] &&
|
||||
keyring.privateKeys.keys[0].keyPacket &&
|
||||
keyring.privateKeys.keys[0].keyPacket.fingerprint
|
||||
);
|
||||
}
|
||||
|
||||
getKeyId(key: any): string {
|
||||
return key.getKeyId().toHex();
|
||||
}
|
||||
|
||||
getPrivateKeyId(): string {
|
||||
// TODO is there a library that comes with angular for doing this?
|
||||
return (
|
||||
keyring.privateKeys &&
|
||||
keyring.privateKeys.keys[0] &&
|
||||
keyring.privateKeys.keys[0].getKeyId().toHex()
|
||||
);
|
||||
}
|
||||
|
||||
getKeysForId(keyId: string): Array<any> {
|
||||
return keyring.getKeysForId(keyId);
|
||||
}
|
||||
|
||||
getPublicKeyForId(keyId): any {
|
||||
return keyring.publicKeys.getForId(keyId);
|
||||
}
|
||||
|
||||
getPrivateKeyForId(keyId): any {
|
||||
return keyring.privateKeys.getForId(keyId);
|
||||
}
|
||||
|
||||
getPublicKeyForSubkeyId(subkeyId): any {
|
||||
return keyring.publicKeys.getForId(subkeyId, true);
|
||||
}
|
||||
|
||||
getPublicKeysForAddress(address): Array<any> {
|
||||
return keyring.publicKeys.getForAddress(address);
|
||||
}
|
||||
|
||||
removeKeysForId(keyId): Array<any> {
|
||||
return keyring.removeKeysForId(keyId);
|
||||
}
|
||||
|
||||
removePublicKeyForId(keyId): any {
|
||||
return keyring.publicKeys.removeForId(keyId);
|
||||
}
|
||||
|
||||
removePublicKey(publicKey: any): any {
|
||||
const keyId = publicKey.getKeyId().toHex();
|
||||
return keyring.publicKeys.removeForId(keyId);
|
||||
}
|
||||
|
||||
clearKeysInKeyring(): void {
|
||||
keyring.clear();
|
||||
}
|
||||
|
||||
async sign(plainText): Promise<any> {
|
||||
const privateKey = this.getPrivateKey();
|
||||
if (!privateKey.isDecrypted()) {
|
||||
const password = window.prompt('password');
|
||||
await privateKey.decrypt(password);
|
||||
}
|
||||
const opts = {
|
||||
message: openpgp.message.fromText(plainText),
|
||||
privateKeys: [privateKey],
|
||||
detached: true,
|
||||
};
|
||||
const signatureObject = await openpgp.sign(opts);
|
||||
return signatureObject.signature;
|
||||
}
|
||||
}
|
||||
|
||||
export { MutablePgpKeyStore, MutableKeyStore };
|
||||
9
src/app/_pgp/pgp-signer.spec.ts
Normal file
9
src/app/_pgp/pgp-signer.spec.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { PGPSigner } from '@app/_pgp/pgp-signer';
|
||||
import { MutableKeyStore, MutablePgpKeyStore } from '@app/_pgp/pgp-key-store';
|
||||
const keystore: MutableKeyStore = new MutablePgpKeyStore();
|
||||
|
||||
describe('PgpSigner', () => {
|
||||
it('should create an instance', () => {
|
||||
expect(new PGPSigner(keystore)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
114
src/app/_pgp/pgp-signer.ts
Normal file
114
src/app/_pgp/pgp-signer.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
import { MutableKeyStore } from '@app/_pgp/pgp-key-store';
|
||||
import { LoggingService } from '@app/_services/logging.service';
|
||||
|
||||
const openpgp = require('openpgp');
|
||||
|
||||
interface Signable {
|
||||
digest(): string;
|
||||
}
|
||||
|
||||
interface Signature {
|
||||
engine: string;
|
||||
algo: string;
|
||||
data: string;
|
||||
digest: string;
|
||||
}
|
||||
|
||||
interface Signer {
|
||||
onsign(signature: Signature): void;
|
||||
onverify(flag: boolean): void;
|
||||
fingerprint(): string;
|
||||
prepare(material: Signable): boolean;
|
||||
verify(digest: string, signature: Signature): void;
|
||||
sign(digest: string): Promise<void>;
|
||||
}
|
||||
|
||||
class PGPSigner implements Signer {
|
||||
engine = 'pgp';
|
||||
algo = 'sha256';
|
||||
dgst: string;
|
||||
signature: Signature;
|
||||
keyStore: MutableKeyStore;
|
||||
onsign: (signature: Signature) => void;
|
||||
onverify: (flag: boolean) => void;
|
||||
loggingService: LoggingService;
|
||||
|
||||
constructor(keyStore: MutableKeyStore) {
|
||||
this.keyStore = keyStore;
|
||||
this.onsign = (signature: Signature) => {};
|
||||
this.onverify = (flag: boolean) => {};
|
||||
}
|
||||
|
||||
public fingerprint(): string {
|
||||
return this.keyStore.getFingerprint();
|
||||
}
|
||||
|
||||
public prepare(material: Signable): boolean {
|
||||
this.dgst = material.digest();
|
||||
return true;
|
||||
}
|
||||
|
||||
public verify(digest: string, signature: Signature): void {
|
||||
openpgp.signature
|
||||
.readArmored(signature.data)
|
||||
.then((sig) => {
|
||||
const opts = {
|
||||
message: openpgp.cleartext.fromText(digest),
|
||||
publicKeys: this.keyStore.getTrustedKeys(),
|
||||
signature: sig,
|
||||
};
|
||||
openpgp.verify(opts).then((v) => {
|
||||
let i = 0;
|
||||
for (i = 0; i < v.signatures.length; i++) {
|
||||
const s = v.signatures[i];
|
||||
if (s.valid) {
|
||||
this.onverify(s);
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.loggingService.sendErrorLevelMessage(
|
||||
`Checked ${i} signature(s) but none valid`,
|
||||
this,
|
||||
{ error: '404 Not found!' }
|
||||
);
|
||||
this.onverify(false);
|
||||
});
|
||||
})
|
||||
.catch((e) => {
|
||||
this.loggingService.sendErrorLevelMessage(e.message, this, { error: e });
|
||||
this.onverify(false);
|
||||
});
|
||||
}
|
||||
|
||||
public async sign(digest: string): Promise<void> {
|
||||
const m = openpgp.cleartext.fromText(digest);
|
||||
const pk = this.keyStore.getPrivateKey();
|
||||
if (!pk.isDecrypted()) {
|
||||
const password = window.prompt('password');
|
||||
await pk.decrypt(password);
|
||||
}
|
||||
const opts = {
|
||||
message: m,
|
||||
privateKeys: [pk],
|
||||
detached: true,
|
||||
};
|
||||
openpgp
|
||||
.sign(opts)
|
||||
.then((s) => {
|
||||
this.signature = {
|
||||
engine: this.engine,
|
||||
algo: this.algo,
|
||||
data: s.signature,
|
||||
// TODO: fix for browser later
|
||||
digest,
|
||||
};
|
||||
this.onsign(this.signature);
|
||||
})
|
||||
.catch((e) => {
|
||||
this.loggingService.sendErrorLevelMessage(e.message, this, { error: e });
|
||||
this.onsign(undefined);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export { Signable, Signature, Signer, PGPSigner };
|
||||
@@ -3,12 +3,10 @@ import { hobaParseChallengeHeader } from '@src/assets/js/hoba.js';
|
||||
import { signChallenge } from '@src/assets/js/hoba-pgp.js';
|
||||
import { environment } from '@src/environments/environment';
|
||||
import { LoggingService } from '@app/_services/logging.service';
|
||||
import { MutableKeyStore, MutablePgpKeyStore } from '@cicnet/crdt-meta';
|
||||
import { MutableKeyStore, MutablePgpKeyStore } from '@app/_pgp';
|
||||
import { ErrorDialogService } from '@app/_services/error-dialog.service';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { HttpError, rejectBody } from '@app/_helpers/global-error-handler';
|
||||
import { Staff } from '@app/_models';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
@@ -16,11 +14,6 @@ import { BehaviorSubject, Observable } from 'rxjs';
|
||||
export class AuthService {
|
||||
sessionToken: any;
|
||||
mutableKeyStore: MutableKeyStore;
|
||||
trustedUsers: Array<Staff> = [];
|
||||
private trustedUsersList: BehaviorSubject<Array<Staff>> = new BehaviorSubject<Array<Staff>>(
|
||||
this.trustedUsers
|
||||
);
|
||||
trustedUsersSubject: Observable<Array<Staff>> = this.trustedUsersList.asObservable();
|
||||
|
||||
constructor(
|
||||
private httpClient: HttpClient,
|
||||
@@ -197,22 +190,10 @@ export class AuthService {
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
addTrustedUser(user: Staff): void {
|
||||
const savedIndex = this.trustedUsers.findIndex((staff) => staff.userid === user.userid);
|
||||
if (savedIndex === 0) {
|
||||
return;
|
||||
}
|
||||
if (savedIndex > 0) {
|
||||
this.trustedUsers.splice(savedIndex, 1);
|
||||
}
|
||||
this.trustedUsers.unshift(user);
|
||||
this.trustedUsersList.next(this.trustedUsers);
|
||||
}
|
||||
|
||||
getTrustedUsers(): void {
|
||||
this.mutableKeyStore.getPublicKeys().forEach((key) => {
|
||||
this.addTrustedUser(key.users[0].userId);
|
||||
});
|
||||
getTrustedUsers(): any {
|
||||
const trustedUsers: Array<any> = [];
|
||||
this.mutableKeyStore.getPublicKeys().forEach((key) => trustedUsers.push(key.users[0].userId));
|
||||
return trustedUsers;
|
||||
}
|
||||
|
||||
async getPublicKeys(): Promise<any> {
|
||||
@@ -230,8 +211,4 @@ export class AuthService {
|
||||
getPrivateKey(): any {
|
||||
return this.mutableKeyStore.getPrivateKey();
|
||||
}
|
||||
|
||||
getPrivateKeyInfo(): any {
|
||||
return this.getPrivateKey().users[0].userId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import { TransactionService } from '@app/_services/transaction.service';
|
||||
import { environment } from '@src/environments/environment';
|
||||
import { LoggingService } from '@app/_services/logging.service';
|
||||
import { RegistryService } from '@app/_services/registry.service';
|
||||
import { Web3Service } from '@app/_services/web3.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
@@ -17,33 +16,31 @@ export class BlockSyncService {
|
||||
|
||||
constructor(
|
||||
private transactionService: TransactionService,
|
||||
private loggingService: LoggingService
|
||||
private loggingService: LoggingService,
|
||||
private registryService: RegistryService
|
||||
) {}
|
||||
|
||||
async init(): Promise<void> {
|
||||
await this.transactionService.init();
|
||||
}
|
||||
|
||||
async blockSync(address: string = null, offset: number = 0, limit: number = 100): Promise<void> {
|
||||
blockSync(address: string = null, offset: number = 0, limit: number = 100): void {
|
||||
this.transactionService.resetTransactionsList();
|
||||
const settings: Settings = new Settings(this.scan);
|
||||
const readyStateElements: { network: number } = { network: 2 };
|
||||
settings.w3.provider = environment.web3Provider;
|
||||
settings.w3.engine = Web3Service.getInstance();
|
||||
settings.registry = await RegistryService.getRegistry();
|
||||
settings.w3.engine = this.registryService.getWeb3();
|
||||
settings.registry = this.registryService.getRegistry();
|
||||
settings.txHelper = new TransactionHelper(settings.w3.engine, settings.registry);
|
||||
|
||||
settings.txHelper.ontransfer = async (transaction: any): Promise<void> => {
|
||||
window.dispatchEvent(this.newEvent(transaction, 'cic_transfer'));
|
||||
window.dispatchEvent(this.newTransferEvent(transaction));
|
||||
};
|
||||
settings.txHelper.onconversion = async (transaction: any): Promise<any> => {
|
||||
window.dispatchEvent(this.newEvent(transaction, 'cic_convert'));
|
||||
window.dispatchEvent(this.newConversionEvent(transaction));
|
||||
};
|
||||
// settings.registry.onload = (addressReturned: string): void => {
|
||||
// this.loggingService.sendInfoLevelMessage(`Loaded network contracts ${addressReturned}`);
|
||||
// this.readyStateProcessor(settings, readyStateElements.network, address, offset, limit);
|
||||
// };
|
||||
this.readyStateProcessor(settings, readyStateElements.network, address, offset, limit);
|
||||
settings.registry.onload = (addressReturned: number): void => {
|
||||
this.loggingService.sendInfoLevelMessage(`Loaded network contracts ${addressReturned}`);
|
||||
this.readyStateProcessor(settings, readyStateElements.network, address, offset, limit);
|
||||
};
|
||||
|
||||
settings.registry.load();
|
||||
}
|
||||
|
||||
readyStateProcessor(
|
||||
@@ -81,8 +78,16 @@ export class BlockSyncService {
|
||||
}
|
||||
}
|
||||
|
||||
newEvent(tx: any, eventType: string): any {
|
||||
return new CustomEvent(eventType, {
|
||||
newTransferEvent(tx: any): any {
|
||||
return new CustomEvent('cic_transfer', {
|
||||
detail: {
|
||||
tx,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
newConversionEvent(tx: any): any {
|
||||
return new CustomEvent('cic_convert', {
|
||||
detail: {
|
||||
tx,
|
||||
},
|
||||
|
||||
@@ -6,4 +6,3 @@ export * from '@app/_services/block-sync.service';
|
||||
export * from '@app/_services/location.service';
|
||||
export * from '@app/_services/logging.service';
|
||||
export * from '@app/_services/error-dialog.service';
|
||||
export * from '@app/_services/web3.service';
|
||||
|
||||
@@ -1,30 +1,33 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import Web3 from 'web3';
|
||||
import { environment } from '@src/environments/environment';
|
||||
import { CICRegistry, FileGetter } from 'cic-client';
|
||||
import { HttpGetter } from '@app/_helpers';
|
||||
import { Web3Service } from '@app/_services/web3.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class RegistryService {
|
||||
static fileGetter: FileGetter = new HttpGetter();
|
||||
private static registry: CICRegistry;
|
||||
web3: Web3 = new Web3(environment.web3Provider);
|
||||
fileGetter: FileGetter = new HttpGetter();
|
||||
registry: CICRegistry = new CICRegistry(
|
||||
this.web3,
|
||||
environment.registryAddress,
|
||||
'Registry',
|
||||
this.fileGetter,
|
||||
['../../assets/js/block-sync/data']
|
||||
);
|
||||
|
||||
constructor() {}
|
||||
constructor() {
|
||||
this.registry.declaratorHelper.addTrust(environment.trustedDeclaratorAddress);
|
||||
this.registry.load();
|
||||
}
|
||||
|
||||
public static async getRegistry(): Promise<CICRegistry> {
|
||||
if (!RegistryService.registry) {
|
||||
RegistryService.registry = new CICRegistry(
|
||||
Web3Service.getInstance(),
|
||||
environment.registryAddress,
|
||||
'Registry',
|
||||
RegistryService.fileGetter,
|
||||
['../../assets/js/block-sync/data']
|
||||
);
|
||||
RegistryService.registry.declaratorHelper.addTrust(environment.trustedDeclaratorAddress);
|
||||
await RegistryService.registry.load();
|
||||
}
|
||||
return RegistryService.registry;
|
||||
getRegistry(): any {
|
||||
return this.registry;
|
||||
}
|
||||
|
||||
getWeb3(): any {
|
||||
return this.web3;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { EventEmitter, Injectable } from '@angular/core';
|
||||
import { environment } from '@src/environments/environment';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { CICRegistry } from 'cic-client';
|
||||
import { TokenRegistry } from '@app/_eth';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { RegistryService } from '@app/_services/registry.service';
|
||||
import { Token } from '@app/_models';
|
||||
import {BehaviorSubject, Observable, Subject} from 'rxjs';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
@@ -12,65 +12,29 @@ import {BehaviorSubject, Observable, Subject} from 'rxjs';
|
||||
export class TokenService {
|
||||
registry: CICRegistry;
|
||||
tokenRegistry: TokenRegistry;
|
||||
onload: (status: boolean) => void;
|
||||
tokens: Array<Token> = [];
|
||||
private tokensList: BehaviorSubject<Array<Token>> = new BehaviorSubject<Array<Token>>(this.tokens);
|
||||
tokensSubject: Observable<Array<Token>> = this.tokensList.asObservable();
|
||||
LoadEvent: EventEmitter<number> = new EventEmitter<number>();
|
||||
|
||||
constructor(private httpClient: HttpClient) {}
|
||||
|
||||
async init(): Promise<void> {
|
||||
this.registry = await RegistryService.getRegistry();
|
||||
constructor(private httpClient: HttpClient, private registryService: RegistryService) {
|
||||
this.registry = registryService.getRegistry();
|
||||
this.registry.load();
|
||||
this.registry.onload = async (address: string): Promise<void> => {
|
||||
this.tokenRegistry = new TokenRegistry(
|
||||
await this.registry.getContractAddressByName('TokenRegistry')
|
||||
);
|
||||
this.onload(this.tokenRegistry !== undefined);
|
||||
this.LoadEvent.next(Date.now());
|
||||
};
|
||||
}
|
||||
|
||||
addToken(token: Token): void {
|
||||
const savedIndex = this.tokens.findIndex((tk) => tk.address === token.address);
|
||||
if (savedIndex === 0) {
|
||||
return;
|
||||
}
|
||||
if (savedIndex > 0) {
|
||||
this.tokens.splice(savedIndex, 1);
|
||||
}
|
||||
this.tokens.unshift(token);
|
||||
this.tokensList.next(this.tokens);
|
||||
}
|
||||
|
||||
async getTokens(): Promise<void> {
|
||||
async getTokens(): Promise<Array<Promise<string>>> {
|
||||
const count: number = await this.tokenRegistry.totalTokens();
|
||||
for (let i = 0; i < count; i++) {
|
||||
const token: Token = await this.getTokenByAddress(await this.tokenRegistry.entry(i));
|
||||
this.addToken(token);
|
||||
}
|
||||
return Array.from({ length: count }, async (v, i) => await this.tokenRegistry.entry(i));
|
||||
}
|
||||
|
||||
async getTokenByAddress(address: string): Promise<Token> {
|
||||
const token: any = {};
|
||||
const tokenContract = await this.registry.addToken(address);
|
||||
token.address = address;
|
||||
token.name = await tokenContract.methods.name().call();
|
||||
token.symbol = await tokenContract.methods.symbol().call();
|
||||
token.supply = await tokenContract.methods.totalSupply().call();
|
||||
token.decimals = await tokenContract.methods.decimals().call();
|
||||
return token;
|
||||
getTokenBySymbol(symbol: string): Observable<any> {
|
||||
return this.httpClient.get(`${environment.cicCacheUrl}/tokens/${symbol}`);
|
||||
}
|
||||
|
||||
async getTokenBySymbol(symbol: string): Promise<Observable<Token>> {
|
||||
const tokenSubject: Subject<Token> = new Subject<Token>();
|
||||
await this.getTokens();
|
||||
this.tokensSubject.subscribe((tokens) => {
|
||||
const queriedToken = tokens.find((token) => token.symbol === symbol);
|
||||
tokenSubject.next(queriedToken);
|
||||
});
|
||||
return tokenSubject.asObservable();
|
||||
}
|
||||
|
||||
async getTokenBalance(address: string): Promise<(address: string) => Promise<number>> {
|
||||
async getTokenBalance(address: string): Promise<number> {
|
||||
const sarafuToken = await this.registry.addToken(await this.tokenRegistry.entry(0));
|
||||
return await sarafuToken.methods.balanceOf(address).call();
|
||||
}
|
||||
|
||||
@@ -2,8 +2,7 @@ import { Injectable } from '@angular/core';
|
||||
import { first } from 'rxjs/operators';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { environment } from '@src/environments/environment';
|
||||
import {User} from '@cicnet/cic-client-meta';
|
||||
import {Envelope} from '@cicnet/crdt-meta';
|
||||
import { Envelope, User } from 'cic-client-meta';
|
||||
import { UserService } from '@app/_services/user.service';
|
||||
import { Keccak } from 'sha3';
|
||||
import { utils } from 'ethers';
|
||||
@@ -18,7 +17,6 @@ import { HttpClient } from '@angular/common/http';
|
||||
import { CICRegistry } from 'cic-client';
|
||||
import { RegistryService } from '@app/_services/registry.service';
|
||||
import Web3 from 'web3';
|
||||
import { Web3Service } from '@app/_services/web3.service';
|
||||
const vCard = require('vcard-parser');
|
||||
|
||||
@Injectable({
|
||||
@@ -36,15 +34,12 @@ export class TransactionService {
|
||||
private httpClient: HttpClient,
|
||||
private authService: AuthService,
|
||||
private userService: UserService,
|
||||
private loggingService: LoggingService
|
||||
private loggingService: LoggingService,
|
||||
private registryService: RegistryService
|
||||
) {
|
||||
this.web3 = Web3Service.getInstance();
|
||||
}
|
||||
|
||||
async init(): Promise<void> {
|
||||
await this.authService.init();
|
||||
await this.userService.init();
|
||||
this.registry = await RegistryService.getRegistry();
|
||||
this.web3 = this.registryService.getWeb3();
|
||||
this.registry = registryService.getRegistry();
|
||||
this.registry.load();
|
||||
}
|
||||
|
||||
getAllTransactions(offset: number, limit: number): Observable<any> {
|
||||
@@ -52,7 +47,7 @@ export class TransactionService {
|
||||
}
|
||||
|
||||
getAddressTransactions(address: string, offset: number, limit: number): Observable<any> {
|
||||
return this.httpClient.get(`${environment.cicCacheUrl}/tx/user/${address}/${offset}/${limit}`);
|
||||
return this.httpClient.get(`${environment.cicCacheUrl}/tx/${address}/${offset}/${limit}`);
|
||||
}
|
||||
|
||||
async setTransaction(transaction, cacheSize: number): Promise<void> {
|
||||
@@ -67,11 +62,10 @@ export class TransactionService {
|
||||
.pipe(first())
|
||||
.subscribe(
|
||||
(res) => {
|
||||
transaction.sender = this.getAccountInfo(res, cacheSize);
|
||||
transaction.sender = this.getAccountInfo(res.body);
|
||||
},
|
||||
(error) => {
|
||||
transaction.sender = defaultAccount;
|
||||
this.userService.addAccount(defaultAccount, cacheSize);
|
||||
}
|
||||
);
|
||||
this.userService
|
||||
@@ -79,11 +73,10 @@ export class TransactionService {
|
||||
.pipe(first())
|
||||
.subscribe(
|
||||
(res) => {
|
||||
transaction.recipient = this.getAccountInfo(res, cacheSize);
|
||||
transaction.recipient = this.getAccountInfo(res.body);
|
||||
},
|
||||
(error) => {
|
||||
transaction.recipient = defaultAccount;
|
||||
this.userService.addAccount(defaultAccount, cacheSize);
|
||||
}
|
||||
);
|
||||
} finally {
|
||||
@@ -104,11 +97,10 @@ export class TransactionService {
|
||||
.pipe(first())
|
||||
.subscribe(
|
||||
(res) => {
|
||||
conversion.sender = conversion.recipient = this.getAccountInfo(res);
|
||||
conversion.sender = conversion.recipient = this.getAccountInfo(res.body);
|
||||
},
|
||||
(error) => {
|
||||
conversion.sender = conversion.recipient = defaultAccount;
|
||||
this.userService.addAccount(defaultAccount, cacheSize);
|
||||
}
|
||||
);
|
||||
} finally {
|
||||
@@ -117,16 +109,9 @@ export class TransactionService {
|
||||
}
|
||||
|
||||
addTransaction(transaction, cacheSize: number): void {
|
||||
const savedIndex = this.transactions.findIndex((tx) => tx.tx.txHash === transaction.tx.txHash);
|
||||
if (savedIndex === 0) {
|
||||
return;
|
||||
}
|
||||
if (savedIndex > 0) {
|
||||
this.transactions.splice(savedIndex, 1);
|
||||
}
|
||||
this.transactions.unshift(transaction);
|
||||
if (this.transactions.length > cacheSize) {
|
||||
this.transactions.length = Math.min(this.transactions.length, cacheSize);
|
||||
this.transactions.length = cacheSize;
|
||||
}
|
||||
this.transactionList.next(this.transactions);
|
||||
}
|
||||
@@ -136,10 +121,9 @@ export class TransactionService {
|
||||
this.transactionList.next(this.transactions);
|
||||
}
|
||||
|
||||
getAccountInfo(account: string, cacheSize: number = 100): any {
|
||||
getAccountInfo(account: string): any {
|
||||
const accountInfo = Envelope.fromJSON(JSON.stringify(account)).unwrap().m.data;
|
||||
accountInfo.vcard = vCard.parse(atob(accountInfo.vcard));
|
||||
this.userService.addAccount(accountInfo, cacheSize);
|
||||
return accountInfo;
|
||||
}
|
||||
|
||||
@@ -149,43 +133,41 @@ export class TransactionService {
|
||||
recipientAddress: string,
|
||||
value: number
|
||||
): Promise<any> {
|
||||
this.registry.onload = async (addressReturned: string): Promise<void> => {
|
||||
const transferAuthAddress = await this.registry.getContractAddressByName(
|
||||
'TransferAuthorization'
|
||||
);
|
||||
const hashFunction = new Keccak(256);
|
||||
hashFunction.update('createRequest(address,address,address,uint256)');
|
||||
const hash = hashFunction.digest();
|
||||
const methodSignature = hash.toString('hex').substring(0, 8);
|
||||
const abiCoder = new utils.AbiCoder();
|
||||
const abi = await abiCoder.encode(
|
||||
['address', 'address', 'address', 'uint256'],
|
||||
[senderAddress, recipientAddress, tokenAddress, value]
|
||||
);
|
||||
const data = fromHex(methodSignature + strip0x(abi));
|
||||
const tx = new Tx(environment.bloxbergChainId);
|
||||
tx.nonce = await this.web3.eth.getTransactionCount(senderAddress);
|
||||
tx.gasPrice = Number(await this.web3.eth.getGasPrice());
|
||||
tx.gasLimit = 8000000;
|
||||
tx.to = fromHex(strip0x(transferAuthAddress));
|
||||
tx.value = toValue(value);
|
||||
tx.data = data;
|
||||
const txMsg = tx.message();
|
||||
const privateKey = this.authService.mutableKeyStore.getPrivateKey();
|
||||
if (!privateKey.isDecrypted()) {
|
||||
const password = window.prompt('password');
|
||||
await privateKey.decrypt(password);
|
||||
}
|
||||
const signatureObject = secp256k1.ecdsaSign(txMsg, privateKey.keyPacket.privateParams.d);
|
||||
const r = signatureObject.signature.slice(0, 32);
|
||||
const s = signatureObject.signature.slice(32);
|
||||
const v = signatureObject.recid;
|
||||
tx.setSignature(r, s, v);
|
||||
const txWire = add0x(toHex(tx.serializeRLP()));
|
||||
const result = await this.web3.eth.sendSignedTransaction(txWire);
|
||||
this.loggingService.sendInfoLevelMessage(`Result: ${result}`);
|
||||
const transaction = await this.web3.eth.getTransaction(result.transactionHash);
|
||||
this.loggingService.sendInfoLevelMessage(`Transaction: ${transaction}`);
|
||||
};
|
||||
const transferAuthAddress = await this.registry.getContractAddressByName(
|
||||
'TransferAuthorization'
|
||||
);
|
||||
const hashFunction = new Keccak(256);
|
||||
hashFunction.update('createRequest(address,address,address,uint256)');
|
||||
const hash = hashFunction.digest();
|
||||
const methodSignature = hash.toString('hex').substring(0, 8);
|
||||
const abiCoder = new utils.AbiCoder();
|
||||
const abi = await abiCoder.encode(
|
||||
['address', 'address', 'address', 'uint256'],
|
||||
[senderAddress, recipientAddress, tokenAddress, value]
|
||||
);
|
||||
const data = fromHex(methodSignature + strip0x(abi));
|
||||
const tx = new Tx(environment.bloxbergChainId);
|
||||
tx.nonce = await this.web3.eth.getTransactionCount(senderAddress);
|
||||
tx.gasPrice = Number(await this.web3.eth.getGasPrice());
|
||||
tx.gasLimit = 8000000;
|
||||
tx.to = fromHex(strip0x(transferAuthAddress));
|
||||
tx.value = toValue(value);
|
||||
tx.data = data;
|
||||
const txMsg = tx.message();
|
||||
const privateKey = this.authService.mutableKeyStore.getPrivateKey();
|
||||
if (!privateKey.isDecrypted()) {
|
||||
const password = window.prompt('password');
|
||||
await privateKey.decrypt(password);
|
||||
}
|
||||
const signatureObject = secp256k1.ecdsaSign(txMsg, privateKey.keyPacket.privateParams.d);
|
||||
const r = signatureObject.signature.slice(0, 32);
|
||||
const s = signatureObject.signature.slice(32);
|
||||
const v = signatureObject.recid;
|
||||
tx.setSignature(r, s, v);
|
||||
const txWire = add0x(toHex(tx.serializeRLP()));
|
||||
const result = await this.web3.eth.sendSignedTransaction(txWire);
|
||||
this.loggingService.sendInfoLevelMessage(`Result: ${result}`);
|
||||
const transaction = await this.web3.eth.getTransaction(result.transactionHash);
|
||||
this.loggingService.sendInfoLevelMessage(`Transaction: ${transaction}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,12 @@ import { BehaviorSubject, Observable, Subject } from 'rxjs';
|
||||
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
|
||||
import { environment } from '@src/environments/environment';
|
||||
import { first } from 'rxjs/operators';
|
||||
import {Phone, User} from '@cicnet/cic-client-meta';
|
||||
import {ArgPair, Envelope, Syncable, MutableKeyStore, PGPSigner, Signer} from '@cicnet/crdt-meta';
|
||||
import { ArgPair, Envelope, Phone, Syncable, User } from 'cic-client-meta';
|
||||
import { AccountDetails } from '@app/_models';
|
||||
import { LoggingService } from '@app/_services/logging.service';
|
||||
import { TokenService } from '@app/_services/token.service';
|
||||
import { AccountIndex } from '@app/_eth';
|
||||
import { MutableKeyStore, PGPSigner, Signer } from '@app/_pgp';
|
||||
import { RegistryService } from '@app/_services/registry.service';
|
||||
import { CICRegistry } from 'cic-client';
|
||||
import { AuthService } from '@app/_services/auth.service';
|
||||
@@ -39,20 +39,20 @@ export class UserService {
|
||||
private httpClient: HttpClient,
|
||||
private loggingService: LoggingService,
|
||||
private tokenService: TokenService,
|
||||
private registryService: RegistryService,
|
||||
private authService: AuthService
|
||||
) {}
|
||||
|
||||
async init(): Promise<void> {
|
||||
await this.authService.init();
|
||||
await this.tokenService.init();
|
||||
this.keystore = this.authService.mutableKeyStore;
|
||||
this.signer = new PGPSigner(this.keystore);
|
||||
this.registry = await RegistryService.getRegistry();
|
||||
) {
|
||||
this.authService.init().then(() => {
|
||||
this.keystore = authService.mutableKeyStore;
|
||||
this.signer = new PGPSigner(this.keystore);
|
||||
});
|
||||
this.registry = registryService.getRegistry();
|
||||
this.registry.load();
|
||||
}
|
||||
|
||||
resetPin(phone: string): Observable<any> {
|
||||
const params: HttpParams = new HttpParams().set('phoneNumber', phone);
|
||||
return this.httpClient.put(`${environment.cicUssdUrl}/pin`, { params });
|
||||
return this.httpClient.get(`${environment.cicUssdUrl}/pin`, { params });
|
||||
}
|
||||
|
||||
getAccountStatus(phone: string): Observable<any> {
|
||||
@@ -183,7 +183,9 @@ export class UserService {
|
||||
'AccountRegistry'
|
||||
);
|
||||
const accountIndexQuery = new AccountIndex(accountIndexAddress);
|
||||
const accountAddresses: Array<string> = await accountIndexQuery.last(limit);
|
||||
const accountAddresses: Array<string> = await accountIndexQuery.last(
|
||||
await accountIndexQuery.totalAccounts()
|
||||
);
|
||||
this.loggingService.sendInfoLevelMessage(accountAddresses);
|
||||
for (const accountAddress of accountAddresses.slice(offset, offset + limit)) {
|
||||
await this.getAccountByAddress(accountAddress, limit);
|
||||
@@ -201,14 +203,16 @@ export class UserService {
|
||||
const account: Syncable = Envelope.fromJSON(JSON.stringify(res)).unwrap();
|
||||
const accountInfo = account.m.data;
|
||||
await personValidation(accountInfo);
|
||||
this.tokenService.onload = async (status: boolean): Promise<void> => {
|
||||
accountInfo.balance = await this.tokenService.getTokenBalance(
|
||||
accountInfo.identities.evm[`bloxberg:${environment.bloxbergChainId}`][0]
|
||||
);
|
||||
};
|
||||
accountInfo.balance = await this.tokenService.getTokenBalance(
|
||||
accountInfo.identities.evm[`bloxberg:${environment.bloxbergChainId}`][0]
|
||||
);
|
||||
accountInfo.vcard = vCard.parse(atob(accountInfo.vcard));
|
||||
await vcardValidation(accountInfo.vcard);
|
||||
this.addAccount(accountInfo, limit);
|
||||
this.accounts.unshift(accountInfo);
|
||||
if (this.accounts.length > limit) {
|
||||
this.accounts.length = limit;
|
||||
}
|
||||
this.accountsList.next(this.accounts);
|
||||
accountSubject.next(accountInfo);
|
||||
});
|
||||
return accountSubject.asObservable();
|
||||
@@ -260,23 +264,4 @@ export class UserService {
|
||||
getGenders(): Observable<any> {
|
||||
return this.httpClient.get(`${environment.cicMetaUrl}/genders`);
|
||||
}
|
||||
|
||||
addAccount(account: AccountDetails, cacheSize: number): void {
|
||||
const savedIndex = this.accounts.findIndex(
|
||||
(acc) =>
|
||||
acc.identities.evm[`bloxberg:${environment.bloxbergChainId}`][0] ===
|
||||
account.identities.evm[`bloxberg:${environment.bloxbergChainId}`][0]
|
||||
);
|
||||
if (savedIndex === 0) {
|
||||
return;
|
||||
}
|
||||
if (savedIndex > 0) {
|
||||
this.accounts.splice(savedIndex, 1);
|
||||
}
|
||||
this.accounts.unshift(account);
|
||||
if (this.accounts.length > cacheSize) {
|
||||
this.accounts.length = Math.min(this.accounts.length, cacheSize);
|
||||
}
|
||||
this.accountsList.next(this.accounts);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { Web3Service } from './web3.service';
|
||||
|
||||
describe('Web3Service', () => {
|
||||
let service: Web3Service;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(Web3Service);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -1,19 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import Web3 from 'web3';
|
||||
import { environment } from '@src/environments/environment';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class Web3Service {
|
||||
private static web3: Web3;
|
||||
|
||||
constructor() {}
|
||||
|
||||
public static getInstance(): Web3 {
|
||||
if (!Web3Service.web3) {
|
||||
Web3Service.web3 = new Web3(environment.web3Provider);
|
||||
}
|
||||
return Web3Service.web3;
|
||||
}
|
||||
}
|
||||
@@ -1 +1,2 @@
|
||||
<app-network-status></app-network-status>
|
||||
<router-outlet (activate)="onResize(mediaQuery)"></router-outlet>
|
||||
|
||||
@@ -27,23 +27,28 @@ export class AppComponent implements OnInit {
|
||||
private errorDialogService: ErrorDialogService,
|
||||
private swUpdate: SwUpdate
|
||||
) {
|
||||
(async () => {
|
||||
try {
|
||||
await this.authService.init();
|
||||
// this.authService.getPublicKeys()
|
||||
// .pipe(catchError(async (error) => {
|
||||
// this.loggingService.sendErrorLevelMessage('Unable to load trusted public keys.', this, {error});
|
||||
// this.errorDialogService.openDialog({message: 'Trusted keys endpoint can\'t be reached. Please try again later.'});
|
||||
// })).subscribe(this.authService.mutableKeyStore.importPublicKey);
|
||||
const publicKeys = await this.authService.getPublicKeys();
|
||||
await this.authService.mutableKeyStore.importPublicKey(publicKeys);
|
||||
} catch (error) {
|
||||
this.errorDialogService.openDialog({
|
||||
message: 'Trusted keys endpoint cannot be reached. Please try again later.',
|
||||
});
|
||||
// TODO do something to halt user progress...show a sad cicada page 🦗?
|
||||
}
|
||||
})();
|
||||
this.mediaQuery.addEventListener('change', this.onResize);
|
||||
this.onResize(this.mediaQuery);
|
||||
}
|
||||
|
||||
async ngOnInit(): Promise<void> {
|
||||
await this.authService.init();
|
||||
await this.transactionService.init();
|
||||
try {
|
||||
const publicKeys = await this.authService.getPublicKeys();
|
||||
await this.authService.mutableKeyStore.importPublicKey(publicKeys);
|
||||
this.authService.getTrustedUsers();
|
||||
} catch (error) {
|
||||
this.errorDialogService.openDialog({
|
||||
message: 'Trusted keys endpoint cannot be reached. Please try again later.',
|
||||
});
|
||||
// TODO do something to halt user progress...show a sad cicada page 🦗?
|
||||
}
|
||||
ngOnInit(): void {
|
||||
if (!this.swUpdate.isEnabled) {
|
||||
this.swUpdate.available.subscribe(() => {
|
||||
if (confirm('New Version available. Load New Version?')) {
|
||||
|
||||
@@ -12,7 +12,7 @@ import { AuthGuard } from '@app/_guards';
|
||||
import { LoggerModule } from 'ngx-logger';
|
||||
import { environment } from '@src/environments/environment';
|
||||
import { ErrorInterceptor, HttpConfigInterceptor, LoggingInterceptor } from '@app/_interceptors';
|
||||
import { MutablePgpKeyStore } from '@cicnet/crdt-meta';
|
||||
import { MutablePgpKeyStore } from '@app/_pgp';
|
||||
import { ServiceWorkerModule } from '@angular/service-worker';
|
||||
|
||||
@NgModule({
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
<app-network-status></app-network-status>
|
||||
<div class="container">
|
||||
<div class="row justify-content-center mt-5 mb-5">
|
||||
<div class="col-lg-6 col-md-8 col-sm-10">
|
||||
<div class="card">
|
||||
<mat-card-title class="card-header pt-4 pb-4 text-center background-dark">
|
||||
<mat-card-title class="card-header pt-4 pb-4 text-center bg-dark">
|
||||
<a routerLink="/">
|
||||
<h1 class="text-white">CICADA</h1>
|
||||
</a>
|
||||
|
||||
@@ -10,7 +10,6 @@ import { MatSelectModule } from '@angular/material/select';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatRippleModule } from '@angular/material/core';
|
||||
import { SharedModule } from '@app/shared/shared.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [AuthComponent, PasswordToggleDirective],
|
||||
@@ -23,7 +22,6 @@ import { SharedModule } from '@app/shared/shared.module';
|
||||
MatInputModule,
|
||||
MatButtonModule,
|
||||
MatRippleModule,
|
||||
SharedModule,
|
||||
],
|
||||
})
|
||||
export class AuthModule {}
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
<strong> {{account?.vcard?.fn[0].value}} </strong>
|
||||
</h3>
|
||||
<span class="ml-auto"><strong>Balance:</strong> {{account?.balance | tokenRatio}} SRF</span>
|
||||
<span class="ml-2"><strong>Created:</strong> {{account?.date_registered | unixDate}}</span>
|
||||
<span class="ml-2"><strong>Created:</strong> {{account?.date_registered | date}}</span>
|
||||
<span class="ml-2"><strong>Address:</strong>
|
||||
<a href="{{bloxbergLink}}" target="_blank"> {{accountAddress}} </a>
|
||||
<img src="assets/images/checklist.svg" class="ml-2" height="20rem" (click)="copyAddress()" alt="Copy">
|
||||
@@ -48,19 +48,10 @@
|
||||
|
||||
<div class="col-md-6 col-lg-4">
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>First Name: *</mat-label>
|
||||
<input matInput type="text" id="firstName" placeholder="{{account?.vcard?.fn[0].value.split(' ')[0]}}"
|
||||
value="{{account?.vcard?.fn[0].value.split(' ')[0]}}" formControlName="firstName" [errorStateMatcher]="matcher">
|
||||
<mat-error *ngIf="submitted && accountInfoFormStub.firstName.errors">First Name is required.</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 col-lg-4">
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Last Name(s): *</mat-label>
|
||||
<input matInput type="text" id="lastName" placeholder="{{account?.vcard?.fn[0].value.split(' ').slice(1).join(' ')}}"
|
||||
value="{{account?.vcard?.fn[0].value.split(' ').slice(1).join(' ')}}" formControlName="lastName" [errorStateMatcher]="matcher">
|
||||
<mat-error *ngIf="submitted && accountInfoFormStub.lastName.errors">Last Name is required.</mat-error>
|
||||
<mat-label>Name(s): *</mat-label>
|
||||
<input matInput type="text" id="givenNames" placeholder="{{account?.vcard?.fn[0].value}}"
|
||||
value="{{account?.vcard?.fn[0].value}}" formControlName="name" [errorStateMatcher]="matcher">
|
||||
<mat-error *ngIf="submitted && accountInfoFormStub.name.errors">Name is required.</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
@@ -219,9 +210,12 @@
|
||||
<tr>
|
||||
<td>{{account?.vcard?.fn[0].value}}</td>
|
||||
<td>{{account?.balance | tokenRatio}}</td>
|
||||
<td>{{account?.date_registered | unixDate}}</td>
|
||||
<td>{{account?.date_registered | date}}</td>
|
||||
<td>
|
||||
<span class="badge badge-success badge-pill">
|
||||
<span *ngIf="accountStatus === 'active'" class="badge badge-success badge-pill">
|
||||
{{accountStatus}}
|
||||
</span>
|
||||
<span *ngIf="accountStatus === 'blocked'" class="badge badge-danger badge-pill">
|
||||
{{accountStatus}}
|
||||
</span>
|
||||
</td>
|
||||
@@ -234,7 +228,7 @@
|
||||
|
||||
<mat-tab-group *ngIf="account" dynamicHeight mat-align-tabs="start">
|
||||
<mat-tab label="Transactions">
|
||||
<app-transaction-details [transaction]="transaction" (closeWindow)="transaction = $event"></app-transaction-details>
|
||||
<app-transaction-details [transaction]="transaction"></app-transaction-details>
|
||||
<div class="card mt-1">
|
||||
<div class="card-header">
|
||||
<div class="row">
|
||||
@@ -258,17 +252,17 @@
|
||||
<mat-icon matSuffix>search</mat-icon>
|
||||
</mat-form-field>
|
||||
|
||||
<table mat-table class="mat-elevation-z10" [dataSource]="transactionsDataSource" matSort matSortActive="created"
|
||||
<mat-table class="mat-elevation-z10" [dataSource]="transactionsDataSource" matSort matSortActive="created"
|
||||
#TransactionTableSort="matSort" matSortDirection="asc" matSortDisableClear>
|
||||
|
||||
<ng-container matColumnDef="sender">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header> Sender </th>
|
||||
<td mat-cell *matCellDef="let transaction"> {{transaction?.sender?.vcard.fn[0].value || transaction.from}} </td>
|
||||
<td mat-cell *matCellDef="let transaction"> {{transaction?.sender?.vcard.fn[0].value}} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="recipient">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header> Recipient </th>
|
||||
<td mat-cell *matCellDef="let transaction"> {{transaction?.recipient?.vcard.fn[0].value || transaction.to}} </td>
|
||||
<td mat-cell *matCellDef="let transaction"> {{transaction?.recipient?.vcard.fn[0].value}} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="value">
|
||||
@@ -281,7 +275,7 @@
|
||||
|
||||
<ng-container matColumnDef="created">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header> Created </th>
|
||||
<td mat-cell *matCellDef="let transaction"> {{transaction?.tx.timestamp | unixDate}} </td>
|
||||
<td mat-cell *matCellDef="let transaction"> {{transaction?.tx.timestamp | date}} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="type">
|
||||
@@ -291,10 +285,10 @@
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="transactionsDisplayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let transaction; columns: transactionsDisplayedColumns" matRipple
|
||||
(click)="viewTransaction(transaction)"></tr>
|
||||
</table>
|
||||
<mat-header-row *matHeaderRowDef="transactionsDisplayedColumns"></mat-header-row>
|
||||
<mat-row *matRowDef="let transaction; columns: transactionsDisplayedColumns" matRipple
|
||||
(click)="viewTransaction(transaction)"></mat-row>
|
||||
</mat-table>
|
||||
|
||||
<mat-paginator #TransactionTablePaginator="matPaginator" [pageSize]="transactionsDefaultPageSize"
|
||||
[pageSizeOptions]="transactionsPageSizeOptions" showFirstLastButtons></mat-paginator>
|
||||
@@ -343,7 +337,7 @@
|
||||
|
||||
<ng-container matColumnDef="created">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header> CREATED </mat-header-cell>
|
||||
<mat-cell *matCellDef="let user"> {{user?.date_registered | unixDate}} </mat-cell>
|
||||
<mat-cell *matCellDef="let user"> {{user?.date_registered | date}} </mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="balance">
|
||||
|
||||
@@ -78,17 +78,8 @@ export class AccountDetailsComponent implements OnInit {
|
||||
private cdr: ChangeDetectorRef,
|
||||
private snackBar: MatSnackBar
|
||||
) {
|
||||
this.route.paramMap.subscribe((params: Params) => {
|
||||
this.accountAddress = add0x(params.get('id'));
|
||||
this.bloxbergLink =
|
||||
'https://blockexplorer.bloxberg.org/address/' + this.accountAddress + '/transactions';
|
||||
});
|
||||
}
|
||||
|
||||
async ngOnInit(): Promise<void> {
|
||||
this.accountInfoForm = this.formBuilder.group({
|
||||
firstName: ['', Validators.required],
|
||||
lastName: ['', Validators.required],
|
||||
name: ['', Validators.required],
|
||||
phoneNumber: ['', Validators.required],
|
||||
age: ['', Validators.required],
|
||||
type: ['', Validators.required],
|
||||
@@ -99,71 +90,36 @@ export class AccountDetailsComponent implements OnInit {
|
||||
location: ['', Validators.required],
|
||||
locationType: ['', Validators.required],
|
||||
});
|
||||
await this.blockSyncService.init();
|
||||
await this.tokenService.init();
|
||||
await this.transactionService.init();
|
||||
await this.userService.init();
|
||||
await this.blockSyncService.blockSync(this.accountAddress);
|
||||
this.userService.resetAccountsList();
|
||||
(await this.userService.getAccountByAddress(this.accountAddress, 100)).subscribe(
|
||||
async (res) => {
|
||||
if (res !== undefined) {
|
||||
this.account = res;
|
||||
this.cdr.detectChanges();
|
||||
this.loggingService.sendInfoLevelMessage(this.account);
|
||||
const fullName = this.account.vcard?.fn[0].value.split(' ');
|
||||
this.accountInfoForm.patchValue({
|
||||
firstName: fullName[0],
|
||||
lastName: fullName.slice(1).join(' '),
|
||||
phoneNumber: this.account.vcard?.tel[0].value,
|
||||
age: this.account.age,
|
||||
type: this.account.type,
|
||||
bio: this.account.products,
|
||||
gender: this.account.gender,
|
||||
businessCategory:
|
||||
this.account.category ||
|
||||
this.userService.getCategoryByProduct(this.account.products[0]),
|
||||
userLocation: this.account.location.area_name,
|
||||
location:
|
||||
this.account.location.area ||
|
||||
this.locationService
|
||||
.getAreaNameByLocation(this.account.location.area_name)
|
||||
.pipe(first())
|
||||
.subscribe((response) => {
|
||||
return response;
|
||||
}),
|
||||
locationType:
|
||||
this.account.location.area_type ||
|
||||
this.locationService
|
||||
.getAreaTypeByArea(this.accountInfoFormStub.location.value)
|
||||
.pipe(first())
|
||||
.subscribe((response) => {
|
||||
return response;
|
||||
}),
|
||||
});
|
||||
this.userService
|
||||
.getAccountStatus(this.account.vcard?.tel[0].value)
|
||||
.pipe(first())
|
||||
.subscribe((response) => (this.accountStatus = response.status));
|
||||
} else {
|
||||
alert('Account not found!');
|
||||
this.route.paramMap.subscribe(async (params: Params) => {
|
||||
this.accountAddress = add0x(params.get('id'));
|
||||
this.bloxbergLink =
|
||||
'https://blockexplorer.bloxberg.org/address/' + this.accountAddress + '/transactions';
|
||||
(await this.userService.getAccountByAddress(this.accountAddress, 100)).subscribe(
|
||||
async (res) => {
|
||||
if (res !== undefined) {
|
||||
this.account = res;
|
||||
this.cdr.detectChanges();
|
||||
this.loggingService.sendInfoLevelMessage(this.account);
|
||||
// this.userService.getAccountStatus(this.account.vcard?.tel[0].value).pipe(first())
|
||||
// .subscribe(response => this.accountStatus = response);
|
||||
this.accountInfoForm.patchValue({
|
||||
name: this.account.vcard?.fn[0].value,
|
||||
phoneNumber: this.account.vcard?.tel[0].value,
|
||||
age: this.account.age,
|
||||
type: this.account.type,
|
||||
bio: this.account.products,
|
||||
gender: this.account.gender,
|
||||
businessCategory: this.account.category,
|
||||
userLocation: this.account.location.area_name,
|
||||
location: this.account.location.area,
|
||||
locationType: this.account.location.area_type,
|
||||
});
|
||||
} else {
|
||||
alert('Account not found!');
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
this.userService.accountsSubject.subscribe((accounts) => {
|
||||
this.userDataSource = new MatTableDataSource<any>(accounts);
|
||||
this.userDataSource.paginator = this.userTablePaginator;
|
||||
this.userDataSource.sort = this.userTableSort;
|
||||
this.accounts = accounts;
|
||||
this.cdr.detectChanges();
|
||||
});
|
||||
|
||||
this.transactionService.transactionsSubject.subscribe((transactions) => {
|
||||
this.transactionsDataSource = new MatTableDataSource<any>(transactions);
|
||||
this.transactionsDataSource.paginator = this.transactionTablePaginator;
|
||||
this.transactionsDataSource.sort = this.transactionTableSort;
|
||||
this.transactions = transactions;
|
||||
this.cdr.detectChanges();
|
||||
);
|
||||
this.blockSyncService.blockSync(this.accountAddress);
|
||||
});
|
||||
this.userService
|
||||
.getCategories()
|
||||
@@ -191,6 +147,22 @@ export class AccountDetailsComponent implements OnInit {
|
||||
.subscribe((res) => (this.genders = res));
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.userService.accountsSubject.subscribe((accounts) => {
|
||||
this.userDataSource = new MatTableDataSource<any>(accounts);
|
||||
this.userDataSource.paginator = this.userTablePaginator;
|
||||
this.userDataSource.sort = this.userTableSort;
|
||||
this.accounts = accounts;
|
||||
});
|
||||
|
||||
this.transactionService.transactionsSubject.subscribe((transactions) => {
|
||||
this.transactionsDataSource = new MatTableDataSource<any>(transactions);
|
||||
this.transactionsDataSource.paginator = this.transactionTablePaginator;
|
||||
this.transactionsDataSource.sort = this.transactionTableSort;
|
||||
this.transactions = transactions;
|
||||
});
|
||||
}
|
||||
|
||||
doTransactionFilter(value: string): void {
|
||||
this.transactionsDataSource.filter = value.trim().toLocaleLowerCase();
|
||||
}
|
||||
@@ -220,7 +192,7 @@ export class AccountDetailsComponent implements OnInit {
|
||||
}
|
||||
const accountKey = await this.userService.changeAccountInfo(
|
||||
this.accountAddress,
|
||||
this.accountInfoFormStub.firstName.value + ' ' + this.accountInfoFormStub.lastName.value,
|
||||
this.accountInfoFormStub.name.value,
|
||||
this.accountInfoFormStub.phoneNumber.value,
|
||||
this.accountInfoFormStub.age.value,
|
||||
this.accountInfoFormStub.type.value,
|
||||
|
||||
@@ -30,8 +30,7 @@ export class AccountSearchComponent implements OnInit {
|
||||
private router: Router
|
||||
) {}
|
||||
|
||||
async ngOnInit(): Promise<void> {
|
||||
await this.userService.init();
|
||||
ngOnInit(): void {
|
||||
this.nameSearchForm = this.formBuilder.group({
|
||||
name: ['', Validators.required],
|
||||
});
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
|
||||
<ng-container matColumnDef="created">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header> CREATED </mat-header-cell>
|
||||
<mat-cell *matCellDef="let user"> {{user?.date_registered | unixDate}} </mat-cell>
|
||||
<mat-cell *matCellDef="let user"> {{user?.date_registered | date}} </mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="balance">
|
||||
|
||||
@@ -32,26 +32,28 @@ export class AccountsComponent implements OnInit {
|
||||
private userService: UserService,
|
||||
private loggingService: LoggingService,
|
||||
private router: Router
|
||||
) {}
|
||||
) {
|
||||
(async () => {
|
||||
try {
|
||||
// TODO it feels like this should be in the onInit handler
|
||||
await this.userService.loadAccounts(100);
|
||||
} catch (error) {
|
||||
this.loggingService.sendErrorLevelMessage('Failed to load accounts', this, { error });
|
||||
}
|
||||
})();
|
||||
this.userService
|
||||
.getAccountTypes()
|
||||
.pipe(first())
|
||||
.subscribe((res) => (this.accountTypes = res));
|
||||
}
|
||||
|
||||
async ngOnInit(): Promise<void> {
|
||||
await this.userService.init();
|
||||
try {
|
||||
// TODO it feels like this should be in the onInit handler
|
||||
await this.userService.loadAccounts(100);
|
||||
} catch (error) {
|
||||
this.loggingService.sendErrorLevelMessage('Failed to load accounts', this, { error });
|
||||
}
|
||||
ngOnInit(): void {
|
||||
this.userService.accountsSubject.subscribe((accounts) => {
|
||||
this.dataSource = new MatTableDataSource<any>(accounts);
|
||||
this.dataSource.paginator = this.paginator;
|
||||
this.dataSource.sort = this.sort;
|
||||
this.accounts = accounts;
|
||||
});
|
||||
this.userService
|
||||
.getAccountTypes()
|
||||
.pipe(first())
|
||||
.subscribe((res) => (this.accountTypes = res));
|
||||
}
|
||||
|
||||
doFilter(value: string): void {
|
||||
|
||||
@@ -26,8 +26,7 @@ export class CreateAccountComponent implements OnInit {
|
||||
private userService: UserService
|
||||
) {}
|
||||
|
||||
async ngOnInit(): Promise<void> {
|
||||
await this.userService.init();
|
||||
ngOnInit(): void {
|
||||
this.createForm = this.formBuilder.group({
|
||||
accountType: ['', Validators.required],
|
||||
idNumber: ['', Validators.required],
|
||||
|
||||
@@ -30,10 +30,7 @@ export class AdminComponent implements OnInit {
|
||||
@ViewChild(MatPaginator) paginator: MatPaginator;
|
||||
@ViewChild(MatSort) sort: MatSort;
|
||||
|
||||
constructor(private userService: UserService, private loggingService: LoggingService) {}
|
||||
|
||||
async ngOnInit(): Promise<void> {
|
||||
await this.userService.init();
|
||||
constructor(private userService: UserService, private loggingService: LoggingService) {
|
||||
this.userService.getActions();
|
||||
this.userService.actionsSubject.subscribe((actions) => {
|
||||
this.dataSource = new MatTableDataSource<any>(actions);
|
||||
@@ -43,6 +40,8 @@ export class AdminComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit(): void {}
|
||||
|
||||
doFilter(value: string): void {
|
||||
this.dataSource.filter = value.trim().toLocaleLowerCase();
|
||||
}
|
||||
|
||||
@@ -23,10 +23,9 @@
|
||||
SETTINGS
|
||||
</mat-card-title>
|
||||
<div class="card-body">
|
||||
<h4>CICADA Admin Credentials</h4>
|
||||
<span><strong>UserId: </strong> {{ userInfo?.userid }} </span><br>
|
||||
<span><strong>Username: </strong> {{ userInfo?.name }} </span><br>
|
||||
<span><strong>Email: </strong> {{ userInfo?.email }} </span>
|
||||
<h4>Kobo Toolbox Credentials</h4>
|
||||
<span><strong>Username: </strong> admin_reserve </span><br>
|
||||
<span><strong>Password: </strong> ******** </span>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="card-body">
|
||||
|
||||
@@ -17,22 +17,19 @@ export class SettingsComponent implements OnInit {
|
||||
dataSource: MatTableDataSource<any>;
|
||||
displayedColumns: Array<string> = ['name', 'email', 'userId'];
|
||||
trustedUsers: Array<Staff>;
|
||||
userInfo: Staff;
|
||||
|
||||
@ViewChild(MatPaginator) paginator: MatPaginator;
|
||||
@ViewChild(MatSort) sort: MatSort;
|
||||
|
||||
constructor(private authService: AuthService) {}
|
||||
|
||||
async ngOnInit(): Promise<void> {
|
||||
await this.authService.init();
|
||||
this.authService.trustedUsersSubject.subscribe((users) => {
|
||||
this.dataSource = new MatTableDataSource<any>(users);
|
||||
this.dataSource.paginator = this.paginator;
|
||||
this.dataSource.sort = this.sort;
|
||||
this.trustedUsers = users;
|
||||
});
|
||||
this.userInfo = this.authService.getPrivateKeyInfo();
|
||||
ngOnInit(): void {
|
||||
const d = new Date();
|
||||
this.date = `${d.getDate()}/${d.getMonth()}/${d.getFullYear()}`;
|
||||
this.trustedUsers = this.authService.getTrustedUsers();
|
||||
this.dataSource = new MatTableDataSource<any>(this.trustedUsers);
|
||||
this.dataSource.paginator = this.paginator;
|
||||
this.dataSource.sort = this.sort;
|
||||
}
|
||||
|
||||
doFilter(value: string): void {
|
||||
|
||||
@@ -1,36 +1,60 @@
|
||||
<div *ngIf="token" class="mb-3 mt-1">
|
||||
<div class="card text-center">
|
||||
<mat-card-title class="card-header">
|
||||
<div class="row">
|
||||
TOKEN DETAILS
|
||||
<button mat-raised-button type="button" class="btn btn-outline-secondary ml-auto mr-2" (click)="close()"> CLOSE </button>
|
||||
</div>
|
||||
</mat-card-title>
|
||||
<div class="card-body">
|
||||
<div>
|
||||
<span><strong>Name:</strong> {{token?.name}}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span><strong>Symbol:</strong> {{token?.symbol}}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span><strong>Address:</strong> {{token?.address}}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span><strong>Details:</strong> A community inclusive currency for trading among lower to middle income societies.</span>
|
||||
</div>
|
||||
<div>
|
||||
<span><strong>Supply:</strong> {{token?.supply | tokenRatio}}</span>
|
||||
</div><br>
|
||||
<div>
|
||||
<h2>Reserve</h2>
|
||||
<div>
|
||||
<span><strong>Weight:</strong> {{token?.reserveRatio}}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span><strong>Owner:</strong> {{token?.owner}}</span>
|
||||
<!-- Begin page -->
|
||||
<div class="wrapper">
|
||||
<app-sidebar></app-sidebar>
|
||||
|
||||
<!-- ============================================================== -->
|
||||
<!-- Start Page Content here -->
|
||||
<!-- ============================================================== -->
|
||||
|
||||
<div id="content">
|
||||
<app-topbar></app-topbar>
|
||||
<!-- Start Content-->
|
||||
<div class="container-fluid text-center" appMenuSelection>
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a routerLink="/home">Home</a></li>
|
||||
<li class="breadcrumb-item"><a routerLink="/tokens">Tokens</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">{{token.name}}</li>
|
||||
</ol>
|
||||
</nav>
|
||||
<div class="col-md-6 center-body">
|
||||
<div class="card">
|
||||
<mat-card-title class="card-header">
|
||||
Token
|
||||
</mat-card-title>
|
||||
<div class="card-body">
|
||||
<div>
|
||||
<span><strong>Name:</strong> {{token.name}}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span><strong>Symbol:</strong> {{token.symbol}}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span><strong>Address:</strong> {{token.address}}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span><strong>Details:</strong> A community inclusive currency for trading among lower to middle income societies.</span>
|
||||
</div>
|
||||
<div>
|
||||
<span><strong>Supply:</strong> {{token.supply | tokenRatio}}</span>
|
||||
</div><br>
|
||||
<div>
|
||||
<h2>Reserve</h2>
|
||||
<div>
|
||||
<span><strong>Weight:</strong> {{token.reserveRatio}}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span><strong>Owner:</strong> {{token.owner}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<app-footer appMenuSelection></app-footer>
|
||||
</div>
|
||||
<!-- ============================================================== -->
|
||||
<!-- End Page content -->
|
||||
<!-- ============================================================== -->
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
EventEmitter,
|
||||
Input,
|
||||
OnInit,
|
||||
Output,
|
||||
} from '@angular/core';
|
||||
import { Token } from '@app/_models';
|
||||
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute, Params } from '@angular/router';
|
||||
import { TokenService } from '@app/_services';
|
||||
import { first } from 'rxjs/operators';
|
||||
import { Token } from '../../../_models';
|
||||
|
||||
@Component({
|
||||
selector: 'app-token-details',
|
||||
@@ -15,16 +11,18 @@ import { Token } from '@app/_models';
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class TokenDetailsComponent implements OnInit {
|
||||
@Input() token: Token;
|
||||
token: Token;
|
||||
|
||||
@Output() closeWindow: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
constructor() {}
|
||||
constructor(private route: ActivatedRoute, private tokenService: TokenService) {
|
||||
this.route.paramMap.subscribe((params: Params) => {
|
||||
this.tokenService
|
||||
.getTokenBySymbol(params.get('id'))
|
||||
.pipe(first())
|
||||
.subscribe((res) => {
|
||||
this.token = res;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit(): void {}
|
||||
|
||||
close(): void {
|
||||
this.token = null;
|
||||
this.closeWindow.emit(this.token);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,9 +24,6 @@
|
||||
</div>
|
||||
</mat-card-title>
|
||||
<div class="card-body">
|
||||
|
||||
<app-token-details [token]="token" (closeWindow)="token = $event"></app-token-details>
|
||||
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label> Filter </mat-label>
|
||||
<input matInput type="text" (keyup)="doFilter($event.target.value)" placeholder="Filter">
|
||||
|
||||
@@ -5,7 +5,8 @@ import { LoggingService, TokenService } from '@app/_services';
|
||||
import { MatTableDataSource } from '@angular/material/table';
|
||||
import { Router } from '@angular/router';
|
||||
import { exportCsv } from '@app/_helpers';
|
||||
import { Token } from '@app/_models';
|
||||
import { TokenRegistry } from '../../_eth';
|
||||
import { Token } from '../../_models';
|
||||
|
||||
@Component({
|
||||
selector: 'app-tokens',
|
||||
@@ -18,8 +19,7 @@ export class TokensComponent implements OnInit {
|
||||
columnsToDisplay: Array<string> = ['name', 'symbol', 'address', 'supply'];
|
||||
@ViewChild(MatPaginator) paginator: MatPaginator;
|
||||
@ViewChild(MatSort) sort: MatSort;
|
||||
tokens: Array<Token>;
|
||||
token: Token;
|
||||
tokens: Array<Promise<string>>;
|
||||
|
||||
constructor(
|
||||
private tokenService: TokenService,
|
||||
@@ -28,25 +28,22 @@ export class TokensComponent implements OnInit {
|
||||
) {}
|
||||
|
||||
async ngOnInit(): Promise<void> {
|
||||
await this.tokenService.init();
|
||||
this.tokenService.onload = async (status: boolean): Promise<void> => {
|
||||
await this.tokenService.getTokens();
|
||||
};
|
||||
this.tokenService.tokensSubject.subscribe((tokens) => {
|
||||
this.loggingService.sendInfoLevelMessage(tokens);
|
||||
this.dataSource = new MatTableDataSource(tokens);
|
||||
this.dataSource.paginator = this.paginator;
|
||||
this.dataSource.sort = this.sort;
|
||||
this.tokens = tokens;
|
||||
this.tokenService.LoadEvent.subscribe(async () => {
|
||||
this.tokens = await this.tokenService.getTokens();
|
||||
});
|
||||
this.tokens = await this.tokenService.getTokens();
|
||||
this.loggingService.sendInfoLevelMessage(this.tokens);
|
||||
this.dataSource = new MatTableDataSource(this.tokens);
|
||||
this.dataSource.paginator = this.paginator;
|
||||
this.dataSource.sort = this.sort;
|
||||
}
|
||||
|
||||
doFilter(value: string): void {
|
||||
this.dataSource.filter = value.trim().toLocaleLowerCase();
|
||||
}
|
||||
|
||||
viewToken(token): void {
|
||||
this.token = token;
|
||||
async viewToken(token): Promise<void> {
|
||||
await this.router.navigateByUrl(`/tokens/${token.symbol}`);
|
||||
}
|
||||
|
||||
downloadCsv(): void {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<div *ngIf="transaction" class="mb-3 mt-1">
|
||||
<div *ngIf="transaction | async" class="mb-3 mt-1">
|
||||
<div class="card text-center">
|
||||
<mat-card-title class="card-header">
|
||||
<div class="row">
|
||||
TRANSACTION DETAILS
|
||||
<button mat-raised-button type="button" class="btn btn-outline-secondary ml-auto mr-2" (click)="close()"> CLOSE </button>
|
||||
<button mat-raised-button type="button" class="btn btn-outline-secondary ml-auto mr-2" (click)="transaction = null"> CLOSE </button>
|
||||
</div>
|
||||
</mat-card-title>
|
||||
<div *ngIf="transaction.type == 'transaction'" class="card-body">
|
||||
@@ -66,7 +66,7 @@
|
||||
<span>Success: {{transaction.tx.success}}</span>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<span>Timestamp: {{transaction.tx.timestamp | unixDate}}</span>
|
||||
<span>Timestamp: {{transaction.tx.timestamp | date}}</span>
|
||||
</li>
|
||||
</ul><br>
|
||||
<div class="mb-3">
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
EventEmitter,
|
||||
Input,
|
||||
OnInit,
|
||||
Output,
|
||||
} from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { TransactionService } from '@app/_services';
|
||||
import { copyToClipboard } from '@app/_helpers';
|
||||
@@ -20,9 +13,6 @@ import { strip0x } from '@src/assets/js/ethtx/dist/hex';
|
||||
})
|
||||
export class TransactionDetailsComponent implements OnInit {
|
||||
@Input() transaction;
|
||||
|
||||
@Output() closeWindow: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
senderBloxbergLink: string;
|
||||
recipientBloxbergLink: string;
|
||||
traderBloxbergLink: string;
|
||||
@@ -33,8 +23,7 @@ export class TransactionDetailsComponent implements OnInit {
|
||||
private snackBar: MatSnackBar
|
||||
) {}
|
||||
|
||||
async ngOnInit(): Promise<void> {
|
||||
await this.transactionService.init();
|
||||
ngOnInit(): void {
|
||||
if (this.transaction?.type === 'conversion') {
|
||||
this.traderBloxbergLink =
|
||||
'https://blockexplorer.bloxberg.org/address/' + this.transaction?.trader + '/transactions';
|
||||
@@ -72,9 +61,4 @@ export class TransactionDetailsComponent implements OnInit {
|
||||
this.snackBar.open(address + ' copied successfully!', 'Close', { duration: 3000 });
|
||||
}
|
||||
}
|
||||
|
||||
close(): void {
|
||||
this.transaction = null;
|
||||
this.closeWindow.emit(this.transaction);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
</mat-card-title>
|
||||
<div class="card-body">
|
||||
|
||||
<app-transaction-details [transaction]="transaction" (closeWindow)="transaction = $event"></app-transaction-details>
|
||||
<app-transaction-details [transaction]="transaction"></app-transaction-details>
|
||||
|
||||
<div class="row card-header">
|
||||
<mat-form-field appearance="outline">
|
||||
@@ -48,12 +48,12 @@
|
||||
|
||||
<ng-container matColumnDef="sender">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header> Sender </th>
|
||||
<td mat-cell *matCellDef="let transaction"> {{transaction?.sender?.vcard.fn[0].value || transaction.from}} </td>
|
||||
<td mat-cell *matCellDef="let transaction"> {{transaction?.sender?.vcard.fn[0].value}} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="recipient">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header> Recipient </th>
|
||||
<td mat-cell *matCellDef="let transaction"> {{transaction?.recipient?.vcard.fn[0].value || transaction.to}} </td>
|
||||
<td mat-cell *matCellDef="let transaction"> {{transaction?.recipient?.vcard.fn[0].value}} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="value">
|
||||
@@ -66,7 +66,7 @@
|
||||
|
||||
<ng-container matColumnDef="created">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header> Created </th>
|
||||
<td mat-cell *matCellDef="let transaction"> {{transaction?.tx.timestamp | unixDate}} </td>
|
||||
<td mat-cell *matCellDef="let transaction"> {{transaction?.tx.timestamp | date}} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="type">
|
||||
|
||||
@@ -36,19 +36,17 @@ export class TransactionsComponent implements OnInit, AfterViewInit {
|
||||
private blockSyncService: BlockSyncService,
|
||||
private transactionService: TransactionService,
|
||||
private userService: UserService
|
||||
) {}
|
||||
) {
|
||||
this.blockSyncService.blockSync();
|
||||
}
|
||||
|
||||
async ngOnInit(): Promise<void> {
|
||||
ngOnInit(): void {
|
||||
this.transactionService.transactionsSubject.subscribe((transactions) => {
|
||||
this.transactionDataSource = new MatTableDataSource<any>(transactions);
|
||||
this.transactionDataSource.paginator = this.paginator;
|
||||
this.transactionDataSource.sort = this.sort;
|
||||
this.transactions = transactions;
|
||||
});
|
||||
await this.blockSyncService.init();
|
||||
await this.transactionService.init();
|
||||
await this.userService.init();
|
||||
await this.blockSyncService.blockSync();
|
||||
this.userService
|
||||
.getTransactionTypes()
|
||||
.pipe(first())
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
import { UnixDatePipe } from './unix-date.pipe';
|
||||
|
||||
describe('UnixDatePipe', () => {
|
||||
it('create an instance', () => {
|
||||
const pipe = new UnixDatePipe();
|
||||
expect(pipe).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -1,10 +0,0 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
|
||||
@Pipe({
|
||||
name: 'unixDate',
|
||||
})
|
||||
export class UnixDatePipe implements PipeTransform {
|
||||
transform(timestamp: number, ...args: unknown[]): any {
|
||||
return new Date(timestamp * 1000).toLocaleDateString('en-GB');
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,5 @@
|
||||
<!-- Footer Start -->
|
||||
<footer class="footer">
|
||||
<a target="blank" title="GPL-3" href="https://www.gnu.org/licenses/gpl-3.0.en.html"> Copyleft </a> 🄯.
|
||||
{{ currentYear }}
|
||||
<a target="blank" title="Gitlab@GrassrootsEconomics" href="https://gitlab.com/grassrootseconomics"><u> Grassroots Economics </u></a>
|
||||
|
||||
2020 © Grassroots Economics
|
||||
</footer>
|
||||
<!-- end Footer -->
|
||||
|
||||
@@ -7,7 +7,6 @@ import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class FooterComponent implements OnInit {
|
||||
currentYear = new Date().getFullYear();
|
||||
constructor() {}
|
||||
|
||||
ngOnInit(): void {}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<nav class="navbar navbar-dark background-dark">
|
||||
<nav class="navbar navbar-dark bg-dark">
|
||||
<h1 class="navbar-brand">
|
||||
<div *ngIf="noInternetConnection; then offlineBlock else onlineBlock"></div>
|
||||
<ng-template #offlineBlock>
|
||||
|
||||
@@ -12,7 +12,6 @@ import { ErrorDialogComponent } from '@app/shared/error-dialog/error-dialog.comp
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { SafePipe } from '@app/shared/_pipes/safe.pipe';
|
||||
import { NetworkStatusComponent } from './network-status/network-status.component';
|
||||
import { UnixDatePipe } from './_pipes/unix-date.pipe';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
@@ -25,7 +24,6 @@ import { UnixDatePipe } from './_pipes/unix-date.pipe';
|
||||
ErrorDialogComponent,
|
||||
SafePipe,
|
||||
NetworkStatusComponent,
|
||||
UnixDatePipe,
|
||||
],
|
||||
exports: [
|
||||
TopbarComponent,
|
||||
@@ -35,7 +33,6 @@ import { UnixDatePipe } from './_pipes/unix-date.pipe';
|
||||
TokenRatioPipe,
|
||||
SafePipe,
|
||||
NetworkStatusComponent,
|
||||
UnixDatePipe,
|
||||
],
|
||||
imports: [CommonModule, RouterModule, MatIconModule, MatDialogModule],
|
||||
})
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<!-- ========== Left Sidebar Start ========== -->
|
||||
<div id="sidebar">
|
||||
<app-network-status></app-network-status>
|
||||
<nav>
|
||||
|
||||
<div class="sidebar-header">
|
||||
|
||||
@@ -42,7 +42,7 @@ Driver.prototype.sync = function (n) {
|
||||
const processor = async (b, t) => {
|
||||
return await self.process(b, t);
|
||||
};
|
||||
self.syncer(self.lo, self.hi, self.filters[0], self.filters[1], countGetter, processor);
|
||||
self.syncer(self, self.lo, self.hi, self.filters[0], self.filters[1], countGetter, processor);
|
||||
};
|
||||
|
||||
Driver.prototype.process = function (b, t) {
|
||||
|
||||
@@ -10,7 +10,7 @@ export const environment = {
|
||||
publicKeysUrl: 'https://dev.grassrootseconomics.net/.well-known/publickeys/',
|
||||
cicCacheUrl: 'https://cache.dev.grassrootseconomics.net',
|
||||
web3Provider: 'wss://bloxberg-ws.dev.grassrootseconomics.net',
|
||||
cicUssdUrl: 'https://user.dev.grassrootseconomics.net',
|
||||
cicUssdUrl: 'https://ussd.dev.grassrootseconomics.net',
|
||||
registryAddress: '0xea6225212005e86a4490018ded4bf37f3e772161',
|
||||
trustedDeclaratorAddress: '0xEb3907eCad74a0013c259D5874AE7f22DcBcC95C',
|
||||
};
|
||||
|
||||
@@ -10,7 +10,7 @@ export const environment = {
|
||||
publicKeysUrl: 'https://dev.grassrootseconomics.net/.well-known/publickeys/',
|
||||
cicCacheUrl: 'https://cache.dev.grassrootseconomics.net',
|
||||
web3Provider: 'wss://bloxberg-ws.dev.grassrootseconomics.net',
|
||||
cicUssdUrl: 'https://user.dev.grassrootseconomics.net',
|
||||
cicUssdUrl: 'https://ussd.dev.grassrootseconomics.net',
|
||||
registryAddress: '0xea6225212005e86a4490018ded4bf37f3e772161',
|
||||
trustedDeclaratorAddress: '0xEb3907eCad74a0013c259D5874AE7f22DcBcC95C',
|
||||
};
|
||||
|
||||
@@ -10,7 +10,7 @@ export const environment = {
|
||||
publicKeysUrl: 'https://dev.grassrootseconomics.net/.well-known/publickeys/',
|
||||
cicCacheUrl: 'https://cache.dev.grassrootseconomics.net',
|
||||
web3Provider: 'wss://bloxberg-ws.dev.grassrootseconomics.net',
|
||||
cicUssdUrl: 'https://user.dev.grassrootseconomics.net',
|
||||
cicUssdUrl: 'https://ussd.dev.grassrootseconomics.net',
|
||||
registryAddress: '0xea6225212005e86a4490018ded4bf37f3e772161',
|
||||
trustedDeclaratorAddress: '0xEb3907eCad74a0013c259D5874AE7f22DcBcC95C',
|
||||
};
|
||||
|
||||
@@ -18,8 +18,8 @@ body {
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
.background-dark {
|
||||
background: #313a46 !important;
|
||||
.bg-dark {
|
||||
background: #313a46;
|
||||
}
|
||||
|
||||
p {
|
||||
|
||||
Reference in New Issue
Block a user