From fcc82ab7ccdf572f833c50f4605db56cbe908ca6 Mon Sep 17 00:00:00 2001 From: bernd2022 <104787072+bernd2022@users.noreply.github.com> Date: Fri, 10 Jan 2025 09:30:22 +0100 Subject: [PATCH 01/13] [DEV-3452] dEuro Logs (#1888) * [DEV-3452] dEuro Logs * [DEV-3452] rename eurocoin to deuro * [DEV-3452] changes after review --- .vscode/settings.json | 1 + package-lock.json | 1412 ++++++++++++++--- package.json | 2 + src/config/config.ts | 7 + .../blockchain/blockchain.module.ts | 3 + .../deuro/controllers/deuro.controller.ts | 15 + .../blockchain/deuro/deuro-client.ts | 74 + .../blockchain/deuro/deuro.module.ts | 13 + .../blockchain/deuro/deuro.service.ts | 196 +++ .../blockchain/deuro/dto/deuro.dto.ts | 68 + src/shared/services/process.service.ts | 1 + 11 files changed, 1609 insertions(+), 183 deletions(-) create mode 100644 src/integration/blockchain/deuro/controllers/deuro.controller.ts create mode 100644 src/integration/blockchain/deuro/deuro-client.ts create mode 100644 src/integration/blockchain/deuro/deuro.module.ts create mode 100644 src/integration/blockchain/deuro/deuro.service.ts create mode 100644 src/integration/blockchain/deuro/dto/deuro.dto.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index f0c038014f..e181d4e1fc 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -13,6 +13,7 @@ "citizenships", "datas", "datetime", + "deuro", "dfip", "dilisense", "firstname", diff --git a/package-lock.json b/package-lock.json index 6bf664fc4a..b7c2e52442 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "@defichain/jellyfish-api-jsonrpc": "^3.30.1", "@defichain/jellyfish-network": "^3.30.1", "@defichain/whale-api-client": "^3.30.1", + "@deuro/eurocoin": "^1.0.7", "@dhedge/v2-sdk": "^1.9.8", "@eth-optimism/sdk": "^3.2.0", "@maticnetwork/maticjs": "^3.7.8", @@ -85,6 +86,7 @@ "swagger-ui-express": "^4.6.2", "swissqrbill": "^4.0.2", "typeorm": "^0.3.12", + "viem": "^1.0.6", "xoauth2": "^1.2.0", "zbase32": "^1.0.5" }, @@ -795,7 +797,6 @@ "version": "7.24.2", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", - "dev": true, "dependencies": { "@babel/highlight": "^7.24.2", "picocolors": "^1.0.0" @@ -1077,7 +1078,6 @@ "version": "7.24.5", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.5.tgz", "integrity": "sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==", - "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.24.5", "chalk": "^2.4.2", @@ -1092,7 +1092,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "dependencies": { "color-convert": "^1.9.0" }, @@ -1104,7 +1103,6 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -1118,7 +1116,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "dependencies": { "color-name": "1.1.3" } @@ -1126,14 +1123,12 @@ "node_modules/@babel/highlight/node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "node_modules/@babel/highlight/node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, "engines": { "node": ">=4" } @@ -1142,7 +1137,6 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, "dependencies": { "has-flag": "^3.0.0" }, @@ -1481,8 +1475,6 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", - "dev": true, - "optional": true, "engines": { "node": ">=0.1.90" } @@ -1491,7 +1483,6 @@ "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "devOptional": true, "dependencies": { "@jridgewell/trace-mapping": "0.3.9" }, @@ -1503,7 +1494,6 @@ "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "devOptional": true, "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -1710,6 +1700,50 @@ "defichain": "^3.30.1" } }, + "node_modules/@deuro/eurocoin": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@deuro/eurocoin/-/eurocoin-1.0.7.tgz", + "integrity": "sha512-SaecZkY/TAaSQ8Nvx7ZptwaUvyvVv3sJDWkXjzelA6Ze5cOHrDYS3JHZO/AxjSLK5lSX81SvYEMEoT4xDSvePQ==", + "license": "MIT", + "dependencies": { + "hardhat-abi-exporter": "^2.10.0", + "hardhat-contract-sizer": "^2.5.1", + "prettier": "^3.3.3", + "prettier-plugin-solidity": "^1.4.1", + "prompt": "^1.3.0", + "solhint": "^5.0.3", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } + }, + "node_modules/@deuro/eurocoin/node_modules/prettier": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz", + "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==", + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/@deuro/eurocoin/node_modules/typescript": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", + "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/@dhedge/v2-sdk": { "version": "1.10.5", "resolved": "https://registry.npmjs.org/@dhedge/v2-sdk/-/v2-sdk-1.10.5.tgz", @@ -4427,7 +4461,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "devOptional": true, "engines": { "node": ">=6.0.0" } @@ -4454,8 +4487,7 @@ "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.14", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "devOptional": true + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.17", @@ -6010,6 +6042,47 @@ "node": ">=14" } }, + "node_modules/@pnpm/config.env-replace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", + "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", + "license": "MIT", + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", + "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", + "license": "MIT", + "dependencies": { + "graceful-fs": "4.2.10" + }, + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file/node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "license": "ISC" + }, + "node_modules/@pnpm/npm-conf": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.3.1.tgz", + "integrity": "sha512-c83qWb22rNRuB0UaVCI0uRPNRr8Z0FWnEIvT47jiHAmOIUHbBOg5XvV7pM5x+rKn9HRpjxquDbXYSXr3fAKFcw==", + "license": "MIT", + "dependencies": { + "@pnpm/config.env-replace": "^1.1.0", + "@pnpm/network.ca-file": "^1.0.1", + "config-chain": "^1.1.11" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", @@ -6527,6 +6600,12 @@ "optional": true, "peer": true }, + "node_modules/@solidity-parser/parser": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.19.0.tgz", + "integrity": "sha512-RV16k/qIxW/wWc+mLzV3ARyKUaMUTBy9tOLMzFhtNSKYeTAanQ3a5MudJKf/8arIFnA2L27SNjarQKmFg0w/jA==", + "license": "MIT" + }, "node_modules/@sqltools/formatter": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.5.tgz", @@ -6660,26 +6739,22 @@ "node_modules/@tsconfig/node10": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", - "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==", - "devOptional": true + "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==" }, "node_modules/@tsconfig/node12": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", - "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==", - "devOptional": true + "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==" }, "node_modules/@tsconfig/node14": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", - "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", - "devOptional": true + "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==" }, "node_modules/@tsconfig/node16": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", - "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", - "devOptional": true + "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==" }, "node_modules/@types/babel__core": { "version": "7.20.0", @@ -8089,7 +8164,6 @@ "version": "8.11.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "devOptional": true, "bin": { "acorn": "bin/acorn" }, @@ -8119,7 +8193,6 @@ "version": "8.2.0", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "devOptional": true, "engines": { "node": ">=0.4.0" } @@ -8364,6 +8437,15 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/antlr4": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/antlr4/-/antlr4-4.13.2.tgz", + "integrity": "sha512-QiVbZhyy4xAZ17UPEuG3YTOt8ZaoeOR1CvEAqrEsDBsOqINslaB147i9xqljZqoyf5S+EUlGStaj+t22LT9MOg==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=16" + } + }, "node_modules/any-promise": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", @@ -8465,8 +8547,7 @@ "node_modules/arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "devOptional": true + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" }, "node_modules/argparse": { "version": "2.0.1", @@ -8595,6 +8676,21 @@ "node": "*" } }, + "node_modules/ast-parents": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/ast-parents/-/ast-parents-0.0.1.tgz", + "integrity": "sha512-XHusKxKz3zoYk1ic8Un640joHbFMhbqneyoZfoKnEGtf2ey9Uh/IdpcQplODdO/kENaMIWsD0nJm4+wX3UNLHA==", + "license": "MIT" + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/async": { "version": "3.2.6", "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", @@ -9627,7 +9723,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, "engines": { "node": ">=6" } @@ -10125,7 +10220,6 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", - "dev": true, "dependencies": { "string-width": "^4.2.0" }, @@ -10244,6 +10338,15 @@ "color-support": "bin.js" } }, + "node_modules/colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw==", + "license": "MIT", + "engines": { + "node": ">=0.1.90" + } + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -10478,8 +10581,7 @@ "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "devOptional": true + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" }, "node_modules/cron": { "version": "2.3.1", @@ -10551,6 +10653,14 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/cycle": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", + "integrity": "sha512-TVF6svNzeQCOpjCqsy0/CSy8VgObG3wXusJ73xW2GbG5rGx7lC8zxDSURicsXI2UsGdi2L0QNRCi745/wUDvsA==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/d": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", @@ -10854,6 +10964,37 @@ "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" }, + "node_modules/delete-empty": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/delete-empty/-/delete-empty-3.0.0.tgz", + "integrity": "sha512-ZUyiwo76W+DYnKsL3Kim6M/UOavPdBJgDYWOmuQhYaZvJH0AXAHbUNyEDtRbBra8wqqr686+63/0azfEk1ebUQ==", + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.0", + "minimist": "^1.2.0", + "path-starts-with": "^2.0.0", + "rimraf": "^2.6.2" + }, + "bin": { + "delete-empty": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/delete-empty/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -10943,7 +11084,6 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "devOptional": true, "engines": { "node": ">=0.3.1" } @@ -11445,7 +11585,6 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, "dependencies": { "is-arrayish": "^0.2.1" } @@ -12582,6 +12721,14 @@ "node >=0.6.0" ] }, + "node_modules/eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==", + "engines": { + "node": "> 0.1.90" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -12590,8 +12737,7 @@ "node_modules/fast-diff": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", - "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", - "dev": true + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==" }, "node_modules/fast-glob": { "version": "3.3.2", @@ -12630,6 +12776,22 @@ "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.6.tgz", "integrity": "sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w==" }, + "node_modules/fast-uri": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.5.tgz", + "integrity": "sha512-5JnBCWpFlMo0a3ciDy/JckMzzv1U9coZrIhedq+HXxxUfDTAiS0LA8OKVao4G9BxmCVck/jtA5r3KAtRWEyD8Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/fast-xml-parser": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz", @@ -13738,6 +13900,36 @@ } } }, + "node_modules/hardhat-abi-exporter": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/hardhat-abi-exporter/-/hardhat-abi-exporter-2.10.1.tgz", + "integrity": "sha512-X8GRxUTtebMAd2k4fcPyVnCdPa6dYK4lBsrwzKP5yiSq4i+WadWPIumaLfce53TUf/o2TnLpLOduyO1ylE2NHQ==", + "license": "MIT", + "dependencies": { + "@ethersproject/abi": "^5.5.0", + "delete-empty": "^3.0.0" + }, + "engines": { + "node": ">=14.14.0" + }, + "peerDependencies": { + "hardhat": "^2.0.0" + } + }, + "node_modules/hardhat-contract-sizer": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/hardhat-contract-sizer/-/hardhat-contract-sizer-2.10.0.tgz", + "integrity": "sha512-QiinUgBD5MqJZJh1hl1jc9dNnpJg7eE/w4/4GEnrcmZJJTDbVFNe3+/3Ep24XqISSkYxRz36czcPHKHd/a0dwA==", + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "cli-table3": "^0.6.0", + "strip-ansi": "^6.0.0" + }, + "peerDependencies": { + "hardhat": "^2.0.0" + } + }, "node_modules/hardhat-watcher": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/hardhat-watcher/-/hardhat-watcher-2.5.0.tgz", @@ -14328,10 +14520,10 @@ ] }, "node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "dev": true, + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "license": "MIT", "engines": { "node": ">= 4" } @@ -14351,7 +14543,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -14534,8 +14725,7 @@ "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" }, "node_modules/is-bigint": { "version": "1.0.4", @@ -15016,6 +15206,15 @@ "is-stream": "^1.0.1" } }, + "node_modules/isomorphic-ws": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz", + "integrity": "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==", + "license": "MIT", + "peerDependencies": { + "ws": "*" + } + }, "node_modules/isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -16087,8 +16286,7 @@ "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "node_modules/js-yaml": { "version": "4.1.0", @@ -16131,8 +16329,7 @@ "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, "node_modules/json-schema": { "version": "0.4.0", @@ -16348,6 +16545,21 @@ "node": ">=6" } }, + "node_modules/latest-version": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz", + "integrity": "sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==", + "license": "MIT", + "dependencies": { + "package-json": "^8.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/leac": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/leac/-/leac-0.6.0.tgz", @@ -16548,8 +16760,7 @@ "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, "node_modules/linkify-it": { "version": "5.0.0", @@ -16810,6 +17021,12 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "license": "MIT" + }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -16865,17 +17082,6 @@ "integrity": "sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==", "peer": true }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/luxon": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.5.0.tgz", @@ -16994,8 +17200,7 @@ "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "devOptional": true + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" }, "node_modules/makeerror": { "version": "1.0.12", @@ -18221,8 +18426,7 @@ "node_modules/mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" }, "node_modules/mv": { "version": "2.1.1", @@ -18905,6 +19109,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/package-json": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.1.tgz", + "integrity": "sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==", + "license": "MIT", + "dependencies": { + "got": "^12.1.0", + "registry-auth-token": "^5.0.1", + "registry-url": "^6.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/package-json-from-dist": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", @@ -18927,7 +19149,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, "dependencies": { "callsites": "^3.0.0" }, @@ -18944,7 +19165,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -19085,6 +19305,15 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/path-starts-with": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-starts-with/-/path-starts-with-2.0.1.tgz", + "integrity": "sha512-wZ3AeiRBRlNwkdUxvBANh0+esnt38DLffHDujZyRHkqkaKHTglnY2EP5UX3b8rdeiSutgO4y9NEJwXezNP5vHg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/path-to-regexp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.2.0.tgz", @@ -19094,7 +19323,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, "engines": { "node": ">=8" } @@ -19155,8 +19383,7 @@ "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" }, "node_modules/picomatch": { "version": "2.3.1", @@ -19246,7 +19473,6 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", - "dev": true, "engines": { "node": ">=4" } @@ -19277,7 +19503,6 @@ "version": "2.8.7", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.7.tgz", "integrity": "sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==", - "dev": true, "bin": { "prettier": "bin-prettier.js" }, @@ -19300,6 +19525,22 @@ "node": ">=6.0.0" } }, + "node_modules/prettier-plugin-solidity": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.4.2.tgz", + "integrity": "sha512-VVD/4XlDjSzyPWWCPW8JEleFa8JNKFYac5kNlMjVXemQyQZKfpekPMhFZSePuXB6L+RixlFvWe20iacGjFYrLw==", + "license": "MIT", + "dependencies": { + "@solidity-parser/parser": "^0.19.0", + "semver": "^7.6.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "prettier": ">=2.3.0" + } + }, "node_modules/pretty-format": { "version": "29.5.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", @@ -19390,6 +19631,28 @@ "asap": "~2.0.3" } }, + "node_modules/prompt": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/prompt/-/prompt-1.3.0.tgz", + "integrity": "sha512-ZkaRWtaLBZl7KKAKndKYUL8WqNT+cQHKRZnT4RYYms48jQkFw3rrBL+/N5K/KtdEveHkxs982MX2BkDKub2ZMg==", + "license": "MIT", + "dependencies": { + "@colors/colors": "1.5.0", + "async": "3.2.3", + "read": "1.0.x", + "revalidator": "0.1.x", + "winston": "2.x" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/prompt/node_modules/async": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", + "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==", + "license": "MIT" + }, "node_modules/prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", @@ -19718,6 +19981,18 @@ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, + "node_modules/read": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", + "integrity": "sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==", + "license": "ISC", + "dependencies": { + "mute-stream": "~0.0.4" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", @@ -19782,6 +20057,33 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/registry-auth-token": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.3.tgz", + "integrity": "sha512-1bpc9IyC+e+CNFRaWyn77tk4xGG4PPUyfakSmA6F6cvUDjrm58dfyJ3II+9yb10EDkHoy1LaPSmHaWLOH3m6HA==", + "license": "MIT", + "dependencies": { + "@pnpm/npm-conf": "^2.1.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/registry-url": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz", + "integrity": "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==", + "license": "MIT", + "dependencies": { + "rc": "1.2.8" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/relateurl": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", @@ -19863,7 +20165,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -19948,7 +20249,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, "engines": { "node": ">=4" } @@ -20017,6 +20317,15 @@ "node": ">=0.10.0" } }, + "node_modules/revalidator": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/revalidator/-/revalidator-0.1.8.tgz", + "integrity": "sha512-xcBILK2pA9oh4SiinPEZfhP8HfrB/ha+a2fTMyl7Om2WjlDVrOQy99N2MXXlUHqGJz4qEu2duXxHJjDWuK/0xg==", + "license": "Apache 2.0", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/rfdc": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", @@ -20382,12 +20691,10 @@ } }, "node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "dependencies": { - "lru-cache": "^6.0.0" - }, + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -20647,6 +20954,23 @@ "node": ">=8" } }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, "node_modules/slick": { "version": "1.12.2", "resolved": "https://registry.npmjs.org/slick/-/slick-1.12.2.tgz", @@ -20922,6 +21246,114 @@ "semver": "bin/semver" } }, + "node_modules/solhint": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/solhint/-/solhint-5.0.4.tgz", + "integrity": "sha512-GzKBjJ8S2utRsEOCJXhY2H35gwHGmoQY2rQXcPGT4XdDlzwgGYz0Ovo9Xm7cmWYgSo121uF+5tiwrqQT2b+Rtw==", + "license": "MIT", + "dependencies": { + "@solidity-parser/parser": "^0.19.0", + "ajv": "^6.12.6", + "antlr4": "^4.13.1-patch-1", + "ast-parents": "^0.0.1", + "chalk": "^4.1.2", + "commander": "^10.0.0", + "cosmiconfig": "^8.0.0", + "fast-diff": "^1.2.0", + "glob": "^8.0.3", + "ignore": "^5.2.4", + "js-yaml": "^4.1.0", + "latest-version": "^7.0.0", + "lodash": "^4.17.21", + "pluralize": "^8.0.0", + "semver": "^7.5.2", + "strip-ansi": "^6.0.1", + "table": "^6.8.1", + "text-table": "^0.2.0" + }, + "bin": { + "solhint": "solhint.js" + }, + "optionalDependencies": { + "prettier": "^2.8.3" + } + }, + "node_modules/solhint/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/solhint/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/solhint/node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "license": "MIT", + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/solhint/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/solhint/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/source-map": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", @@ -20999,6 +21431,15 @@ "resolved": "https://registry.npmjs.org/stack-chain/-/stack-chain-1.3.7.tgz", "integrity": "sha1-0ZLJ/06moiyUxN1FkXHj8AzqEoU=" }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/stack-utils": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", @@ -21660,6 +22101,44 @@ "node": ">=0.10" } }, + "node_modules/table": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz", + "integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==", + "license": "BSD-3-Clause", + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, "node_modules/tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -21886,8 +22365,7 @@ "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" }, "node_modules/thenify": { "version": "3.3.1", @@ -22125,7 +22603,6 @@ "version": "10.9.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", - "devOptional": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -22663,7 +23140,6 @@ "version": "4.9.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "devOptional": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -22878,8 +23354,7 @@ "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "devOptional": true + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" }, "node_modules/v8-to-istanbul": { "version": "9.1.0", @@ -22951,6 +23426,163 @@ "extsprintf": "^1.2.0" } }, + "node_modules/viem": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/viem/-/viem-1.0.6.tgz", + "integrity": "sha512-NOVDREj8bWHajuP5Nw6edd0v3auuGWvLHGScmo9OOt1l7g3f1xMQxPA6JlhNmWXzoHjzzxt/5SorBn2DQ6N6Sg==", + "license": "MIT", + "dependencies": { + "@adraffy/ens-normalize": "1.9.0", + "@noble/curves": "1.0.0", + "@noble/hashes": "1.3.0", + "@scure/bip32": "1.3.0", + "@scure/bip39": "1.2.0", + "@wagmi/chains": "1.1.0", + "abitype": "0.8.7", + "isomorphic-ws": "5.0.0", + "ws": "8.12.0" + } + }, + "node_modules/viem/node_modules/@adraffy/ens-normalize": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.9.0.tgz", + "integrity": "sha512-iowxq3U30sghZotgl4s/oJRci6WPBfNO5YYgk2cIOMCHr3LeGPcsZjCEr+33Q4N+oV3OABDAtA+pyvWjbvBifQ==", + "license": "MIT" + }, + "node_modules/viem/node_modules/@noble/curves": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.0.0.tgz", + "integrity": "sha512-2upgEu0iLiDVDZkNLeFV2+ht0BAVgQnEmCk6JsOch9Rp8xfkMCbvbAZlA2pBHQc73dbl+vFOXfqkf4uemdn0bw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.3.0" + } + }, + "node_modules/viem/node_modules/@noble/hashes": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.0.tgz", + "integrity": "sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT" + }, + "node_modules/viem/node_modules/@scure/bip32": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.0.tgz", + "integrity": "sha512-bcKpo1oj54hGholplGLpqPHRbIsnbixFtc06nwuNM5/dwSXOq/AAYoIBRsBmnZJSdfeNW5rnff7NTAz3ZCqR9Q==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.0.0", + "@noble/hashes": "~1.3.0", + "@scure/base": "~1.1.0" + } + }, + "node_modules/viem/node_modules/@scure/bip39": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.0.tgz", + "integrity": "sha512-SX/uKq52cuxm4YFXWFaVByaSHJh2w3BnokVSeUJVCv6K7WulT9u2BuNRBhuFl8vAuYnzx9bEu9WgpcNYTrYieg==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.3.0", + "@scure/base": "~1.1.0" + } + }, + "node_modules/viem/node_modules/@wagmi/chains": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@wagmi/chains/-/chains-1.1.0.tgz", + "integrity": "sha512-pWZlxBk0Ql8E7DV8DwqlbBpOyUdaG9UDlQPBxJNALuEK1I0tbQ3AVvSDnlsEIt06UPmPo5o27gzs3hwPQ/A+UA==", + "funding": [ + { + "type": "gitcoin", + "url": "https://wagmi.sh/gitcoin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/wagmi-dev" + } + ], + "license": "MIT", + "peerDependencies": { + "typescript": ">=5.0.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/viem/node_modules/abitype": { + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/abitype/-/abitype-0.8.7.tgz", + "integrity": "sha512-wQ7hV8Yg/yKmGyFpqrNZufCxbszDe5es4AZGYPBitocfSqXtjrTG9JMWFcc4N30ukl2ve48aBTwt7NJxVQdU3w==", + "license": "MIT", + "peerDependencies": { + "typescript": ">=5.0.4", + "zod": "^3 >=3.19.1" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, + "node_modules/viem/node_modules/typescript": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", + "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/viem/node_modules/ws": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.12.0.tgz", + "integrity": "sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/void-elements": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", @@ -23873,6 +24505,32 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/winston": { + "version": "2.4.7", + "resolved": "https://registry.npmjs.org/winston/-/winston-2.4.7.tgz", + "integrity": "sha512-vLB4BqzCKDnnZH9PHGoS2ycawueX4HLqENXQitvFHczhgW2vFpSOn31LZtVr1KU8YTw7DS4tM+cqyovxo8taVg==", + "license": "MIT", + "dependencies": { + "async": "^2.6.4", + "colors": "1.0.x", + "cycle": "1.0.x", + "eyes": "0.1.x", + "isstream": "0.1.x", + "stack-trace": "0.0.x" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/winston/node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.14" + } + }, "node_modules/with": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/with/-/with-7.0.2.tgz", @@ -24122,7 +24780,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "devOptional": true, "engines": { "node": ">=6" } @@ -24678,7 +25335,6 @@ "version": "7.24.2", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", - "dev": true, "requires": { "@babel/highlight": "^7.24.2", "picocolors": "^1.0.0" @@ -24892,7 +25548,6 @@ "version": "7.24.5", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.5.tgz", "integrity": "sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==", - "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.24.5", "chalk": "^2.4.2", @@ -24904,7 +25559,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "requires": { "color-convert": "^1.9.0" } @@ -24913,7 +25567,6 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -24924,7 +25577,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "requires": { "color-name": "1.1.3" } @@ -24932,20 +25584,17 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, "requires": { "has-flag": "^3.0.0" } @@ -25196,15 +25845,12 @@ "@colors/colors": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", - "dev": true, - "optional": true + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==" }, "@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "devOptional": true, "requires": { "@jridgewell/trace-mapping": "0.3.9" }, @@ -25213,7 +25859,6 @@ "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "devOptional": true, "requires": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -25332,6 +25977,33 @@ "url-search-params-polyfill": "8.1.1" } }, + "@deuro/eurocoin": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@deuro/eurocoin/-/eurocoin-1.0.7.tgz", + "integrity": "sha512-SaecZkY/TAaSQ8Nvx7ZptwaUvyvVv3sJDWkXjzelA6Ze5cOHrDYS3JHZO/AxjSLK5lSX81SvYEMEoT4xDSvePQ==", + "requires": { + "hardhat-abi-exporter": "^2.10.0", + "hardhat-contract-sizer": "^2.5.1", + "prettier": "^3.3.3", + "prettier-plugin-solidity": "^1.4.1", + "prompt": "^1.3.0", + "solhint": "^5.0.3", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + }, + "dependencies": { + "prettier": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz", + "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==" + }, + "typescript": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", + "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==" + } + } + }, "@dhedge/v2-sdk": { "version": "1.10.5", "resolved": "https://registry.npmjs.org/@dhedge/v2-sdk/-/v2-sdk-1.10.5.tgz", @@ -27282,8 +27954,7 @@ "@jridgewell/resolve-uri": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "devOptional": true + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" }, "@jridgewell/set-array": { "version": "1.1.2", @@ -27304,8 +27975,7 @@ "@jridgewell/sourcemap-codec": { "version": "1.4.14", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "devOptional": true + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" }, "@jridgewell/trace-mapping": { "version": "0.3.17", @@ -28318,6 +28988,36 @@ "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "optional": true }, + "@pnpm/config.env-replace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", + "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==" + }, + "@pnpm/network.ca-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", + "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", + "requires": { + "graceful-fs": "4.2.10" + }, + "dependencies": { + "graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + } + } + }, + "@pnpm/npm-conf": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.3.1.tgz", + "integrity": "sha512-c83qWb22rNRuB0UaVCI0uRPNRr8Z0FWnEIvT47jiHAmOIUHbBOg5XvV7pM5x+rKn9HRpjxquDbXYSXr3fAKFcw==", + "requires": { + "@pnpm/config.env-replace": "^1.1.0", + "@pnpm/network.ca-file": "^1.0.1", + "config-chain": "^1.1.11" + } + }, "@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", @@ -28743,6 +29443,11 @@ "optional": true, "peer": true }, + "@solidity-parser/parser": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.19.0.tgz", + "integrity": "sha512-RV16k/qIxW/wWc+mLzV3ARyKUaMUTBy9tOLMzFhtNSKYeTAanQ3a5MudJKf/8arIFnA2L27SNjarQKmFg0w/jA==" + }, "@sqltools/formatter": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.5.tgz", @@ -28866,26 +29571,22 @@ "@tsconfig/node10": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", - "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==", - "devOptional": true + "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==" }, "@tsconfig/node12": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", - "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==", - "devOptional": true + "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==" }, "@tsconfig/node14": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", - "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", - "devOptional": true + "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==" }, "@tsconfig/node16": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", - "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", - "devOptional": true + "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==" }, "@types/babel__core": { "version": "7.20.0", @@ -30092,8 +30793,7 @@ "acorn": { "version": "8.11.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "devOptional": true + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==" }, "acorn-import-assertions": { "version": "1.8.0", @@ -30112,8 +30812,7 @@ "acorn-walk": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "devOptional": true + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==" }, "adm-zip": { "version": "0.4.16", @@ -30290,6 +30989,11 @@ "color-convert": "^2.0.1" } }, + "antlr4": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/antlr4/-/antlr4-4.13.2.tgz", + "integrity": "sha512-QiVbZhyy4xAZ17UPEuG3YTOt8ZaoeOR1CvEAqrEsDBsOqINslaB147i9xqljZqoyf5S+EUlGStaj+t22LT9MOg==" + }, "any-promise": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", @@ -30370,8 +31074,7 @@ "arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "devOptional": true + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" }, "argparse": { "version": "2.0.1", @@ -30475,6 +31178,16 @@ "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==" }, + "ast-parents": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/ast-parents/-/ast-parents-0.0.1.tgz", + "integrity": "sha512-XHusKxKz3zoYk1ic8Un640joHbFMhbqneyoZfoKnEGtf2ey9Uh/IdpcQplODdO/kENaMIWsD0nJm4+wX3UNLHA==" + }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==" + }, "async": { "version": "3.2.6", "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", @@ -31293,8 +32006,7 @@ "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" }, "camel-case": { "version": "3.0.0", @@ -31647,7 +32359,6 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", - "dev": true, "requires": { "@colors/colors": "1.5.0", "string-width": "^4.2.0" @@ -31738,6 +32449,11 @@ "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==" }, + "colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw==" + }, "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -31929,8 +32645,7 @@ "create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "devOptional": true + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" }, "cron": { "version": "2.3.1", @@ -31985,6 +32700,11 @@ "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==" }, + "cycle": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", + "integrity": "sha512-TVF6svNzeQCOpjCqsy0/CSy8VgObG3wXusJ73xW2GbG5rGx7lC8zxDSURicsXI2UsGdi2L0QNRCi745/wUDvsA==" + }, "d": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", @@ -32202,6 +32922,27 @@ "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" }, + "delete-empty": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/delete-empty/-/delete-empty-3.0.0.tgz", + "integrity": "sha512-ZUyiwo76W+DYnKsL3Kim6M/UOavPdBJgDYWOmuQhYaZvJH0AXAHbUNyEDtRbBra8wqqr686+63/0azfEk1ebUQ==", + "requires": { + "ansi-colors": "^4.1.0", + "minimist": "^1.2.0", + "path-starts-with": "^2.0.0", + "rimraf": "^2.6.2" + }, + "dependencies": { + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + } + } + }, "depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -32271,8 +33012,7 @@ "diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "devOptional": true + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" }, "diff-sequences": { "version": "29.4.3", @@ -32647,7 +33387,6 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, "requires": { "is-arrayish": "^0.2.1" } @@ -33540,6 +34279,11 @@ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==" }, + "eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==" + }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -33548,8 +34292,7 @@ "fast-diff": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", - "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", - "dev": true + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==" }, "fast-glob": { "version": "3.3.2", @@ -33585,6 +34328,11 @@ "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.6.tgz", "integrity": "sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w==" }, + "fast-uri": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.5.tgz", + "integrity": "sha512-5JnBCWpFlMo0a3ciDy/JckMzzv1U9coZrIhedq+HXxxUfDTAiS0LA8OKVao4G9BxmCVck/jtA5r3KAtRWEyD8Q==" + }, "fast-xml-parser": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz", @@ -34511,6 +35259,25 @@ } } }, + "hardhat-abi-exporter": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/hardhat-abi-exporter/-/hardhat-abi-exporter-2.10.1.tgz", + "integrity": "sha512-X8GRxUTtebMAd2k4fcPyVnCdPa6dYK4lBsrwzKP5yiSq4i+WadWPIumaLfce53TUf/o2TnLpLOduyO1ylE2NHQ==", + "requires": { + "@ethersproject/abi": "^5.5.0", + "delete-empty": "^3.0.0" + } + }, + "hardhat-contract-sizer": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/hardhat-contract-sizer/-/hardhat-contract-sizer-2.10.0.tgz", + "integrity": "sha512-QiinUgBD5MqJZJh1hl1jc9dNnpJg7eE/w4/4GEnrcmZJJTDbVFNe3+/3Ep24XqISSkYxRz36czcPHKHd/a0dwA==", + "requires": { + "chalk": "^4.0.0", + "cli-table3": "^0.6.0", + "strip-ansi": "^6.0.0" + } + }, "hardhat-watcher": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/hardhat-watcher/-/hardhat-watcher-2.5.0.tgz", @@ -34813,10 +35580,9 @@ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" }, "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "dev": true + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==" }, "immediate": { "version": "3.0.6", @@ -34833,7 +35599,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, "requires": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -34968,8 +35733,7 @@ "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" }, "is-bigint": { "version": "1.0.4", @@ -35280,6 +36044,12 @@ } } }, + "isomorphic-ws": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz", + "integrity": "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==", + "requires": {} + }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -36077,8 +36847,7 @@ "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "js-yaml": { "version": "4.1.0", @@ -36112,8 +36881,7 @@ "json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, "json-schema": { "version": "0.4.0", @@ -36299,6 +37067,14 @@ "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", "dev": true }, + "latest-version": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz", + "integrity": "sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==", + "requires": { + "package-json": "^8.1.0" + } + }, "leac": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/leac/-/leac-0.6.0.tgz", @@ -36467,8 +37243,7 @@ "lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, "linkify-it": { "version": "5.0.0", @@ -36684,6 +37459,11 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==" + }, "log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -36727,14 +37507,6 @@ "integrity": "sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==", "peer": true }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" - } - }, "luxon": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.5.0.tgz", @@ -36830,8 +37602,7 @@ "make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "devOptional": true + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" }, "makeerror": { "version": "1.0.12", @@ -37833,8 +38604,7 @@ "mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" }, "mv": { "version": "2.1.1", @@ -38336,6 +39106,17 @@ "p-timeout": "^3.0.0" } }, + "package-json": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.1.tgz", + "integrity": "sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==", + "requires": { + "got": "^12.1.0", + "registry-auth-token": "^5.0.1", + "registry-url": "^6.0.0", + "semver": "^7.3.7" + } + }, "package-json-from-dist": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", @@ -38358,7 +39139,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, "requires": { "callsites": "^3.0.0" } @@ -38372,7 +39152,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, "requires": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -38472,6 +39251,11 @@ } } }, + "path-starts-with": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-starts-with/-/path-starts-with-2.0.1.tgz", + "integrity": "sha512-wZ3AeiRBRlNwkdUxvBANh0+esnt38DLffHDujZyRHkqkaKHTglnY2EP5UX3b8rdeiSutgO4y9NEJwXezNP5vHg==" + }, "path-to-regexp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.2.0.tgz", @@ -38480,8 +39264,7 @@ "path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" }, "pathval": { "version": "1.1.1", @@ -38530,8 +39313,7 @@ "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" }, "picomatch": { "version": "2.3.1", @@ -38595,8 +39377,7 @@ "pluralize": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", - "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", - "dev": true + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==" }, "png-js": { "version": "1.0.0", @@ -38617,8 +39398,7 @@ "prettier": { "version": "2.8.7", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.7.tgz", - "integrity": "sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==", - "dev": true + "integrity": "sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==" }, "prettier-linter-helpers": { "version": "1.0.0", @@ -38629,6 +39409,15 @@ "fast-diff": "^1.1.2" } }, + "prettier-plugin-solidity": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.4.2.tgz", + "integrity": "sha512-VVD/4XlDjSzyPWWCPW8JEleFa8JNKFYac5kNlMjVXemQyQZKfpekPMhFZSePuXB6L+RixlFvWe20iacGjFYrLw==", + "requires": { + "@solidity-parser/parser": "^0.19.0", + "semver": "^7.6.3" + } + }, "pretty-format": { "version": "29.5.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", @@ -38696,6 +39485,25 @@ "asap": "~2.0.3" } }, + "prompt": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/prompt/-/prompt-1.3.0.tgz", + "integrity": "sha512-ZkaRWtaLBZl7KKAKndKYUL8WqNT+cQHKRZnT4RYYms48jQkFw3rrBL+/N5K/KtdEveHkxs982MX2BkDKub2ZMg==", + "requires": { + "@colors/colors": "1.5.0", + "async": "3.2.3", + "read": "1.0.x", + "revalidator": "0.1.x", + "winston": "2.x" + }, + "dependencies": { + "async": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", + "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==" + } + } + }, "prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", @@ -38961,6 +39769,14 @@ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, + "read": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", + "integrity": "sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==", + "requires": { + "mute-stream": "~0.0.4" + } + }, "readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", @@ -39013,6 +39829,22 @@ "set-function-name": "^2.0.1" } }, + "registry-auth-token": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.3.tgz", + "integrity": "sha512-1bpc9IyC+e+CNFRaWyn77tk4xGG4PPUyfakSmA6F6cvUDjrm58dfyJ3II+9yb10EDkHoy1LaPSmHaWLOH3m6HA==", + "requires": { + "@pnpm/npm-conf": "^2.1.0" + } + }, + "registry-url": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz", + "integrity": "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==", + "requires": { + "rc": "1.2.8" + } + }, "relateurl": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", @@ -39075,8 +39907,7 @@ "require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==" }, "require-in-the-middle": { "version": "5.2.0", @@ -39138,8 +39969,7 @@ "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" }, "resolve.exports": { "version": "2.0.2", @@ -39188,6 +40018,11 @@ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true }, + "revalidator": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/revalidator/-/revalidator-0.1.8.tgz", + "integrity": "sha512-xcBILK2pA9oh4SiinPEZfhP8HfrB/ha+a2fTMyl7Om2WjlDVrOQy99N2MXXlUHqGJz4qEu2duXxHJjDWuK/0xg==" + }, "rfdc": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", @@ -39462,12 +40297,9 @@ } }, "semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "requires": { - "lru-cache": "^6.0.0" - } + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==" }, "send": { "version": "0.18.0", @@ -39666,6 +40498,16 @@ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + } + }, "slick": { "version": "1.12.2", "resolved": "https://registry.npmjs.org/slick/-/slick-1.12.2.tgz", @@ -39866,6 +40708,78 @@ } } }, + "solhint": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/solhint/-/solhint-5.0.4.tgz", + "integrity": "sha512-GzKBjJ8S2utRsEOCJXhY2H35gwHGmoQY2rQXcPGT4XdDlzwgGYz0Ovo9Xm7cmWYgSo121uF+5tiwrqQT2b+Rtw==", + "requires": { + "@solidity-parser/parser": "^0.19.0", + "ajv": "^6.12.6", + "antlr4": "^4.13.1-patch-1", + "ast-parents": "^0.0.1", + "chalk": "^4.1.2", + "commander": "^10.0.0", + "cosmiconfig": "^8.0.0", + "fast-diff": "^1.2.0", + "glob": "^8.0.3", + "ignore": "^5.2.4", + "js-yaml": "^4.1.0", + "latest-version": "^7.0.0", + "lodash": "^4.17.21", + "pluralize": "^8.0.0", + "prettier": "^2.8.3", + "semver": "^7.5.2", + "strip-ansi": "^6.0.1", + "table": "^6.8.1", + "text-table": "^0.2.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "requires": { + "balanced-match": "^1.0.0" + } + }, + "commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==" + }, + "cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "requires": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + } + }, + "glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, "source-map": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", @@ -39932,6 +40846,11 @@ "resolved": "https://registry.npmjs.org/stack-chain/-/stack-chain-1.3.7.tgz", "integrity": "sha1-0ZLJ/06moiyUxN1FkXHj8AzqEoU=" }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==" + }, "stack-utils": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", @@ -40404,6 +41323,36 @@ "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", "dev": true }, + "table": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz", + "integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==", + "requires": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "requires": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + } + } + }, "tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -40567,8 +41516,7 @@ "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" }, "thenify": { "version": "3.3.1", @@ -40736,7 +41684,6 @@ "version": "10.9.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", - "devOptional": true, "requires": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -41062,8 +42009,7 @@ "typescript": { "version": "4.9.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "devOptional": true + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==" }, "uc.micro": { "version": "2.0.0", @@ -41221,8 +42167,7 @@ "v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "devOptional": true + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" }, "v8-to-istanbul": { "version": "9.1.0", @@ -41281,6 +42226,85 @@ "extsprintf": "^1.2.0" } }, + "viem": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/viem/-/viem-1.0.6.tgz", + "integrity": "sha512-NOVDREj8bWHajuP5Nw6edd0v3auuGWvLHGScmo9OOt1l7g3f1xMQxPA6JlhNmWXzoHjzzxt/5SorBn2DQ6N6Sg==", + "requires": { + "@adraffy/ens-normalize": "1.9.0", + "@noble/curves": "1.0.0", + "@noble/hashes": "1.3.0", + "@scure/bip32": "1.3.0", + "@scure/bip39": "1.2.0", + "@wagmi/chains": "1.1.0", + "abitype": "0.8.7", + "isomorphic-ws": "5.0.0", + "ws": "8.12.0" + }, + "dependencies": { + "@adraffy/ens-normalize": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.9.0.tgz", + "integrity": "sha512-iowxq3U30sghZotgl4s/oJRci6WPBfNO5YYgk2cIOMCHr3LeGPcsZjCEr+33Q4N+oV3OABDAtA+pyvWjbvBifQ==" + }, + "@noble/curves": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.0.0.tgz", + "integrity": "sha512-2upgEu0iLiDVDZkNLeFV2+ht0BAVgQnEmCk6JsOch9Rp8xfkMCbvbAZlA2pBHQc73dbl+vFOXfqkf4uemdn0bw==", + "requires": { + "@noble/hashes": "1.3.0" + } + }, + "@noble/hashes": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.0.tgz", + "integrity": "sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg==" + }, + "@scure/bip32": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.0.tgz", + "integrity": "sha512-bcKpo1oj54hGholplGLpqPHRbIsnbixFtc06nwuNM5/dwSXOq/AAYoIBRsBmnZJSdfeNW5rnff7NTAz3ZCqR9Q==", + "requires": { + "@noble/curves": "~1.0.0", + "@noble/hashes": "~1.3.0", + "@scure/base": "~1.1.0" + } + }, + "@scure/bip39": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.0.tgz", + "integrity": "sha512-SX/uKq52cuxm4YFXWFaVByaSHJh2w3BnokVSeUJVCv6K7WulT9u2BuNRBhuFl8vAuYnzx9bEu9WgpcNYTrYieg==", + "requires": { + "@noble/hashes": "~1.3.0", + "@scure/base": "~1.1.0" + } + }, + "@wagmi/chains": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@wagmi/chains/-/chains-1.1.0.tgz", + "integrity": "sha512-pWZlxBk0Ql8E7DV8DwqlbBpOyUdaG9UDlQPBxJNALuEK1I0tbQ3AVvSDnlsEIt06UPmPo5o27gzs3hwPQ/A+UA==", + "requires": {} + }, + "abitype": { + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/abitype/-/abitype-0.8.7.tgz", + "integrity": "sha512-wQ7hV8Yg/yKmGyFpqrNZufCxbszDe5es4AZGYPBitocfSqXtjrTG9JMWFcc4N30ukl2ve48aBTwt7NJxVQdU3w==", + "requires": {} + }, + "typescript": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", + "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", + "peer": true + }, + "ws": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.12.0.tgz", + "integrity": "sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig==", + "requires": {} + } + } + }, "void-elements": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", @@ -42013,6 +43037,29 @@ "execa": "^4.0.2" } }, + "winston": { + "version": "2.4.7", + "resolved": "https://registry.npmjs.org/winston/-/winston-2.4.7.tgz", + "integrity": "sha512-vLB4BqzCKDnnZH9PHGoS2ycawueX4HLqENXQitvFHczhgW2vFpSOn31LZtVr1KU8YTw7DS4tM+cqyovxo8taVg==", + "requires": { + "async": "^2.6.4", + "colors": "1.0.x", + "cycle": "1.0.x", + "eyes": "0.1.x", + "isstream": "0.1.x", + "stack-trace": "0.0.x" + }, + "dependencies": { + "async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "requires": { + "lodash": "^4.17.14" + } + } + } + }, "with": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/with/-/with-7.0.2.tgz", @@ -42197,8 +43244,7 @@ "yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "devOptional": true + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==" }, "yocto-queue": { "version": "0.1.0", diff --git a/package.json b/package.json index 28e3b51f79..6f6477ba87 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "@defichain/jellyfish-api-jsonrpc": "^3.30.1", "@defichain/jellyfish-network": "^3.30.1", "@defichain/whale-api-client": "^3.30.1", + "@deuro/eurocoin": "^1.0.7", "@dhedge/v2-sdk": "^1.9.8", "@eth-optimism/sdk": "^3.2.0", "@maticnetwork/maticjs": "^3.7.8", @@ -97,6 +98,7 @@ "swagger-ui-express": "^4.6.2", "swissqrbill": "^4.0.2", "typeorm": "^0.3.12", + "viem": "^1.0.6", "xoauth2": "^1.2.0", "zbase32": "^1.0.5" }, diff --git a/src/config/config.ts b/src/config/config.ts index 00d9b99cf0..da9f8be9f3 100644 --- a/src/config/config.ts +++ b/src/config/config.ts @@ -450,6 +450,13 @@ export class Configuration { xchf: process.env.ZCHF_XCHF_CONTRACT_ADDRESS, }, }, + deuro: { + deuroGatewayUrl: process.env.DEURO_GATEWAY_URL, + deuroApiKey: process.env.ALCHEMY_API_KEY, + deuroChainId: +process.env.DEURO_CHAIN_ID, + deuroGraphUrl: process.env.DEURO_GRAPH_URL, + deuroTvlUrl: process.env.DEURO_TVL_URL, + }, ebel2x: { contractAddress: process.env.EBEL2X_CONTRACT_ADDRESS, }, diff --git a/src/integration/blockchain/blockchain.module.ts b/src/integration/blockchain/blockchain.module.ts index 56f74ec105..d0178bdaf1 100644 --- a/src/integration/blockchain/blockchain.module.ts +++ b/src/integration/blockchain/blockchain.module.ts @@ -7,6 +7,7 @@ import { ArbitrumModule } from './arbitrum/arbitrum.module'; import { ArweaveModule } from './arweave/arweave.module'; import { BaseModule } from './base/base.module'; import { BscModule } from './bsc/bsc.module'; +import { DEuroModule } from './deuro/deuro.module'; import { Ebel2xModule } from './ebel2x/ebel2x.module'; import { EthereumModule } from './ethereum/ethereum.module'; import { FrankencoinModule } from './frankencoin/frankencoin.module'; @@ -32,6 +33,7 @@ import { CryptoService } from './shared/services/crypto.service'; LightningModule, MoneroModule, FrankencoinModule, + DEuroModule, Ebel2xModule, ArweaveModule, RailgunModule, @@ -47,6 +49,7 @@ import { CryptoService } from './shared/services/crypto.service'; LightningModule, MoneroModule, FrankencoinModule, + DEuroModule, Ebel2xModule, RailgunModule, EvmGasPriceService, diff --git a/src/integration/blockchain/deuro/controllers/deuro.controller.ts b/src/integration/blockchain/deuro/controllers/deuro.controller.ts new file mode 100644 index 0000000000..afd316b664 --- /dev/null +++ b/src/integration/blockchain/deuro/controllers/deuro.controller.ts @@ -0,0 +1,15 @@ +import { Controller, Get } from '@nestjs/common'; +import { ApiTags } from '@nestjs/swagger'; +import { DEuroService } from '../deuro.service'; +import { DEuroInfoDto } from '../dto/deuro.dto'; + +@ApiTags('DEuro') +@Controller('deuro') +export class DEuroController { + constructor(private readonly service: DEuroService) {} + + @Get('info') + async getInfo(): Promise { + return this.service.getDEuroInfo(); + } +} diff --git a/src/integration/blockchain/deuro/deuro-client.ts b/src/integration/blockchain/deuro/deuro-client.ts new file mode 100644 index 0000000000..97c475cd93 --- /dev/null +++ b/src/integration/blockchain/deuro/deuro-client.ts @@ -0,0 +1,74 @@ +import { ADDRESS, DecentralizedEUROABI, EquityABI } from '@deuro/eurocoin'; +import { Contract, ethers } from 'ethers'; +import { gql, request } from 'graphql-request'; +import { Config } from 'src/config/config'; +import { HttpService } from 'src/shared/services/http.service'; +import { DEuroDepsGraphDto, DEuroPositionGraphDto } from './dto/deuro.dto'; + +export class DEuroClient { + private readonly provider: ethers.providers.JsonRpcProvider; + + constructor(private readonly http: HttpService, gatewayUrl: string, apiKey: string) { + const providerUrl = `${gatewayUrl}/${apiKey}`; + this.provider = new ethers.providers.JsonRpcProvider(providerUrl); + } + + async getTvl(): Promise { + return this.http.get(`${Config.blockchain.deuro.deuroTvlUrl}`); + } + + async getPositionV2s(): Promise { + const document = gql` + { + positionV2s { + items { + id + position + owner + deuro + collateral + price + collateralSymbol + collateralBalance + collateralDecimals + limitForClones + availableForClones + minted + reserveContribution + expiration + } + } + } + `; + + return request<{ positionV2s: { items: [DEuroPositionGraphDto] } }>( + Config.blockchain.deuro.deuroGraphUrl, + document, + ).then((r) => r.positionV2s.items); + } + + async getDEPS(chainId: number): Promise { + const address = ADDRESS[chainId].decentralizedEURO; + + const document = gql` + { + dEPS(id: "${address}") { + id + profits + loss + reserve + } + } + `; + + return request<{ dEPS: DEuroDepsGraphDto }>(Config.blockchain.deuro.deuroGraphUrl, document).then((r) => r.dEPS); + } + + getDEuroContract(chainId: number): Contract { + return new Contract(ADDRESS[chainId].decentralizedEURO, DecentralizedEUROABI, this.provider); + } + + getEquityContract(chainId: number): Contract { + return new Contract(ADDRESS[chainId].equity, EquityABI, this.provider); + } +} diff --git a/src/integration/blockchain/deuro/deuro.module.ts b/src/integration/blockchain/deuro/deuro.module.ts new file mode 100644 index 0000000000..63e3c4d5e3 --- /dev/null +++ b/src/integration/blockchain/deuro/deuro.module.ts @@ -0,0 +1,13 @@ +import { Module } from '@nestjs/common'; +import { SharedModule } from 'src/shared/shared.module'; +import { LogModule } from 'src/subdomains/supporting/log/log.module'; +import { DEuroController } from './controllers/deuro.controller'; +import { DEuroService } from './deuro.service'; + +@Module({ + imports: [SharedModule, LogModule], + controllers: [DEuroController], + providers: [DEuroService], + exports: [DEuroService], +}) +export class DEuroModule {} diff --git a/src/integration/blockchain/deuro/deuro.service.ts b/src/integration/blockchain/deuro/deuro.service.ts new file mode 100644 index 0000000000..35f495d3ea --- /dev/null +++ b/src/integration/blockchain/deuro/deuro.service.ts @@ -0,0 +1,196 @@ +import { Injectable, OnModuleInit } from '@nestjs/common'; +import { ModuleRef } from '@nestjs/core'; +import { Cron, CronExpression } from '@nestjs/schedule'; +import { GetConfig } from 'src/config/config'; +import { Fiat } from 'src/shared/models/fiat/fiat.entity'; +import { FiatService } from 'src/shared/models/fiat/fiat.service'; +import { DfxLogger } from 'src/shared/services/dfx-logger'; +import { HttpService } from 'src/shared/services/http.service'; +import { DisabledProcess, Process } from 'src/shared/services/process.service'; +import { Lock } from 'src/shared/utils/lock'; +import { CreateLogDto } from 'src/subdomains/supporting/log/dto/create-log.dto'; +import { LogSeverity } from 'src/subdomains/supporting/log/log.entity'; +import { LogService } from 'src/subdomains/supporting/log/log.service'; +import { PricingService } from 'src/subdomains/supporting/pricing/services/pricing.service'; +import { EvmUtil } from '../shared/evm/evm.util'; +import { DEuroClient } from './deuro-client'; +import { + DEuroInfoDto, + DEuroLogDto, + DEuroPoolSharesDto, + DEuroPositionDto, + DEuroPositionGraphDto, +} from './dto/deuro.dto'; + +@Injectable() +export class DEuroService implements OnModuleInit { + private readonly logger = new DfxLogger(DEuroService); + + private static readonly LOG_SYSTEM = 'EvmInformation'; + private static readonly LOG_SUBSYSTEM = 'DEuroSmartContract'; + + private readonly client: DEuroClient; + + private pricingService: PricingService; + + private usd: Fiat; + private eur: Fiat; + + private readonly chainId: number; + + constructor( + http: HttpService, + private readonly moduleRef: ModuleRef, + private readonly logService: LogService, + private readonly fiatService: FiatService, + ) { + const { deuroGatewayUrl, deuroApiKey, deuroChainId } = GetConfig().blockchain.deuro; + + this.client = new DEuroClient(http, deuroGatewayUrl, deuroApiKey); + this.chainId = deuroChainId; + } + + async onModuleInit() { + this.pricingService = this.moduleRef.get(PricingService, { strict: false }); + + this.usd = await this.fiatService.getFiatByName('USD'); + this.eur = await this.fiatService.getFiatByName('EUR'); + } + + @Cron(CronExpression.EVERY_10_MINUTES) + @Lock() + async processLogInfo(): Promise { + if (DisabledProcess(Process.DEURO_LOG_INFO)) return; + + const logMessage: DEuroLogDto = { + positionV2s: await this.getPositionV2s(), + poolShares: await this.getDEPS(), + totalSupply: await this.getTotalSupply(), + totalValueLocked: await this.getTvl(), + }; + + const log: CreateLogDto = { + system: DEuroService.LOG_SYSTEM, + subsystem: DEuroService.LOG_SUBSYSTEM, + severity: LogSeverity.INFO, + message: JSON.stringify(logMessage), + valid: null, + category: null, + }; + + await this.logService.create(log); + } + + async getPositionV2s(): Promise { + const positions = await this.client.getPositionV2s(); + return this.getPositions(positions); + } + + private async getPositions(positions: DEuroPositionGraphDto[]): Promise { + const positionsResult: DEuroPositionDto[] = []; + + for (const position of positions) { + try { + const deuroContract = this.client.getDEuroContract(this.chainId); + + const calculateAssignedReserve = await deuroContract.calculateAssignedReserve( + position.minted, + position.reserveContribution, + ); + + positionsResult.push({ + address: { + position: position.position, + deuro: position.deuro, + collateral: position.collateral, + owner: position.owner, + }, + collateral: { + symbol: position.collateralSymbol, + amount: EvmUtil.fromWeiAmount(position.collateralBalance, position.collateralDecimals), + }, + details: { + availableAmount: EvmUtil.fromWeiAmount(position.availableForClones), + totalBorrowed: EvmUtil.fromWeiAmount(position.minted), + liquidationPrice: EvmUtil.fromWeiAmount(position.price, 36 - position.collateralDecimals), + retainedReserve: EvmUtil.fromWeiAmount(calculateAssignedReserve), + limit: EvmUtil.fromWeiAmount(position.limitForClones), + expirationDate: new Date(Number(position.expiration) * 1000), + }, + }); + } catch (e) { + this.logger.error(`Error while getting position ${position.position}`, e); + } + } + + return positionsResult; + } + + async getDEPS(): Promise { + const equityContract = this.client.getEquityContract(this.chainId); + const deuroContract = this.client.getDEuroContract(this.chainId); + + const deps = await this.client.getDEPS(this.chainId); + + try { + const totalSupply = await equityContract.totalSupply(); + const price = await equityContract.price(); + const deuroMinterReserve = await deuroContract.minterReserve(); + const deuroEquity = await deuroContract.equity(); + + const depsResult: DEuroPoolSharesDto = { + depsPrice: EvmUtil.fromWeiAmount(price), + supply: EvmUtil.fromWeiAmount(totalSupply), + marketCap: EvmUtil.fromWeiAmount(totalSupply) * EvmUtil.fromWeiAmount(price), + totalReserve: EvmUtil.fromWeiAmount(deuroMinterReserve) + EvmUtil.fromWeiAmount(deuroEquity), + equityCapital: EvmUtil.fromWeiAmount(deuroEquity), + minterReserve: EvmUtil.fromWeiAmount(deuroMinterReserve), + totalIncome: EvmUtil.fromWeiAmount(deps?.profits ?? '0x0'), + totalLosses: EvmUtil.fromWeiAmount(deps?.loss ?? '0x0'), + }; + + return depsResult; + } catch (e) { + this.logger.error(`Error while getting pool shares ${deps?.id ?? 0}`, e); + } + } + + private async getTotalSupply(): Promise { + const deuroContract = this.client.getDEuroContract(this.chainId); + const deuroTotalSupply = await deuroContract.totalSupply(); + + return EvmUtil.fromWeiAmount(deuroTotalSupply); + } + + async getTvl(): Promise { + // TODO: Frankencoin TVL comes from "https://api.llama.fi/tvl/frankencoin" + // TODO: and DEuro TVL comes from "?????" + return 0; //this.client.getTvl(); + } + + async getDEuroInfo(): Promise { + const maxDEuroLogEntity = await this.logService.maxEntity( + DEuroService.LOG_SYSTEM, + DEuroService.LOG_SUBSYSTEM, + LogSeverity.INFO, + ); + + if (!maxDEuroLogEntity) { + return { + totalSupplyDeuro: 0, + totalValueLockedInEur: 0, + depsMarketCapInEur: 0, + }; + } + + const deuroLog = JSON.parse(maxDEuroLogEntity.message); + + const priceUsdToEur = await this.pricingService.getPrice(this.usd, this.eur, true); + + return { + totalSupplyDeuro: deuroLog.totalSupply, + totalValueLockedInEur: priceUsdToEur.convert(deuroLog.totalValueLocked), + depsMarketCapInEur: deuroLog.poolShares.marketCap, + }; + } +} diff --git a/src/integration/blockchain/deuro/dto/deuro.dto.ts b/src/integration/blockchain/deuro/dto/deuro.dto.ts new file mode 100644 index 0000000000..b5caf421fc --- /dev/null +++ b/src/integration/blockchain/deuro/dto/deuro.dto.ts @@ -0,0 +1,68 @@ +export interface DEuroPositionGraphDto { + id: string; + position: string; + owner: string; + deuro: string; + collateral: string; + price: string; + collateralSymbol: string; + collateralBalance: string; + collateralDecimals: number; + limitForClones: string; + availableForClones: string; + minted: string; + reserveContribution: number; + expiration: string; +} + +export interface DEuroDepsGraphDto { + id: string; + profits: string; + loss: string; + reserve: string; +} + +export interface DEuroLogDto { + positionV2s: DEuroPositionDto[]; + poolShares: DEuroPoolSharesDto; + totalSupply: number; + totalValueLocked: number; +} + +export interface DEuroInfoDto { + totalSupplyDeuro: number; + totalValueLockedInEur: number; + depsMarketCapInEur: number; +} + +export interface DEuroPositionDto { + address: { + position: string; + deuro: string; + collateral: string; + owner: string; + }; + collateral: { + symbol: string; + amount: number; + }; + details: { + availableAmount: number; + totalBorrowed: number; + liquidationPrice: number; + retainedReserve: number; + limit: number; + expirationDate: Date; + }; +} + +export interface DEuroPoolSharesDto { + depsPrice: number; + supply: number; + marketCap: number; + totalReserve: number; + equityCapital: number; + minterReserve: number; + totalIncome: number; + totalLosses: number; +} diff --git a/src/shared/services/process.service.ts b/src/shared/services/process.service.ts index dfb2156119..09fab46c2b 100644 --- a/src/shared/services/process.service.ts +++ b/src/shared/services/process.service.ts @@ -35,6 +35,7 @@ export enum Process { LNURL_AUTH_CACHE = 'LnurlAuthCache', TFA_CACHE = '2faCache', FRANKENCOIN_LOG_INFO = 'FrankencoinLogInfo', + DEURO_LOG_INFO = 'DEuroLogInfo', WEBHOOK = 'Webhook', AUTO_CREATE_BANK_DATA = 'AutoCreateBankData', TX_SPEEDUP = 'TxSpeedup', From d43675a784a5fa4d3c7037e64351ba3fad6576ca Mon Sep 17 00:00:00 2001 From: Yannick1712 <52333989+Yannick1712@users.noreply.github.com> Date: Fri, 10 Jan 2025 14:00:13 +0100 Subject: [PATCH 02/13] [NOTASK] update rule status --- src/subdomains/core/trading/dto/update-trading-rule.dto.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/subdomains/core/trading/dto/update-trading-rule.dto.ts b/src/subdomains/core/trading/dto/update-trading-rule.dto.ts index 6d980f3e11..2e63531c74 100644 --- a/src/subdomains/core/trading/dto/update-trading-rule.dto.ts +++ b/src/subdomains/core/trading/dto/update-trading-rule.dto.ts @@ -1,4 +1,5 @@ -import { IsInt, IsNumber, IsOptional } from 'class-validator'; +import { IsEnum, IsInt, IsNumber, IsOptional } from 'class-validator'; +import { TradingRuleStatus } from '../enums'; export class UpdateTradingRuleDto { @IsOptional() @@ -20,4 +21,8 @@ export class UpdateTradingRuleDto { @IsOptional() @IsInt() reactivationTime: number; + + @IsOptional() + @IsEnum(TradingRuleStatus) + status: TradingRuleStatus; } From d8ca821c36b6b84ceba1eecf76c6c0f69877da56 Mon Sep 17 00:00:00 2001 From: bernd2022 Date: Fri, 10 Jan 2025 14:23:29 +0100 Subject: [PATCH 03/13] [DEV-3452] added bicep parameters --- infrastructure/bicep/dfx-api.bicep | 16 ++++++++++++++++ infrastructure/bicep/parameters/dev.json | 9 +++++++++ infrastructure/bicep/parameters/loc.json | 9 +++++++++ infrastructure/bicep/parameters/prd.json | 9 +++++++++ 4 files changed, 43 insertions(+) diff --git a/infrastructure/bicep/dfx-api.bicep b/infrastructure/bicep/dfx-api.bicep index b9e5176b79..0066575be6 100644 --- a/infrastructure/bicep/dfx-api.bicep +++ b/infrastructure/bicep/dfx-api.bicep @@ -138,6 +138,10 @@ param zchfEquityContractAddress string param zchfStablecoinBridgeContractAddress string param zchfXchfContractAddress string +param deuroGatewayUrl string +param deuroChainId string +param deuroGraphUrl string + param ebel2XContractAddress string param buyCryptoFeeLimit string @@ -911,6 +915,18 @@ resource apiAppService 'Microsoft.Web/sites@2018-11-01' = { name: 'ZCHF_XCHF_CONTRACT_ADDRESS' value: zchfXchfContractAddress } + { + name: 'DEURO_GATEWAY_URL' + value: deuroGatewayUrl + } + { + name: 'DEURO_CHAIN_ID' + value: deuroChainId + } + { + name: 'DEURO_GRAPH_URL' + value: deuroGraphUrl + } { name: 'EBEL2X_CONTRACT_ADDRESS' value: ebel2XContractAddress diff --git a/infrastructure/bicep/parameters/dev.json b/infrastructure/bicep/parameters/dev.json index 2162b37574..9ae526351c 100644 --- a/infrastructure/bicep/parameters/dev.json +++ b/infrastructure/bicep/parameters/dev.json @@ -269,6 +269,15 @@ "zchfXchfContractAddress": { "value": "0xb4272071ecadd69d933adcd19ca99fe80664fc08" }, + "deuroGatewayUrl": { + "value": "https://eth-mainnet.g.alchemy.com/v2" + }, + "deuroChainId": { + "value": "1" + }, + "deuroGraphUrl": { + "value": "https://dev.ponder.deuro.com" + }, "ebel2XContractAddress": { "value": "" }, diff --git a/infrastructure/bicep/parameters/loc.json b/infrastructure/bicep/parameters/loc.json index 88e6d30213..bb6e8ac954 100644 --- a/infrastructure/bicep/parameters/loc.json +++ b/infrastructure/bicep/parameters/loc.json @@ -269,6 +269,15 @@ "zchfXchfContractAddress": { "value": "0xb4272071ecadd69d933adcd19ca99fe80664fc08" }, + "deuroGatewayUrl": { + "value": "https://eth-mainnet.g.alchemy.com/v2" + }, + "deuroChainId": { + "value": "1" + }, + "deuroGraphUrl": { + "value": "https://dev.ponder.deuro.com" + }, "ebel2XContractAddress": { "value": "" }, diff --git a/infrastructure/bicep/parameters/prd.json b/infrastructure/bicep/parameters/prd.json index a64b92a95c..33f1b6314b 100644 --- a/infrastructure/bicep/parameters/prd.json +++ b/infrastructure/bicep/parameters/prd.json @@ -269,6 +269,15 @@ "zchfXchfContractAddress": { "value": "0xb4272071ecadd69d933adcd19ca99fe80664fc08" }, + "deuroGatewayUrl": { + "value": "https://eth-mainnet.g.alchemy.com/v2" + }, + "deuroChainId": { + "value": "1" + }, + "deuroGraphUrl": { + "value": "https://ponder.deuro.com" + }, "ebel2XContractAddress": { "value": "0xe137dd4bcd22e947c896ae33a0920c09c85e263d" }, From 49d00ae8c9fb88c92ae05cc673ebe3af0c47de36 Mon Sep 17 00:00:00 2001 From: Yannick1712 <52333989+Yannick1712@users.noreply.github.com> Date: Fri, 10 Jan 2025 15:45:48 +0100 Subject: [PATCH 04/13] [DEV-3525] Refactoring tx increaseFee --- .../services/buy-crypto-batch.service.ts | 17 ++++++++++++----- .../services/buy-crypto-preparation.service.ts | 6 +----- .../services/buy-fiat-preparation.service.ts | 4 ++-- .../supporting/payment/services/fee.service.ts | 4 ++-- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/subdomains/core/buy-crypto/process/services/buy-crypto-batch.service.ts b/src/subdomains/core/buy-crypto/process/services/buy-crypto-batch.service.ts index cd44f41e4b..ea0ad4faa2 100644 --- a/src/subdomains/core/buy-crypto/process/services/buy-crypto-batch.service.ts +++ b/src/subdomains/core/buy-crypto/process/services/buy-crypto-batch.service.ts @@ -10,6 +10,7 @@ import { CheckLiquidityRequest, CheckLiquidityResult } from 'src/subdomains/supp import { DexService } from 'src/subdomains/supporting/dex/services/dex.service'; import { PayInStatus } from 'src/subdomains/supporting/payin/entities/crypto-input.entity'; import { FeeLimitExceededException } from 'src/subdomains/supporting/payment/exceptions/fee-limit-exceeded.exception'; +import { FeeService } from 'src/subdomains/supporting/payment/services/fee.service'; import { FeeResult } from 'src/subdomains/supporting/payout/interfaces'; import { PayoutService } from 'src/subdomains/supporting/payout/services/payout.service'; import { PriceStep } from 'src/subdomains/supporting/pricing/domain/entities/price'; @@ -38,6 +39,7 @@ export class BuyCryptoBatchService { private readonly payoutService: PayoutService, private readonly buyCryptoNotificationService: BuyCryptoNotificationService, private readonly liquidityService: LiquidityManagementService, + private readonly feeService: FeeService, ) {} async batchAndOptimizeTransactions(): Promise { @@ -70,6 +72,7 @@ export class BuyCryptoBatchService { cryptoInput: true, buy: { user: true }, cryptoRoute: { user: true }, + transaction: { user: { userData: true } }, }, }); @@ -109,14 +112,18 @@ export class BuyCryptoBatchService { ), ]; continue; - } + } else { + const inputReferenceCurrency = + tx.cryptoInput?.asset ?? (await this.fiatService.getFiatByName(tx.inputReferenceAsset)); - const inputReferenceCurrency = - tx.cryptoInput?.asset ?? (await this.fiatService.getFiatByName(tx.inputReferenceAsset)); + const price = await this.pricingService.getPrice(inputReferenceCurrency, tx.outputReferenceAsset, false); - const price = await this.pricingService.getPrice(inputReferenceCurrency, tx.outputReferenceAsset, false); + tx.calculateOutputReferenceAmount(price); + } - tx.calculateOutputReferenceAmount(price); + for (const feeId of tx.usedFees?.split(';')) { + await this.feeService.increaseTxUsages(tx.amountInChf, Number.parseInt(feeId), tx.userData); + } } catch (e) { if (e instanceof PriceInvalidException) { await this.setPriceInvalidStatus([tx]); diff --git a/src/subdomains/core/buy-crypto/process/services/buy-crypto-preparation.service.ts b/src/subdomains/core/buy-crypto/process/services/buy-crypto-preparation.service.ts index a0a81e15c8..f7fd441b4d 100644 --- a/src/subdomains/core/buy-crypto/process/services/buy-crypto-preparation.service.ts +++ b/src/subdomains/core/buy-crypto/process/services/buy-crypto-preparation.service.ts @@ -222,7 +222,7 @@ export class BuyCryptoPreparationService implements OnModuleInit { for (const entity of entities) { try { - const isFirstRun = !entity.percentFee; + const isFirstRun = entity.percentFee == null; const inputReferenceCurrency = entity.cryptoInput?.asset ?? (await this.fiatService.getFiatByName(entity.inputReferenceAsset)); @@ -277,10 +277,6 @@ export class BuyCryptoPreparationService implements OnModuleInit { } if (isFirstRun) { - for (const feeId of fee.fees) { - await this.feeService.increaseTxUsages(amountInChf, feeId, entity.user.userData); - } - await this.buyCryptoService.updateBuyVolume([entity.buy?.id]); await this.buyCryptoService.updateCryptoRouteVolume([entity.cryptoRoute?.id]); await this.buyCryptoService.updateRefVolume([entity.usedRef]); diff --git a/src/subdomains/core/sell-crypto/process/services/buy-fiat-preparation.service.ts b/src/subdomains/core/sell-crypto/process/services/buy-fiat-preparation.service.ts index 964960f9bf..1ea53f95d1 100644 --- a/src/subdomains/core/sell-crypto/process/services/buy-fiat-preparation.service.ts +++ b/src/subdomains/core/sell-crypto/process/services/buy-fiat-preparation.service.ts @@ -211,8 +211,8 @@ export class BuyFiatPreparationService implements OnModuleInit { if (entity.amlCheck === CheckStatus.FAIL) return; - for (const feeId of fee.fees) { - await this.feeService.increaseTxUsages(amountInChf, feeId, entity.user.userData); + for (const usedFee of fee.fees) { + await this.feeService.increaseTxUsages(amountInChf, usedFee.id, entity.user.userData); } await this.buyFiatService.updateSellVolume([entity.sell?.id]); diff --git a/src/subdomains/supporting/payment/services/fee.service.ts b/src/subdomains/supporting/payment/services/fee.service.ts index 297d3e116b..60defac092 100644 --- a/src/subdomains/supporting/payment/services/fee.service.ts +++ b/src/subdomains/supporting/payment/services/fee.service.ts @@ -199,8 +199,8 @@ export class FeeService implements OnModuleInit { await this.userDataService.addFee(userData, cachedFee.id); } - async increaseTxUsages(txVolume: number, fee: Fee, userData: UserData): Promise { - const cachedFee = await this.getFee(fee.id); + async increaseTxUsages(txVolume: number, feeId: number, userData: UserData): Promise { + const cachedFee = await this.getFee(feeId); await this.feeRepo.update(...cachedFee.increaseTxUsage()); if (cachedFee.maxUserTxUsages) await this.feeRepo.update(...cachedFee.increaseUserTxUsage(userData.id)); From 707bc3ea5e8a388a070e7e28609225d5a5258d7b Mon Sep 17 00:00:00 2001 From: Yannick1712 <52333989+Yannick1712@users.noreply.github.com> Date: Fri, 10 Jan 2025 15:58:29 +0100 Subject: [PATCH 05/13] [DEV-3525] fix unit test --- .../services/__tests__/buy-crypto-batch.service.spec.ts | 4 ++++ .../process/services/buy-crypto-preparation.service.ts | 2 -- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/subdomains/core/buy-crypto/process/services/__tests__/buy-crypto-batch.service.spec.ts b/src/subdomains/core/buy-crypto/process/services/__tests__/buy-crypto-batch.service.spec.ts index 5b94d36304..43bb237994 100644 --- a/src/subdomains/core/buy-crypto/process/services/__tests__/buy-crypto-batch.service.spec.ts +++ b/src/subdomains/core/buy-crypto/process/services/__tests__/buy-crypto-batch.service.spec.ts @@ -8,6 +8,7 @@ import { createCustomBuy } from 'src/subdomains/core/buy-crypto/routes/buy/__moc import { LiquidityManagementService } from 'src/subdomains/core/liquidity-management/services/liquidity-management.service'; import { CheckLiquidityResult } from 'src/subdomains/supporting/dex/interfaces'; import { DexService } from 'src/subdomains/supporting/dex/services/dex.service'; +import { FeeService } from 'src/subdomains/supporting/payment/services/fee.service'; import { PayoutService } from 'src/subdomains/supporting/payout/services/payout.service'; import { Price } from 'src/subdomains/supporting/pricing/domain/entities/price'; import { PricingService } from 'src/subdomains/supporting/pricing/services/pricing.service'; @@ -36,6 +37,7 @@ describe('BuyCryptoBatchService', () => { let payoutService: PayoutService; let buyCryptoNotificationService: BuyCryptoNotificationService; let liquidityManagementService: LiquidityManagementService; + let feeService: FeeService; /*** Spies ***/ @@ -215,6 +217,7 @@ describe('BuyCryptoBatchService', () => { payoutService = mock(); buyCryptoNotificationService = mock(); liquidityManagementService = mock(); + feeService = mock(); const module: TestingModule = await Test.createTestingModule({ providers: [ @@ -229,6 +232,7 @@ describe('BuyCryptoBatchService', () => { { provide: PayoutService, useValue: payoutService }, { provide: BuyCryptoNotificationService, useValue: buyCryptoNotificationService }, { provide: LiquidityManagementService, useValue: liquidityManagementService }, + { provide: FeeService, useValue: feeService }, TestUtil.provideConfig(), ], }).compile(); diff --git a/src/subdomains/core/buy-crypto/process/services/buy-crypto-preparation.service.ts b/src/subdomains/core/buy-crypto/process/services/buy-crypto-preparation.service.ts index f7fd441b4d..e52302d09f 100644 --- a/src/subdomains/core/buy-crypto/process/services/buy-crypto-preparation.service.ts +++ b/src/subdomains/core/buy-crypto/process/services/buy-crypto-preparation.service.ts @@ -18,7 +18,6 @@ import { BankService } from 'src/subdomains/supporting/bank/bank/bank.service'; import { CardBankName } from 'src/subdomains/supporting/bank/bank/dto/bank.dto'; import { PayInService } from 'src/subdomains/supporting/payin/services/payin.service'; import { CryptoPaymentMethod } from 'src/subdomains/supporting/payment/dto/payment-method.enum'; -import { FeeService } from 'src/subdomains/supporting/payment/services/fee.service'; import { TransactionHelper } from 'src/subdomains/supporting/payment/services/transaction-helper'; import { PricingService } from 'src/subdomains/supporting/pricing/services/pricing.service'; import { In, IsNull, Not } from 'typeorm'; @@ -41,7 +40,6 @@ export class BuyCryptoPreparationService implements OnModuleInit { private readonly transactionHelper: TransactionHelper, private readonly pricingService: PricingService, private readonly fiatService: FiatService, - private readonly feeService: FeeService, private readonly buyCryptoService: BuyCryptoService, private readonly amlService: AmlService, private readonly userService: UserService, From 3ca0e553bf6b0a17ab1f4f48d7eabe216263485f Mon Sep 17 00:00:00 2001 From: Yannick1712 <52333989+Yannick1712@users.noreply.github.com> Date: Fri, 10 Jan 2025 18:22:14 +0100 Subject: [PATCH 06/13] [NOTASK] fix paidRefReward bug --- .../reward/services/ref-reward-out.service.ts | 21 +++---------------- .../reward/services/ref-reward.service.ts | 4 ++-- 2 files changed, 5 insertions(+), 20 deletions(-) diff --git a/src/subdomains/core/referral/reward/services/ref-reward-out.service.ts b/src/subdomains/core/referral/reward/services/ref-reward-out.service.ts index cbff93fe61..a9e3532e9f 100644 --- a/src/subdomains/core/referral/reward/services/ref-reward-out.service.ts +++ b/src/subdomains/core/referral/reward/services/ref-reward-out.service.ts @@ -1,7 +1,6 @@ import { Injectable } from '@nestjs/common'; import { AssetService } from 'src/shared/models/asset/asset.service'; import { DfxLogger } from 'src/shared/services/dfx-logger'; -import { UserService } from 'src/subdomains/generic/user/models/user/user.service'; import { LiquidityOrderContext } from 'src/subdomains/supporting/dex/entities/liquidity-order.entity'; import { DexService } from 'src/subdomains/supporting/dex/services/dex.service'; import { PayoutOrderContext } from 'src/subdomains/supporting/payout/entities/payout-order.entity'; @@ -9,6 +8,7 @@ import { PayoutRequest } from 'src/subdomains/supporting/payout/interfaces'; import { PayoutService } from 'src/subdomains/supporting/payout/services/payout.service'; import { RefReward, RewardStatus } from '../ref-reward.entity'; import { RefRewardRepository } from '../ref-reward.repository'; +import { RefRewardService } from './ref-reward.service'; @Injectable() export class RefRewardOutService { @@ -18,8 +18,8 @@ export class RefRewardOutService { private readonly refRewardRepo: RefRewardRepository, private readonly payoutService: PayoutService, private readonly assetService: AssetService, - private readonly userService: UserService, private readonly dexService: DexService, + private readonly refRewardService: RefRewardService, ) {} async checkPaidTransaction(): Promise { @@ -64,21 +64,6 @@ export class RefRewardOutService { //*** HELPER METHODS ***// - private async updatePaidRefCredit(userIds: number[]): Promise { - userIds = userIds.filter((u, j) => userIds.indexOf(u) === j).filter((i) => i); // distinct, not null - - for (const id of userIds) { - const { volume } = await this.refRewardRepo - .createQueryBuilder('refReward') - .select('SUM(amountInEur)', 'volume') - .innerJoin('refReward.user', 'user') - .where('user.id = :id', { id }) - .getRawOne<{ volume: number }>(); - - await this.userService.updatePaidRefCredit(id, volume ?? 0); - } - } - private async doPayout(transaction: RefReward): Promise { const asset = await this.assetService.getNativeAsset(transaction.targetBlockchain); @@ -112,7 +97,7 @@ export class RefRewardOutService { await this.dexService.completeOrders(LiquidityOrderContext.REF_PAYOUT, tx.id.toString()); - await this.updatePaidRefCredit([tx.user?.id]); + await this.refRewardService.updatePaidRefCredit([tx.user?.id]); } } catch (e) { this.logger.error(`Error on checking completion of ref-reward ${tx.id}:`, e); diff --git a/src/subdomains/core/referral/reward/services/ref-reward.service.ts b/src/subdomains/core/referral/reward/services/ref-reward.service.ts index 5bbcfaebae..0938f2d71c 100644 --- a/src/subdomains/core/referral/reward/services/ref-reward.service.ts +++ b/src/subdomains/core/referral/reward/services/ref-reward.service.ts @@ -133,7 +133,7 @@ export class RefRewardService { } // --- HELPER METHODS --- // - private async updatePaidRefCredit(userIds: number[]): Promise { + async updatePaidRefCredit(userIds: number[]): Promise { userIds = userIds.filter((u, j) => userIds.indexOf(u) === j).filter((i) => i); // distinct, not null for (const id of userIds) { @@ -141,7 +141,7 @@ export class RefRewardService { .createQueryBuilder('refReward') .select('SUM(amountInEur)', 'volume') .innerJoin('refReward.user', 'user') - .where('user.id = :id', { id }) + .andWhere('refReward.status = :status', { status: RewardStatus.COMPLETE }) .getRawOne<{ volume: number }>(); await this.userService.updatePaidRefCredit(id, volume ?? 0); From c250243596a27bf25ad6892541552d65c0f6fbcb Mon Sep 17 00:00:00 2001 From: Yannick1712 <52333989+Yannick1712@users.noreply.github.com> Date: Sat, 11 Jan 2025 09:07:35 +0100 Subject: [PATCH 07/13] [NOTASK] remove continue --- .../core/buy-crypto/process/services/buy-crypto-batch.service.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/subdomains/core/buy-crypto/process/services/buy-crypto-batch.service.ts b/src/subdomains/core/buy-crypto/process/services/buy-crypto-batch.service.ts index ea0ad4faa2..9322acfb28 100644 --- a/src/subdomains/core/buy-crypto/process/services/buy-crypto-batch.service.ts +++ b/src/subdomains/core/buy-crypto/process/services/buy-crypto-batch.service.ts @@ -111,7 +111,6 @@ export class BuyCryptoBatchService { tx.inputReferenceAmountMinusFee / tx.outputReferenceAmount, ), ]; - continue; } else { const inputReferenceCurrency = tx.cryptoInput?.asset ?? (await this.fiatService.getFiatByName(tx.inputReferenceAsset)); From b07b5d8722b2a422241d426af45cc91f166e2288 Mon Sep 17 00:00:00 2001 From: Yannick <52333989+Yannick1712@users.noreply.github.com> Date: Sat, 11 Jan 2025 15:09:15 +0100 Subject: [PATCH 08/13] [DEV-3500] fix financeLog bug (#1872) * [DEV-3500] fix financeLog bug * [DEV-3500] Refactoring * [DEV-3500] small improvement * [DEV-3500] more improvement * [DEV-3500] add unit tests --- .../dto/__mocks__/exchange-tx.entity.mock.ts | 13 + .../log/__tests__/log-job.service.spec.ts | 258 ++++++++++++++++++ .../supporting/log/log-job.service.ts | 124 +++++---- 3 files changed, 341 insertions(+), 54 deletions(-) create mode 100644 src/integration/exchange/dto/__mocks__/exchange-tx.entity.mock.ts create mode 100644 src/subdomains/supporting/log/__tests__/log-job.service.spec.ts diff --git a/src/integration/exchange/dto/__mocks__/exchange-tx.entity.mock.ts b/src/integration/exchange/dto/__mocks__/exchange-tx.entity.mock.ts new file mode 100644 index 0000000000..91aabad75f --- /dev/null +++ b/src/integration/exchange/dto/__mocks__/exchange-tx.entity.mock.ts @@ -0,0 +1,13 @@ +import { ExchangeTx } from '../../entities/exchange-tx.entity'; + +const defaultExchangeTx: Partial = { + id: 1, +}; + +export function createDefaultExchangeTx(): ExchangeTx { + return createCustomExchangeTx({}); +} + +export function createCustomExchangeTx(customValues: Partial): ExchangeTx { + return Object.assign(new ExchangeTx(), { ...defaultExchangeTx, ...customValues }); +} diff --git a/src/subdomains/supporting/log/__tests__/log-job.service.spec.ts b/src/subdomains/supporting/log/__tests__/log-job.service.spec.ts new file mode 100644 index 0000000000..93b378eaf3 --- /dev/null +++ b/src/subdomains/supporting/log/__tests__/log-job.service.spec.ts @@ -0,0 +1,258 @@ +import { createMock } from '@golevelup/ts-jest'; +import { Test, TestingModule } from '@nestjs/testing'; +import { BlockchainRegistryService } from 'src/integration/blockchain/shared/services/blockchain-registry.service'; +import { createCustomExchangeTx } from 'src/integration/exchange/dto/__mocks__/exchange-tx.entity.mock'; +import { ExchangeTxService } from 'src/integration/exchange/services/exchange-tx.service'; +import { AssetService } from 'src/shared/models/asset/asset.service'; +import { SettingService } from 'src/shared/models/setting/setting.service'; +import { TestSharedModule } from 'src/shared/utils/test.shared.module'; +import { TestUtil } from 'src/shared/utils/test.util'; +import { Util } from 'src/shared/utils/util'; +import { BuyCryptoService } from 'src/subdomains/core/buy-crypto/process/services/buy-crypto.service'; +import { LiquidityManagementBalanceService } from 'src/subdomains/core/liquidity-management/services/liquidity-management-balance.service'; +import { LiquidityManagementPipelineService } from 'src/subdomains/core/liquidity-management/services/liquidity-management-pipeline.service'; +import { RefRewardService } from 'src/subdomains/core/referral/reward/services/ref-reward.service'; +import { BuyFiatService } from 'src/subdomains/core/sell-crypto/process/services/buy-fiat.service'; +import { TradingOrderService } from 'src/subdomains/core/trading/services/trading-order.service'; +import { TradingRuleService } from 'src/subdomains/core/trading/services/trading-rule.service'; +import { BankTxService } from 'src/subdomains/supporting/bank-tx/bank-tx/services/bank-tx.service'; +import { BankTxRepeatService } from '../../bank-tx/bank-tx-repeat/bank-tx-repeat.service'; +import { BankTxReturnService } from '../../bank-tx/bank-tx-return/bank-tx-return.service'; +import { createCustomBankTx } from '../../bank-tx/bank-tx/__mocks__/bank-tx.entity.mock'; +import { BankService } from '../../bank/bank/bank.service'; +import { PayInService } from '../../payin/services/payin.service'; +import { PayoutService } from '../../payout/services/payout.service'; +import { LogJobService } from '../log-job.service'; +import { LogService } from '../log.service'; + +describe('LogJobService', () => { + let service: LogJobService; + + let tradingRuleService: TradingRuleService; + let assetService: AssetService; + let liqManagementBalanceService: LiquidityManagementBalanceService; + let logService: LogService; + let payInService: PayInService; + let buyFiatService: BuyFiatService; + let buyCryptoService: BuyCryptoService; + let settingService: SettingService; + let bankTxService: BankTxService; + let bankTxRepeatService: BankTxRepeatService; + let bankTxReturnService: BankTxReturnService; + let liquidityManagementPipelineService: LiquidityManagementPipelineService; + let exchangeTxService: ExchangeTxService; + let bankService: BankService; + let blockchainRegistryService: BlockchainRegistryService; + let refRewardService: RefRewardService; + let tradingOrderService: TradingOrderService; + let payoutService: PayoutService; + + beforeEach(async () => { + tradingRuleService = createMock(); + assetService = createMock(); + liqManagementBalanceService = createMock(); + logService = createMock(); + payInService = createMock(); + buyFiatService = createMock(); + buyCryptoService = createMock(); + settingService = createMock(); + bankTxService = createMock(); + bankTxRepeatService = createMock(); + bankTxReturnService = createMock(); + liquidityManagementPipelineService = createMock(); + exchangeTxService = createMock(); + bankService = createMock(); + blockchainRegistryService = createMock(); + refRewardService = createMock(); + tradingOrderService = createMock(); + payoutService = createMock(); + + const module: TestingModule = await Test.createTestingModule({ + imports: [TestSharedModule], + providers: [ + LogJobService, + { provide: TradingRuleService, useValue: tradingRuleService }, + { provide: AssetService, useValue: assetService }, + { provide: LiquidityManagementBalanceService, useValue: liqManagementBalanceService }, + { provide: LogService, useValue: logService }, + { provide: PayInService, useValue: payInService }, + { provide: BuyFiatService, useValue: buyFiatService }, + { provide: BuyCryptoService, useValue: buyCryptoService }, + { provide: SettingService, useValue: settingService }, + { provide: BankTxService, useValue: bankTxService }, + { provide: BankTxRepeatService, useValue: bankTxRepeatService }, + { provide: BankTxReturnService, useValue: bankTxReturnService }, + { provide: LiquidityManagementPipelineService, useValue: liquidityManagementPipelineService }, + { provide: ExchangeTxService, useValue: exchangeTxService }, + { provide: BankService, useValue: bankService }, + { provide: BlockchainRegistryService, useValue: blockchainRegistryService }, + { provide: RefRewardService, useValue: refRewardService }, + { provide: TradingOrderService, useValue: tradingOrderService }, + { provide: PayoutService, useValue: payoutService }, + TestUtil.provideConfig(), + ], + }).compile(); + + service = module.get(LogJobService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); + + it('should return an empty array', async () => { + expect(service.filterSenderPendingList([], [])).toMatchObject({ receiver: [], sender: [] }); + }); + + it('should return sender & receiver', async () => { + const senderTx = [createCustomExchangeTx({ id: 1, created: Util.hoursBefore(27), amount: 9999.0 })]; + + const receiverTx = [ + createCustomBankTx({ + id: 1, + created: Util.hoursBefore(26), + valueDate: Util.hoursBefore(26), + instructedAmount: 9999.0, + amount: 9999.0, + }), + ]; + + expect(service.filterSenderPendingList(senderTx, receiverTx)).toMatchObject({ + sender: senderTx, + receiver: receiverTx, + }); + }); + + it('should filter not matching older senderTx', async () => { + const senderTx = [ + createCustomExchangeTx({ id: 1, created: Util.daysBefore(8), amount: 9999.0 }), + createCustomExchangeTx({ id: 2, created: Util.daysBefore(8), amount: 9999.0 }), + createCustomExchangeTx({ id: 3, created: Util.daysBefore(7), amount: 9999.0 }), + ]; + + const receiverTx = [ + createCustomBankTx({ + id: 1, + created: Util.daysBefore(6), + valueDate: Util.daysBefore(6), + instructedAmount: 9999.0, + amount: 9999.0, + }), + createCustomBankTx({ + id: 2, + created: Util.daysBefore(5), + valueDate: Util.daysBefore(5), + instructedAmount: 9999.0, + amount: 9999.0, + }), + createCustomBankTx({ + id: 3, + created: Util.daysBefore(5), + valueDate: Util.daysBefore(5), + instructedAmount: 9999.0, + amount: 9999.0, + }), + ]; + + expect(service.filterSenderPendingList(senderTx, receiverTx)).toMatchObject({ + sender: [senderTx[2]], + receiver: receiverTx, + }); + }); + + it('should filter tx 14d or older', async () => { + const senderTx = [ + createCustomExchangeTx({ id: 1, created: Util.daysBefore(17), amount: 9999.0 }), + createCustomExchangeTx({ id: 2, created: Util.daysBefore(12), amount: 9999.0 }), + createCustomExchangeTx({ id: 3, created: Util.daysBefore(7), amount: 9999.0 }), + ]; + + const receiverTx = [ + createCustomBankTx({ + id: 1, + created: Util.daysBefore(16), + valueDate: Util.daysBefore(16), + instructedAmount: 9999.0, + amount: 9999.0, + }), + createCustomBankTx({ + id: 2, + created: Util.daysBefore(11), + valueDate: Util.daysBefore(11), + instructedAmount: 9999.0, + amount: 9999.0, + }), + createCustomBankTx({ + id: 3, + created: Util.daysBefore(6), + valueDate: Util.daysBefore(6), + instructedAmount: 9999.0, + amount: 9999.0, + }), + ]; + + expect(service.filterSenderPendingList(senderTx, receiverTx)).toMatchObject({ + sender: senderTx.slice(1), + receiver: receiverTx.slice(1), + }); + }); + + it('should filter tx 21d or older', async () => { + const senderTx = [ + createCustomExchangeTx({ id: 1, created: Util.daysBefore(21), amount: 47543.81 }), + createCustomExchangeTx({ id: 2, created: Util.daysBefore(17), amount: 19999.0 }), + ]; + + const receiverTx = [ + createCustomBankTx({ + id: 1, + created: Util.daysBefore(20), + valueDate: Util.daysBefore(20), + instructedAmount: 47543.81, + amount: 47520.04, + }), + createCustomBankTx({ + id: 2, + created: Util.daysBefore(16), + valueDate: Util.daysBefore(16), + instructedAmount: 19999.0, + amount: 19989.0, + }), + ]; + + expect(service.filterSenderPendingList(senderTx, receiverTx)).toMatchObject({ + sender: [senderTx[1]], + receiver: [receiverTx[1]], + }); + }); + + it('should filter receiver 21d or older', async () => { + const senderTx = [ + createCustomExchangeTx({ id: 3, created: Util.daysBefore(19), amount: 9999.0 }), + createCustomExchangeTx({ id: 2, created: Util.daysBefore(18), amount: 9999.0 }), + createCustomExchangeTx({ id: 1, created: Util.daysBefore(17), amount: 9999.0 }), + ]; + + const receiverTx = [ + createCustomBankTx({ + id: 1, + created: Util.daysBefore(21), + valueDate: Util.daysBefore(21), + instructedAmount: 9999.0, + amount: 9999.0, + }), + createCustomBankTx({ + id: 2, + created: Util.daysBefore(18), + valueDate: Util.daysBefore(18), + instructedAmount: 9999.0, + amount: 9999.0, + }), + ]; + + expect(service.filterSenderPendingList(senderTx, receiverTx)).toMatchObject({ + sender: senderTx, + receiver: [receiverTx[1]], + }); + }); +}); diff --git a/src/subdomains/supporting/log/log-job.service.ts b/src/subdomains/supporting/log/log-job.service.ts index 2cc984300b..4db2a2922c 100644 --- a/src/subdomains/supporting/log/log-job.service.ts +++ b/src/subdomains/supporting/log/log-job.service.ts @@ -233,25 +233,16 @@ export class LogJobService { ExchangeTxType.WITHDRAWAL, ]); - const before14Days = Util.daysBefore(14); - const before21Days = Util.daysBefore(21); - - before14Days.setHours(0, 0, 0, 0); - // sender and receiver data const { sender: recentChfKrakenMaerkiTx, receiver: recentChfKrakenBankTx } = this.filterSenderPendingList( recentKrakenExchangeTx.filter( (k) => k.type === ExchangeTxType.WITHDRAWAL && k.method === 'Bank Frick (SIC) International' && - k.address === 'Maerki Baumann' && - k.created > before21Days, + k.address === 'Maerki Baumann', ), recentKrakenBankTx.filter( - (b) => - b.accountIban === maerkiChfBank.iban && - b.creditDebitIndicator === BankTxIndicator.CREDIT && - b.created > before14Days, + (b) => b.accountIban === maerkiChfBank.iban && b.creditDebitIndicator === BankTxIndicator.CREDIT, ), ); const { sender: recentEurKrakenMaerkiTx, receiver: recentEurKrakenBankTx } = this.filterSenderPendingList( @@ -259,45 +250,33 @@ export class LogJobService { (k) => k.type === ExchangeTxType.WITHDRAWAL && k.method === 'Bank Frick (SEPA) International' && - k.address === 'Maerki Baumann & Co. AG' && - k.created > before21Days, + k.address === 'Maerki Baumann & Co. AG', ), recentKrakenBankTx.filter( - (b) => - b.accountIban === maerkiEurBank.iban && - b.creditDebitIndicator === BankTxIndicator.CREDIT && - b.created > before14Days, + (b) => b.accountIban === maerkiEurBank.iban && b.creditDebitIndicator === BankTxIndicator.CREDIT, ), ); const { sender: recentChfMaerkiKrakenTx, receiver: recentChfBankTxKraken } = this.filterSenderPendingList( recentKrakenBankTx.filter( - (b) => - b.accountIban === maerkiChfBank.iban && - b.creditDebitIndicator === BankTxIndicator.DEBIT && - b.created > before21Days, + (b) => b.accountIban === maerkiChfBank.iban && b.creditDebitIndicator === BankTxIndicator.DEBIT, ), recentKrakenExchangeTx.filter( (k) => k.type === ExchangeTxType.DEPOSIT && k.method === 'Bank Frick (SIC) International' && - k.address === 'MAEBCHZZXXX' && - k.created > before14Days, + k.address === 'MAEBCHZZXXX', ), ); const { sender: recentEurMaerkiKrakenTx, receiver: recentEurBankTxKraken } = this.filterSenderPendingList( recentKrakenBankTx.filter( - (b) => - b.accountIban === maerkiEurBank.iban && - b.creditDebitIndicator === BankTxIndicator.DEBIT && - b.created > before21Days, + (b) => b.accountIban === maerkiEurBank.iban && b.creditDebitIndicator === BankTxIndicator.DEBIT, ), recentKrakenExchangeTx.filter( (k) => k.type === ExchangeTxType.DEPOSIT && k.method === 'Bank Frick (SEPA) International' && - k.address === 'MAEBCHZZXXX' && - k.created > before14Days, + k.address === 'MAEBCHZZXXX', ), ); @@ -626,25 +605,75 @@ export class LogJobService { ); } - private filterSenderPendingList( + public filterSenderPendingList( senderTx: (BankTx | ExchangeTx)[], receiverTx: (BankTx | ExchangeTx)[] | undefined, ): { receiver: (BankTx | ExchangeTx)[]; sender: (BankTx | ExchangeTx)[] } { - if (!receiverTx?.length) return { sender: senderTx, receiver: receiverTx }; - let receiverIndex = 0; - let senderPair = undefined; + const before14Days = Util.daysBefore(14); + const before21Days = Util.daysBefore(21); + + before14Days.setHours(0, 0, 0, 0); + + const filtered21SenderTx = senderTx.filter((s) => s.created > before21Days); + const filtered14ReceiverTx = receiverTx.filter((r) => r.created > before14Days); + + if (!filtered21SenderTx.length) return { receiver: [], sender: [] }; + if (!filtered14ReceiverTx?.length) { + const filtered21ReceiverTx = receiverTx.filter((r) => r.created > before21Days); + const { receiverIndex: rawReceiverIndex } = this.findSenderReceiverPair(filtered21SenderTx, filtered21ReceiverTx); + + return { + sender: filtered21SenderTx, + receiver: + rawReceiverIndex != null + ? filtered21ReceiverTx.filter((r) => r.id >= filtered21ReceiverTx[rawReceiverIndex]?.id) + : filtered14ReceiverTx, + }; + } + + const { senderPair, receiverIndex } = this.findSenderReceiverPair(filtered21SenderTx, filtered14ReceiverTx); + + if (filtered21SenderTx[0] instanceof BankTx) { + this.logger.verbose( + `FinanceLog receiverTxId/date: ${filtered14ReceiverTx?.[receiverIndex]?.id}/${filtered14ReceiverTx?.[ + receiverIndex + ]?.created.toDateString()}; senderTx[0] id/date: ${ + filtered21SenderTx[0]?.id + }/${filtered21SenderTx[0].valueDate.toDateString()}; senderPair id/date: ${senderPair?.id}/${ + senderPair && senderPair instanceof BankTx + ? senderPair.valueDate.toDateString() + : senderPair?.created.toDateString() + }; senderTx length: ${filtered21SenderTx.length}`, + ); + } + + return { + receiver: filtered14ReceiverTx.filter((r) => r.id >= filtered14ReceiverTx[receiverIndex]?.id ?? 0), + sender: (senderPair ? filtered21SenderTx.filter((s) => s.id >= senderPair.id) : filtered21SenderTx).sort( + (a, b) => a.id - b.id, + ), + }; + } + + private findSenderReceiverPair( + senderTx: (BankTx | ExchangeTx)[], + receiverTx: (BankTx | ExchangeTx)[] | undefined, + ): { senderPair: BankTx | ExchangeTx; receiverIndex: number } { + if (!receiverTx.length) return { receiverIndex: undefined, senderPair: undefined }; if (senderTx.length > 1) senderTx[0] instanceof BankTx ? senderTx.sort((a, b) => a.id - b.id) : senderTx.sort((a, b) => b.id - a.id); if (receiverTx.length > 1) receiverTx.sort((a, b) => a.id - b.id); + let receiverIndex = 0; + do { const receiverAmount = receiverTx[receiverIndex] instanceof BankTx ? (receiverTx[receiverIndex] as BankTx).instructedAmount : receiverTx[receiverIndex].amount; - senderPair = senderTx.find((s) => + const senderPair = senderTx.find((s) => s instanceof BankTx ? s.instructedAmount === receiverAmount && receiverTx[receiverIndex].created.toDateString() === s.valueDate.toDateString() && @@ -652,27 +681,14 @@ export class LogJobService { : s.amount === receiverAmount && receiverTx[receiverIndex].created > s.created, ); - if (!senderPair) receiverIndex++; - } while (!senderPair && receiverTx.length > receiverIndex); - - if (senderTx[0] instanceof BankTx) { - this.logger.verbose( - `FinanceLog receiverTxId/date: ${receiverTx?.[receiverIndex]?.id}/${receiverTx?.[ - receiverIndex - ]?.created.toDateString()}; senderTx[0] id/date: ${ - senderTx[0]?.id - }/${senderTx[0].valueDate.toDateString()}; senderPair id/date: ${senderPair?.id}/${ - senderPair && senderPair instanceof BankTx - ? senderPair.valueDate.toDateString() - : senderPair?.created.toDateString() - }; senderTx length: ${senderTx.length}`, - ); - } + if (!senderPair) { + receiverIndex++; + } else { + return { senderPair, receiverIndex }; + } + } while (receiverTx.length > receiverIndex); - return { - receiver: receiverTx.filter((r) => r.id >= receiverTx[receiverIndex]?.id ?? 0), - sender: (senderPair ? senderTx.filter((s) => s.id >= senderPair.id) : senderTx).sort((a, b) => a.id - b.id), - }; + return { receiverIndex: undefined, senderPair: undefined }; } private async getCustomBalances( From e0a5be5f2c83f08efac247516a533632f198a6d5 Mon Sep 17 00:00:00 2001 From: Yannick <52333989+Yannick1712@users.noreply.github.com> Date: Sat, 11 Jan 2025 15:12:59 +0100 Subject: [PATCH 09/13] [DEV-3210] custom mail template onChainLabs (#1868) * [DEV-3210] custo mail template onChainLabs * [DEV-3210] Refactoring * [DEV-3210] Refactoring 2 --- src/shared/services/process.service.ts | 1 + .../buy-crypto-notification.service.ts | 12 +- .../ref-reward-notification.service.ts | 3 +- .../services/buy-fiat-notification.service.ts | 12 +- .../generic/kyc/services/kyc-admin.service.ts | 2 +- .../kyc/services/kyc-notification.service.ts | 7 +- .../generic/kyc/services/tfa.service.ts | 1 + .../account-merge/account-merge.service.ts | 1 + .../generic/user/models/auth/auth.service.ts | 4 +- .../user-data/dto/create-user-data.dto.ts | 10 +- .../user-data-notification.service.ts | 3 + .../user/models/user-data/user-data.entity.ts | 4 + .../models/user-data/user-data.service.ts | 27 +- .../generic/user/models/user/user.service.ts | 1 + .../notification/entities/mail/user-mail.ts | 10 +- .../notification/factories/mail.factory.ts | 25 +- .../notification/templates/onChainLabs.hbs | 335 ++++++++++++++++++ .../services/payin-notification.service.ts | 3 +- .../transaction-notification.service.ts | 6 +- .../support-issue-notification.service.ts | 1 + .../services/support-issue.service.ts | 11 +- 21 files changed, 443 insertions(+), 36 deletions(-) create mode 100644 src/subdomains/supporting/notification/templates/onChainLabs.hbs diff --git a/src/shared/services/process.service.ts b/src/shared/services/process.service.ts index 09fab46c2b..16414a5320 100644 --- a/src/shared/services/process.service.ts +++ b/src/shared/services/process.service.ts @@ -54,6 +54,7 @@ export enum Process { PAYMENT_CONFIRMATIONS = 'PaymentConfirmations', FIAT_OUTPUT_COMPLETE = 'FiatOutputComplete', BLOCKCHAIN_FEE_UPDATE = 'BlockchainFeeUpdate', + USER_DATA_WALLET_SYNC = 'UserDataWalletSync', } type ProcessMap = { [p in Process]?: boolean }; diff --git a/src/subdomains/core/buy-crypto/process/services/buy-crypto-notification.service.ts b/src/subdomains/core/buy-crypto/process/services/buy-crypto-notification.service.ts index d32269b440..825cbbd58f 100644 --- a/src/subdomains/core/buy-crypto/process/services/buy-crypto-notification.service.ts +++ b/src/subdomains/core/buy-crypto/process/services/buy-crypto-notification.service.ts @@ -79,7 +79,7 @@ export class BuyCryptoNotificationService { outputAmount: Not(IsNull()), }, relations: { - transaction: { user: { userData: true } }, + transaction: { user: { userData: true, wallet: true } }, }, }); @@ -91,6 +91,7 @@ export class BuyCryptoNotificationService { context: MailContext.BUY_CRYPTO_COMPLETED, input: { userData: entity.userData, + wallet: entity.user.wallet, title: `${MailTranslationKey.CRYPTO_OUTPUT}.title`, salutation: { key: `${MailTranslationKey.CRYPTO_OUTPUT}.salutation` }, suffix: [ @@ -165,7 +166,7 @@ export class BuyCryptoNotificationService { amlReason: In(BuyCryptoAmlReasonPendingStates), amlCheck: CheckStatus.PENDING, }, - relations: { transaction: { user: { userData: true } } }, + relations: { transaction: { user: { userData: true, wallet: true } } }, }); entities.length > 0 && this.logger.verbose(`Sending ${entities.length} 'pending' email(s)`); @@ -178,6 +179,7 @@ export class BuyCryptoNotificationService { context: MailContext.BUY_CRYPTO_PENDING, input: { userData: entity.userData, + wallet: entity.user.wallet, title: `${MailFactory.parseMailKey(MailTranslationKey.PENDING, entity.amlReason)}.title`, salutation: { key: `${MailFactory.parseMailKey(MailTranslationKey.PENDING, entity.amlReason)}.salutation`, @@ -246,7 +248,7 @@ export class BuyCryptoNotificationService { cryptoInput: true, bankTx: true, checkoutTx: true, - transaction: { user: { userData: true } }, + transaction: { user: { userData: true, wallet: true } }, }, }); @@ -264,6 +266,7 @@ export class BuyCryptoNotificationService { context: MailContext.BUY_CRYPTO_RETURN, input: { userData: entity.userData, + wallet: entity.user.wallet, title: `${entity.translationReturnMailKey}.title`, salutation: { key: `${entity.translationReturnMailKey}.salutation` }, suffix: [ @@ -323,7 +326,7 @@ export class BuyCryptoNotificationService { amlReason: Not(IsNull()), amlCheck: CheckStatus.FAIL, }, - relations: { transaction: { user: { userData: true } } }, + relations: { transaction: { user: { userData: true, wallet: true } } }, }); entities.length > 0 && this.logger.verbose(`Sending ${entities.length} 'chargebackUnconfirmed' email(s)`); @@ -336,6 +339,7 @@ export class BuyCryptoNotificationService { context: MailContext.BUY_CRYPTO_CHARGEBACK_UNCONFIRMED, input: { userData: entity.userData, + wallet: entity.user.wallet, title: `${MailTranslationKey.CHARGEBACK_UNCONFIRMED}.title`, salutation: { key: `${MailTranslationKey.CHARGEBACK_UNCONFIRMED}.salutation`, diff --git a/src/subdomains/core/referral/reward/services/ref-reward-notification.service.ts b/src/subdomains/core/referral/reward/services/ref-reward-notification.service.ts index 6b97835991..914267099c 100644 --- a/src/subdomains/core/referral/reward/services/ref-reward-notification.service.ts +++ b/src/subdomains/core/referral/reward/services/ref-reward-notification.service.ts @@ -35,7 +35,7 @@ export class RefRewardNotificationService { targetAddress: Not(IsNull()), targetBlockchain: Not(IsNull()), }, - relations: { user: { userData: true } }, + relations: { user: { userData: true, wallet: true } }, }); entities.length > 0 && this.logger.verbose(`Sending ${entities.length} 'ref reward' email(s)`); @@ -50,6 +50,7 @@ export class RefRewardNotificationService { context: MailContext.REF_REWARD, input: { userData: entity.user.userData, + wallet: entity.user.wallet, title: `${MailTranslationKey.REFERRAL}.title`, salutation: { key: `${MailTranslationKey.REFERRAL}.salutation` }, table: { diff --git a/src/subdomains/core/sell-crypto/process/services/buy-fiat-notification.service.ts b/src/subdomains/core/sell-crypto/process/services/buy-fiat-notification.service.ts index 8744eb6813..a54d37e093 100644 --- a/src/subdomains/core/sell-crypto/process/services/buy-fiat-notification.service.ts +++ b/src/subdomains/core/sell-crypto/process/services/buy-fiat-notification.service.ts @@ -44,7 +44,7 @@ export class BuyFiatNotificationService { outputAmount: Not(IsNull()), }, relations: { - transaction: { user: { userData: true } }, + transaction: { user: { userData: true, wallet: true } }, }, }); @@ -56,6 +56,7 @@ export class BuyFiatNotificationService { context: MailContext.BUY_FIAT_COMPLETED, input: { userData: entity.userData, + wallet: entity.user.wallet, title: `${MailTranslationKey.FIAT_OUTPUT}.title`, salutation: { key: `${MailTranslationKey.FIAT_OUTPUT}.salutation` }, suffix: [ @@ -127,7 +128,7 @@ export class BuyFiatNotificationService { amlReason: In(BuyFiatAmlReasonPendingStates), amlCheck: CheckStatus.PENDING, }, - relations: { sell: true, transaction: { user: { userData: true } } }, + relations: { sell: true, transaction: { user: { userData: true, wallet: true } } }, }); entities.length > 0 && this.logger.verbose(`Sending ${entities.length} 'pending' email(s)`); @@ -140,6 +141,7 @@ export class BuyFiatNotificationService { context: MailContext.BUY_FIAT_PENDING, input: { userData: entity.userData, + wallet: entity.user.wallet, title: `${MailFactory.parseMailKey(MailTranslationKey.PENDING, entity.amlReason)}.title`, salutation: { key: `${MailFactory.parseMailKey(MailTranslationKey.PENDING, entity.amlReason)}.salutation`, @@ -199,7 +201,7 @@ export class BuyFiatNotificationService { amlReason: Not(IsNull()), mailReturnSendDate: IsNull(), }, - relations: { sell: true, cryptoInput: true, transaction: { user: { userData: true } } }, + relations: { sell: true, cryptoInput: true, transaction: { user: { userData: true, wallet: true } } }, }); entities.length > 0 && this.logger.verbose(`Sending ${entities.length} chargeback email(s)`); @@ -216,6 +218,7 @@ export class BuyFiatNotificationService { context: MailContext.BUY_FIAT_RETURN, input: { userData: entity.userData, + wallet: entity.user.wallet, title: `${MailTranslationKey.CRYPTO_CHARGEBACK}.title`, salutation: { key: `${MailTranslationKey.CRYPTO_CHARGEBACK}.salutation` }, suffix: [ @@ -278,7 +281,7 @@ export class BuyFiatNotificationService { amlReason: Not(IsNull()), amlCheck: CheckStatus.FAIL, }, - relations: { transaction: { user: { userData: true } } }, + relations: { transaction: { user: { userData: true, wallet: true } } }, }); entities.length > 0 && this.logger.verbose(`Sending ${entities.length} 'chargebackUnconfirmed' email(s)`); @@ -291,6 +294,7 @@ export class BuyFiatNotificationService { context: MailContext.BUY_FIAT_CHARGEBACK_UNCONFIRMED, input: { userData: entity.userData, + wallet: entity.user.wallet, title: `${MailTranslationKey.CHARGEBACK_UNCONFIRMED}.title`, salutation: { key: `${MailTranslationKey.CHARGEBACK_UNCONFIRMED}.salutation`, diff --git a/src/subdomains/generic/kyc/services/kyc-admin.service.ts b/src/subdomains/generic/kyc/services/kyc-admin.service.ts index 7ff09ca4b0..1503f9fd5e 100644 --- a/src/subdomains/generic/kyc/services/kyc-admin.service.ts +++ b/src/subdomains/generic/kyc/services/kyc-admin.service.ts @@ -29,7 +29,7 @@ export class KycAdminService { async updateKycStep(stepId: number, dto: UpdateKycStepDto): Promise { const kycStep = await this.kycStepRepo.findOne({ where: { id: stepId }, - relations: { userData: { bankDatas: true } }, + relations: { userData: { bankDatas: true, wallet: true } }, }); if (!kycStep) throw new NotFoundException('KYC step not found'); diff --git a/src/subdomains/generic/kyc/services/kyc-notification.service.ts b/src/subdomains/generic/kyc/services/kyc-notification.service.ts index de4cb9dd64..acfdf9c04c 100644 --- a/src/subdomains/generic/kyc/services/kyc-notification.service.ts +++ b/src/subdomains/generic/kyc/services/kyc-notification.service.ts @@ -43,7 +43,7 @@ export class KycNotificationService { status: In([UserDataStatus.NA, UserDataStatus.ACTIVE, UserDataStatus.KYC_ONLY]), }, }, - relations: { userData: true }, + relations: { userData: { wallet: true } }, }); entities.length > 0 && this.logger.verbose(`Sending ${entities.length} KYC reminder email(s)`); @@ -58,6 +58,7 @@ export class KycNotificationService { context: MailContext.KYC_REMINDER, input: { userData: entity.userData, + wallet: entity.userData.wallet, title: `${MailTranslationKey.KYC_REMINDER}.title`, salutation: { key: `${MailTranslationKey.KYC_REMINDER}.salutation` }, suffix: [ @@ -99,7 +100,8 @@ export class KycNotificationService { type: MailType.USER, context: MailContext.KYC_FAILED, input: { - userData: userData, + userData, + wallet: userData.wallet, title: `${MailTranslationKey.KYC_FAILED}.title`, salutation: { key: `${MailTranslationKey.KYC_FAILED}.salutation` }, suffix: [ @@ -149,6 +151,7 @@ export class KycNotificationService { context: MailContext.KYC_CHANGED, input: { userData, + wallet: userData.wallet, title: `${MailTranslationKey.KYC_SUCCESS}.title`, salutation: { key: `${MailTranslationKey.KYC_SUCCESS}.salutation` }, suffix: [ diff --git a/src/subdomains/generic/kyc/services/tfa.service.ts b/src/subdomains/generic/kyc/services/tfa.service.ts index fbadc7b252..3788b8627f 100644 --- a/src/subdomains/generic/kyc/services/tfa.service.ts +++ b/src/subdomains/generic/kyc/services/tfa.service.ts @@ -162,6 +162,7 @@ export class TfaService { context, input: { userData: userData, + wallet: userData.wallet, title: `${MailTranslationKey.VERIFICATION_CODE}.${tag}.title`, salutation: { key: `${MailTranslationKey.VERIFICATION_CODE}.${tag}.salutation`, diff --git a/src/subdomains/generic/user/models/account-merge/account-merge.service.ts b/src/subdomains/generic/user/models/account-merge/account-merge.service.ts index 197a9cc721..6d707c5b73 100644 --- a/src/subdomains/generic/user/models/account-merge/account-merge.service.ts +++ b/src/subdomains/generic/user/models/account-merge/account-merge.service.ts @@ -53,6 +53,7 @@ export class AccountMergeService { context: MailContext.ACCOUNT_MERGE_REQUEST, input: { userData: receiver, + wallet: receiver.wallet, title: `${MailTranslationKey.ACCOUNT_MERGE_REQUEST}.title`, salutation: { key: `${MailTranslationKey.ACCOUNT_MERGE_REQUEST}.salutation` }, prefix: [ diff --git a/src/subdomains/generic/user/models/auth/auth.service.ts b/src/subdomains/generic/user/models/auth/auth.service.ts index f62dcaf3cf..f6b9f56e3e 100644 --- a/src/subdomains/generic/user/models/auth/auth.service.ts +++ b/src/subdomains/generic/user/models/auth/auth.service.ts @@ -220,6 +220,7 @@ export class AuthService { mail: dto.mail, language: dto.language ?? language, status: UserDataStatus.KYC_ONLY, + wallet: await this.walletService.getDefault(), })); // create random key @@ -240,7 +241,8 @@ export class AuthService { type: MailType.USER, context: MailContext.LOGIN, input: { - userData: userData, + userData, + wallet: userData.wallet, title: `${MailTranslationKey.LOGIN}.title`, salutation: { key: `${MailTranslationKey.LOGIN}.salutation` }, suffix: [ diff --git a/src/subdomains/generic/user/models/user-data/dto/create-user-data.dto.ts b/src/subdomains/generic/user/models/user-data/dto/create-user-data.dto.ts index 38e941b715..6920402a1b 100644 --- a/src/subdomains/generic/user/models/user-data/dto/create-user-data.dto.ts +++ b/src/subdomains/generic/user/models/user-data/dto/create-user-data.dto.ts @@ -1,4 +1,7 @@ -import { IsEnum, IsNotEmpty } from 'class-validator'; +import { Type } from 'class-transformer'; +import { IsEnum, IsNotEmpty, IsOptional, ValidateNested } from 'class-validator'; +import { EntityDto } from 'src/shared/dto/entity.dto'; +import { Wallet } from '../../wallet/wallet.entity'; import { KycType } from '../user-data.entity'; import { UpdateUserDataDto } from './update-user-data.dto'; @@ -6,4 +9,9 @@ export class CreateUserDataDto extends UpdateUserDataDto { @IsNotEmpty() @IsEnum(KycType) kycType: KycType; + + @IsOptional() + @ValidateNested() + @Type(() => EntityDto) + wallet: Wallet; } diff --git a/src/subdomains/generic/user/models/user-data/user-data-notification.service.ts b/src/subdomains/generic/user/models/user-data/user-data-notification.service.ts index dda912e787..31ef1077d2 100644 --- a/src/subdomains/generic/user/models/user-data/user-data-notification.service.ts +++ b/src/subdomains/generic/user/models/user-data/user-data-notification.service.ts @@ -36,6 +36,7 @@ export class UserDataNotificationService { context: MailContext.ADDED_ADDRESS, input: { userData: master, + wallet: master.wallet, title: `${MailTranslationKey.ACCOUNT_MERGE_ADDED_ADDRESS}.title`, salutation: { key: `${MailTranslationKey.ACCOUNT_MERGE_ADDED_ADDRESS}.salutation` }, prefix: [ @@ -74,6 +75,7 @@ export class UserDataNotificationService { context: MailContext.CHANGED_MAIL, input: { userData: master, + wallet: master.wallet, title: `${MailTranslationKey.ACCOUNT_MERGE_CHANGED_MAIL}.title`, salutation: { key: `${MailTranslationKey.ACCOUNT_MERGE_CHANGED_MAIL}.salutation` }, prefix: [ @@ -98,6 +100,7 @@ export class UserDataNotificationService { context: MailContext.CHANGED_MAIL, input: { userData: slave, + wallet: slave.wallet, title: `${MailTranslationKey.ACCOUNT_MERGE_CHANGED_MAIL}.title`, salutation: { key: `${MailTranslationKey.ACCOUNT_MERGE_CHANGED_MAIL}.salutation` }, prefix: [ diff --git a/src/subdomains/generic/user/models/user-data/user-data.entity.ts b/src/subdomains/generic/user/models/user-data/user-data.entity.ts index 3385c19ffd..d9a213786b 100644 --- a/src/subdomains/generic/user/models/user-data/user-data.entity.ts +++ b/src/subdomains/generic/user/models/user-data/user-data.entity.ts @@ -19,6 +19,7 @@ import { SupportIssue } from 'src/subdomains/supporting/support-issue/entities/s import { Column, Entity, Generated, Index, JoinColumn, ManyToOne, OneToMany } from 'typeorm'; import { UserDataRelation } from '../user-data-relation/user-data-relation.entity'; import { TradingLimit } from '../user/dto/user.dto'; +import { Wallet } from '../wallet/wallet.entity'; import { AccountType } from './account-type.enum'; import { KycIdentificationType } from './kyc-identification-type.enum'; @@ -341,6 +342,9 @@ export class UserData extends IEntity { paymentLinksConfig?: string; // PaymentLinkConfig // References + @ManyToOne(() => Wallet, { nullable: true }) + wallet: Wallet; + @ManyToOne(() => UserData, { nullable: true }) @JoinColumn() accountOpener?: UserData; diff --git a/src/subdomains/generic/user/models/user-data/user-data.service.ts b/src/subdomains/generic/user/models/user-data/user-data.service.ts index d67d7367f1..a7e2800f1d 100644 --- a/src/subdomains/generic/user/models/user-data/user-data.service.ts +++ b/src/subdomains/generic/user/models/user-data/user-data.service.ts @@ -21,6 +21,7 @@ import { SettingService } from 'src/shared/models/setting/setting.service'; import { RepositoryFactory } from 'src/shared/repositories/repository.factory'; import { ApiKeyService } from 'src/shared/services/api-key.service'; import { DfxLogger } from 'src/shared/services/dfx-logger'; +import { DisabledProcess, Process } from 'src/shared/services/process.service'; import { Lock } from 'src/shared/utils/lock'; import { Util } from 'src/shared/utils/util'; import { CheckStatus } from 'src/subdomains/core/aml/enums/check-status.enum'; @@ -86,6 +87,26 @@ export class UserDataService { private readonly tfaService: TfaService, ) {} + @Cron(CronExpression.EVERY_MINUTE) + @Lock(7200) + async syncWallet() { + if (DisabledProcess(Process.USER_DATA_WALLET_SYNC)) return; + + const entities = await this.userDataRepo.find({ + where: { wallet: { id: IsNull() }, users: { id: Not(IsNull()) } }, + relations: { users: { wallet: true } }, + take: 10000, + }); + + for (const entity of entities) { + try { + await this.userDataRepo.update(entity.id, { wallet: entity.users[0].wallet }); + } catch (e) { + this.logger.error(`Error in userData wallet sync: ${entity.id}`, e); + } + } + } + // --- GETTERS --- // async getUserDataByUser(userId: number): Promise { return this.userDataRepo @@ -140,7 +161,7 @@ export class UserDataService { mail, status: In([UserDataStatus.ACTIVE, UserDataStatus.NA, UserDataStatus.KYC_ONLY, UserDataStatus.DEACTIVATED]), }, - relations: { users: true }, + relations: { users: true, wallet: true }, }); } @@ -175,7 +196,7 @@ export class UserDataService { async updateUserData(userDataId: number, dto: UpdateUserDataDto): Promise { const userData = await this.userDataRepo.findOne({ where: { id: userDataId }, - relations: { users: { wallet: true }, kycSteps: true }, + relations: { users: { wallet: true }, kycSteps: true, wallet: true }, }); if (!userData) throw new NotFoundException('User data not found'); @@ -740,6 +761,7 @@ export class UserDataService { relatedAccountRelations: true, kycSteps: true, supportIssues: true, + wallet: true, }, }), this.userDataRepo.findOne({ @@ -751,6 +773,7 @@ export class UserDataService { relatedAccountRelations: true, kycSteps: true, supportIssues: true, + wallet: true, }, }), ]); diff --git a/src/subdomains/generic/user/models/user/user.service.ts b/src/subdomains/generic/user/models/user/user.service.ts index 57d55c2340..ad1bcf0854 100644 --- a/src/subdomains/generic/user/models/user/user.service.ts +++ b/src/subdomains/generic/user/models/user/user.service.ts @@ -187,6 +187,7 @@ export class UserService { kycType: user.wallet.customKyc ?? KycType.DFX, language, currency, + wallet: user.wallet, })); user = await this.userRepo.save(user); userIsActive && (await this.userRepo.setUserRef(user, userData?.kycLevel)); diff --git a/src/subdomains/supporting/notification/entities/mail/user-mail.ts b/src/subdomains/supporting/notification/entities/mail/user-mail.ts index 62344b6f2b..b56298b984 100644 --- a/src/subdomains/supporting/notification/entities/mail/user-mail.ts +++ b/src/subdomains/supporting/notification/entities/mail/user-mail.ts @@ -1,11 +1,13 @@ import { Config } from 'src/config/config'; import { UserData } from 'src/subdomains/generic/user/models/user-data/user-data.entity'; +import { Wallet } from 'src/subdomains/generic/user/models/wallet/wallet.entity'; import { MailAffix, TranslationItem } from '../../interfaces'; import { NotificationOptions } from '../notification.entity'; import { Mail } from './base/mail'; export interface MailRequestUserInput { userData: UserData; + wallet: Wallet; title: string; salutation?: TranslationItem; prefix?: TranslationItem[]; @@ -34,7 +36,7 @@ export interface UserMailParams { } export class UserMail extends Mail { - constructor(params: UserMailParams) { + constructor(params: UserMailParams, wallet: Wallet) { const defaultParams: Partial = { twitterUrl: Config.social.twitter, telegramUrl: Config.social.telegram, @@ -42,6 +44,10 @@ export class UserMail extends Mail { instagramUrl: Config.social.instagram, }; - super({ ...params, template: 'user', templateParams: { ...defaultParams, ...params } }); + super({ + ...params, + template: wallet?.name === 'onchainlabs' ? 'onChainLabs' : 'user', + templateParams: { ...defaultParams, ...params }, + }); } } diff --git a/src/subdomains/supporting/notification/factories/mail.factory.ts b/src/subdomains/supporting/notification/factories/mail.factory.ts index 471072c2d8..def5490059 100644 --- a/src/subdomains/supporting/notification/factories/mail.factory.ts +++ b/src/subdomains/supporting/notification/factories/mail.factory.ts @@ -136,20 +136,23 @@ export class MailFactory { private createUserMail(request: MailRequest): UserMail { const { correlationId, options } = request; - const { userData, title, salutation, prefix, suffix, table } = request.input as MailRequestUserInput; + const { userData, wallet, title, salutation, prefix, suffix, table } = request.input as MailRequestUserInput; const lang = userData.language.symbol; - return new UserMail({ - to: userData.mail, - subject: this.translate(title, lang), - salutation: salutation && this.translate(salutation.key, lang, salutation.params), - prefix: prefix && this.getMailAffix(prefix, lang), - table: table && this.getTable(table, lang), - suffix: suffix && this.getMailAffix(suffix, lang), - correlationId, - options, - }); + return new UserMail( + { + to: userData.mail, + subject: this.translate(title, lang), + salutation: salutation && this.translate(salutation.key, lang, salutation.params), + prefix: prefix && this.getMailAffix(prefix, lang), + table: table && this.getTable(table, lang), + suffix: suffix && this.getMailAffix(suffix, lang), + correlationId, + options, + }, + wallet, + ); } private createPersonalMail(request: MailRequest): PersonalMail { diff --git a/src/subdomains/supporting/notification/templates/onChainLabs.hbs b/src/subdomains/supporting/notification/templates/onChainLabs.hbs new file mode 100644 index 0000000000..1783d12778 --- /dev/null +++ b/src/subdomains/supporting/notification/templates/onChainLabs.hbs @@ -0,0 +1,335 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + {{!-- Logo Block --}} +
+
+
+ + + +
+
+
+ + + + + + + +
+ + + + +
+ +
+
+ +
+
+
+ + +
+
+
+ + + + + {{!-- Salutation Block --}} +
+
+
+ + + +
+
+
+ + + + + + + +
+
+

{{salutation}}

+
+
+ +
+
+
+ + +
+
+
+ + + + + {{!-- Prefix Block --}} + {{#each prefix}} +
+
+
+ + + +
+
+
+ + + + + + + +
+
+ + {{!-- Future Button --}} + {{!-- + {{SEE DETAILS}} + --}} + +

{{{this.text}}}

+ {{#if this.url}}{{this.url.text}} + {{#if this.url.textSuffix}}{{this.url.textSuffix}}{{/if}} + {{/if}} + {{#if this.mail}}{{this.mail.address}} + {{#if this.mail.textSuffix}}{{this.mail.textSuffix}}{{/if}} + {{/if}} +
+
+ +
+
+
+ + +
+
+
+ {{/each}} + + + + + {{!-- Table Block --}} + {{#each table}} +
+
+
+ + + +
+
+
+ + + + + + + + + +
+ {{this.text}} + + {{this.value}} +
+ +
+
+
+ + +
+
+
+ {{/each}} + + + + + {{!-- Suffix Block --}} + {{#each suffix}} +
+
+
+ + + +
+
+
+ + + + + + + +
+
+ + {{!-- Future Button --}} + {{!-- + {{SEE DETAILS}} + --}} + +

{{{this.text}}}

+ {{#if this.url}}{{this.url.text}} + {{#if this.url.textSuffix}}{{this.url.textSuffix}}{{/if}} + {{/if}} + {{#if this.mail}}{{this.mail.address}} + {{#if this.mail.textSuffix}}{{this.mail.textSuffix}}{{/if}} + {{/if}} +
+
+ +
+
+
+ + +
+
+
+ {{/each}} + + + + + +
+ + + + + diff --git a/src/subdomains/supporting/payin/services/payin-notification.service.ts b/src/subdomains/supporting/payin/services/payin-notification.service.ts index ebd4fec4bf..2fa391b1f7 100644 --- a/src/subdomains/supporting/payin/services/payin-notification.service.ts +++ b/src/subdomains/supporting/payin/services/payin-notification.service.ts @@ -37,7 +37,7 @@ export class PayInNotificationService { returnTxId: Not(IsNull()), action: PayInAction.RETURN, }, - relations: { route: { user: { userData: true } } }, + relations: { route: { user: { userData: true, wallet: true } } }, }); entities.length > 0 && this.logger.verbose(`Sending ${entities.length} cryptoInput return email(s)`); @@ -50,6 +50,7 @@ export class PayInNotificationService { context: MailContext.CRYPTO_INPUT_RETURN, input: { userData: entity.route.user.userData, + wallet: entity.route.user.wallet, title: `${MailTranslationKey.CRYPTO_CHARGEBACK}.title`, salutation: { key: `${MailTranslationKey.CRYPTO_CHARGEBACK}.salutation` }, table: { diff --git a/src/subdomains/supporting/payment/services/transaction-notification.service.ts b/src/subdomains/supporting/payment/services/transaction-notification.service.ts index 6278aef02e..4ed7ce6006 100644 --- a/src/subdomains/supporting/payment/services/transaction-notification.service.ts +++ b/src/subdomains/supporting/payment/services/transaction-notification.service.ts @@ -45,7 +45,7 @@ export class TransactionNotificationService { relations: { buyCrypto: true, buyFiat: true, - user: { userData: true }, + user: { userData: true, wallet: true }, }, }); if (entities.length === 0) return; @@ -64,6 +64,7 @@ export class TransactionNotificationService { context: entity.mailContext, input: { userData: entity.userData, + wallet: entity.user.wallet, title: `${entity.targetEntity.inputMailTranslationKey}.title`, salutation: { key: `${entity.targetEntity.inputMailTranslationKey}.salutation` }, suffix: [ @@ -94,7 +95,7 @@ export class TransactionNotificationService { bankTx: { type: In(BankTxUnassignedTypes), creditDebitIndicator: BankTxIndicator.CREDIT }, mailSendDate: IsNull(), }, - relations: { bankTx: true }, + relations: { bankTx: true, user: { wallet: true } }, }); if (entities.length === 0) return; @@ -109,6 +110,7 @@ export class TransactionNotificationService { context: MailContext.UNASSIGNED_TX, input: { userData: bankData.userData, + wallet: entity.user.wallet, title: `${MailTranslationKey.UNASSIGNED_FIAT_INPUT}.title`, salutation: { key: `${MailTranslationKey.UNASSIGNED_FIAT_INPUT}.salutation` }, suffix: [ diff --git a/src/subdomains/supporting/support-issue/services/support-issue-notification.service.ts b/src/subdomains/supporting/support-issue/services/support-issue-notification.service.ts index a74a01ddc7..4c1befe2a7 100644 --- a/src/subdomains/supporting/support-issue/services/support-issue-notification.service.ts +++ b/src/subdomains/supporting/support-issue/services/support-issue-notification.service.ts @@ -20,6 +20,7 @@ export class SupportIssueNotificationService { context: MailContext.SUPPORT_MESSAGE, input: { userData: entity.userData, + wallet: entity.userData.wallet, title: `${MailTranslationKey.SUPPORT_MESSAGE}.title`, salutation: { key: `${MailTranslationKey.SUPPORT_MESSAGE}.salutation` }, prefix: [ diff --git a/src/subdomains/supporting/support-issue/services/support-issue.service.ts b/src/subdomains/supporting/support-issue/services/support-issue.service.ts index 92d9229da9..423fdea089 100644 --- a/src/subdomains/supporting/support-issue/services/support-issue.service.ts +++ b/src/subdomains/supporting/support-issue/services/support-issue.service.ts @@ -41,7 +41,7 @@ export class SupportIssueService { async createIssue(userDataId: number, dto: CreateSupportIssueDto): Promise { // mail is required - const userData = await this.userDataService.getUserData(userDataId); + const userData = await this.userDataService.getUserData(userDataId, { wallet: true }); if (!userData.mail) throw new BadRequestException('Mail is missing'); const newIssue = this.supportIssueRepo.create({ userData, ...dto }); @@ -54,7 +54,7 @@ export class SupportIssueService { transaction: { id: newIssue.transaction?.id ?? IsNull() }, state: dto.limitRequest ? Not(SupportIssueState.COMPLETED) : undefined, }, - relations: { messages: true, transaction: true, limitRequest: true }, + relations: { messages: true, transaction: true, limitRequest: true, userData: { wallet: true } }, }); if (!existingIssue) { @@ -101,14 +101,17 @@ export class SupportIssueService { } async createMessage(id: string, dto: CreateSupportMessageDto, userDataId?: number): Promise { - const issue = await this.supportIssueRepo.findOneBy(this.getIssueSearch(id, userDataId)); + const issue = await this.supportIssueRepo.findOne({ + where: this.getIssueSearch(id, userDataId), + relations: { userData: { wallet: true } }, + }); if (!issue) throw new NotFoundException('Support issue not found'); return this.createMessageInternal(issue, { ...dto, author: CustomerAuthor }); } async createMessageSupport(id: number, dto: CreateSupportMessageDto): Promise { - const issue = await this.supportIssueRepo.findOneBy({ id }); + const issue = await this.supportIssueRepo.findOne({ where: { id }, relations: { userData: { wallet: true } } }); if (!issue) throw new NotFoundException('Support issue not found'); return this.createMessageInternal(issue, dto); From 5e5b99bacde1a442fe63fe43f1e22296e9efd120 Mon Sep 17 00:00:00 2001 From: Yannick <52333989+Yannick1712@users.noreply.github.com> Date: Sat, 11 Jan 2025 15:29:20 +0100 Subject: [PATCH 10/13] [DEV-3511] mail bankTx currency exchange (#1879) * [DEV-3511] mail bankTx currency exchange * [DEV-3511] Renaming --- src/shared/i18n/de/mail.json | 3 ++- src/shared/i18n/en/mail.json | 3 ++- src/shared/i18n/es/mail.json | 3 ++- src/shared/i18n/fr/mail.json | 3 ++- src/shared/i18n/it/mail.json | 3 ++- src/shared/i18n/pt/mail.json | 3 ++- src/shared/utils/util.ts | 4 ++++ .../services/transaction-notification.service.ts | 14 ++++++++++++++ 8 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/shared/i18n/de/mail.json b/src/shared/i18n/de/mail.json index b271a72766..3653c94601 100644 --- a/src/shared/i18n/de/mail.json +++ b/src/shared/i18n/de/mail.json @@ -27,7 +27,8 @@ "title": "Einzahlung zuordnen", "salutation": "Deine Einzahlung kann nicht automatisch zugeordnet werden", "transaction_button": "Bitte ordne deinen Zahlungseingang deiner Bestellung zu:
[url:Klick hier]" - } + }, + "currency_exchange": "Übrigens: Das {bankAccount} Bankkonto ist ein {bankAsset}-Konto, wenn du {inputAsset} schickst wird dies direkt bei der Bank getauscht und wir erhalten {bankAsset}.
Wenn möglich schicke also direkt {bankAsset} zu diesem Bankkonto." }, "crypto_output": { "title": "Krypto-Asset verschickt", diff --git a/src/shared/i18n/en/mail.json b/src/shared/i18n/en/mail.json index fd950cb059..ee79a810ef 100644 --- a/src/shared/i18n/en/mail.json +++ b/src/shared/i18n/en/mail.json @@ -27,7 +27,8 @@ "title": "Assign deposit", "salutation": "Your deposit cannot be allocated automatically", "transaction_button": "Please assign your deposit to your order:
[url:click here]" - } + }, + "currency_exchange": "By the way: The {bankAccount} bank account is a {bankAsset} account, if you send {inputAsset} this will be exchanged directly at the bank and we will receive {bankAsset}.
If possible, send {bankAsset} to this bank account." }, "crypto_output": { "title": "Crypto asset paid out", diff --git a/src/shared/i18n/es/mail.json b/src/shared/i18n/es/mail.json index c07563edd8..677dab1297 100644 --- a/src/shared/i18n/es/mail.json +++ b/src/shared/i18n/es/mail.json @@ -27,7 +27,8 @@ "title": "Asignar depósito", "salutation": "Su depósito no puede asignarse automáticamente", "transaction_button": "Por favor, asigne su depósito a su pedido:
[url:haga clic aquí]" - } + }, + "currency_exchange": "Por cierto: La cuenta bancaria {bankAccount} es una cuenta {bankAsset}, si envías {inputAsset} este será canjeado directamente en el banco y recibiremos {bankAsset}.
Si es posible, envía {bankAsset} directamente a esta cuenta bancaria." }, "crypto_output": { "title": "Criptoactivo pagado", diff --git a/src/shared/i18n/fr/mail.json b/src/shared/i18n/fr/mail.json index f35bf979f6..2f60f36a35 100644 --- a/src/shared/i18n/fr/mail.json +++ b/src/shared/i18n/fr/mail.json @@ -27,7 +27,8 @@ "title": "Attribuer un dépôt", "salutation": "Votre dépôt ne peut pas être attribué automatiquement", "transaction_button": "Veuillez affecter votre dépôt à votre commande:
[url:cliquez ici]" - } + }, + "currency_exchange": "Par ailleurs: le compte bancaire {bankAccount} est un compte {bankAsset}, si vous envoyez {inputAsset}, il sera échangé directement à la banque et nous recevrons {bankAsset}.
Si possible, envoyez {bankAsset} directement sur ce compte bancaire." }, "crypto_output": { "title": "Actif cryptographique payé", diff --git a/src/shared/i18n/it/mail.json b/src/shared/i18n/it/mail.json index 6c10d57550..aae14f7394 100644 --- a/src/shared/i18n/it/mail.json +++ b/src/shared/i18n/it/mail.json @@ -27,7 +27,8 @@ "title": "Assegnazione del deposito", "salutation": "Il vostro deposito non può essere assegnato automaticamente", "transaction_button": "Si prega di assegnare il deposito all'ordine:
[url:clicca qui]" - } + }, + "currency_exchange": "A proposito: il conto bancario {bankAccount} è un conto {bankAsset}, se inviate {inputAsset} questo sarà scambiato direttamente in banca e noi riceveremo {bankAsset}.
Se possibile, inviate {bankAsset} direttamente a questo conto bancario." }, "crypto_output": { "title": "Attività in criptovaluta pagata", diff --git a/src/shared/i18n/pt/mail.json b/src/shared/i18n/pt/mail.json index fd950cb059..ee79a810ef 100644 --- a/src/shared/i18n/pt/mail.json +++ b/src/shared/i18n/pt/mail.json @@ -27,7 +27,8 @@ "title": "Assign deposit", "salutation": "Your deposit cannot be allocated automatically", "transaction_button": "Please assign your deposit to your order:
[url:click here]" - } + }, + "currency_exchange": "By the way: The {bankAccount} bank account is a {bankAsset} account, if you send {inputAsset} this will be exchanged directly at the bank and we will receive {bankAsset}.
If possible, send {bankAsset} to this bank account." }, "crypto_output": { "title": "Crypto asset paid out", diff --git a/src/shared/utils/util.ts b/src/shared/utils/util.ts index 82279028ba..c05b485b13 100644 --- a/src/shared/utils/util.ts +++ b/src/shared/utils/util.ts @@ -494,6 +494,10 @@ export class Util { ); } + static blankCenter(value: string, visibleLength = 4): string { + return value.slice(0, visibleLength) + this.blankStart(value, visibleLength); + } + static blankStart(value: string, visibleLength = 4): string { return '***' + value.slice(value.length - visibleLength); } diff --git a/src/subdomains/supporting/payment/services/transaction-notification.service.ts b/src/subdomains/supporting/payment/services/transaction-notification.service.ts index 4ed7ce6006..67eace2aff 100644 --- a/src/subdomains/supporting/payment/services/transaction-notification.service.ts +++ b/src/subdomains/supporting/payment/services/transaction-notification.service.ts @@ -3,6 +3,7 @@ import { Cron, CronExpression } from '@nestjs/schedule'; import { DfxLogger } from 'src/shared/services/dfx-logger'; import { DisabledProcess, Process } from 'src/shared/services/process.service'; import { Lock } from 'src/shared/utils/lock'; +import { Util } from 'src/shared/utils/util'; import { BuyCrypto } from 'src/subdomains/core/buy-crypto/process/entities/buy-crypto.entity'; import { BuyFiat } from 'src/subdomains/core/sell-crypto/process/buy-fiat.entity'; import { BankDataService } from 'src/subdomains/generic/user/models/bank-data/bank-data.service'; @@ -43,6 +44,7 @@ export class TransactionNotificationService { mailSendDate: IsNull(), }, relations: { + bankTx: true, buyCrypto: true, buyFiat: true, user: { userData: true, wallet: true }, @@ -76,6 +78,18 @@ export class TransactionNotificationService { key: `${MailTranslationKey.GENERAL}.link`, params: { url: entity.url, urlText: entity.url }, }, + { key: MailKey.SPACE, params: { value: '4' } }, + entity.bankTx && entity.bankTx.instructedCurrency !== entity.bankTx.currency + ? { + key: `${MailTranslationKey.FIAT_INPUT}.currency_exchange`, + params: { + bankAccount: Util.blankCenter(entity.bankTx.accountIban), + bankAsset: entity.bankTx.currency, + inputAsset: entity.bankTx.instructedCurrency, + }, + } + : null, + { key: MailKey.SPACE, params: { value: '4' } }, { key: MailKey.DFX_TEAM_CLOSING }, ], From 865393ac4a06b8503a8808934dbc306abb3075ef Mon Sep 17 00:00:00 2001 From: bernd2022 <104787072+bernd2022@users.noreply.github.com> Date: Mon, 13 Jan 2025 11:48:06 +0100 Subject: [PATCH 11/13] [DEV-3452] Coingecko: TVL frankencoin / deuro (#1894) * [DEV-3452] Coingecko: TVL frankencoin / deuro * [DEV-3425] TVL ignore price not available --- infrastructure/bicep/dfx-api.bicep | 5 -- infrastructure/bicep/parameters/dev.json | 3 -- infrastructure/bicep/parameters/loc.json | 3 -- infrastructure/bicep/parameters/prd.json | 3 -- src/config/config.ts | 2 - .../blockchain/deuro/deuro-client.ts | 6 +-- .../blockchain/deuro/deuro.service.ts | 26 +++++++--- .../blockchain/deuro/dto/deuro.dto.ts | 10 ++-- .../frankencoin/dto/frankencoin.dto.ts | 10 ++-- .../frankencoin/frankencoin-client.ts | 10 ++-- .../frankencoin/frankencoin.service.ts | 25 ++++++--- .../frankencoin/frankencoin-based.dto.ts | 6 +++ .../frankencoin/frankencoin-based.service.ts | 49 ++++++++++++++++++ .../integration/coin-gecko.service.ts | 51 ++++++++++++++++--- 14 files changed, 152 insertions(+), 57 deletions(-) create mode 100644 src/integration/blockchain/shared/frankencoin/frankencoin-based.dto.ts create mode 100644 src/integration/blockchain/shared/frankencoin/frankencoin-based.service.ts diff --git a/infrastructure/bicep/dfx-api.bicep b/infrastructure/bicep/dfx-api.bicep index 0066575be6..548f338999 100644 --- a/infrastructure/bicep/dfx-api.bicep +++ b/infrastructure/bicep/dfx-api.bicep @@ -132,7 +132,6 @@ param moneroRpcCertificate string param zchfGatewayUrl string param zchfGraphUrl string -param zchfTvlUrl string param zchfContractAddress string param zchfEquityContractAddress string param zchfStablecoinBridgeContractAddress string @@ -895,10 +894,6 @@ resource apiAppService 'Microsoft.Web/sites@2018-11-01' = { name: 'ZCHF_GRAPH_URL' value: zchfGraphUrl } - { - name: 'ZCHF_TVL_URL' - value: zchfTvlUrl - } { name: 'ZCHF_CONTRACT_ADDRESS' value: zchfContractAddress diff --git a/infrastructure/bicep/parameters/dev.json b/infrastructure/bicep/parameters/dev.json index 9ae526351c..3271a33cd3 100644 --- a/infrastructure/bicep/parameters/dev.json +++ b/infrastructure/bicep/parameters/dev.json @@ -254,9 +254,6 @@ "zchfGraphUrl": { "value": "https://maindevponder.frankencoin.com" }, - "zchfTvlUrl": { - "value": "https://api.llama.fi/tvl/frankencoin" - }, "zchfContractAddress": { "value": "0xB58E61C3098d85632Df34EecfB899A1Ed80921cB" }, diff --git a/infrastructure/bicep/parameters/loc.json b/infrastructure/bicep/parameters/loc.json index bb6e8ac954..01f04d3cbb 100644 --- a/infrastructure/bicep/parameters/loc.json +++ b/infrastructure/bicep/parameters/loc.json @@ -254,9 +254,6 @@ "zchfGraphUrl": { "value": "https://maindevponder.frankencoin.com" }, - "zchfTvlUrl": { - "value": "https://api.llama.fi/tvl/frankencoin" - }, "zchfContractAddress": { "value": "0xB58E61C3098d85632Df34EecfB899A1Ed80921cB" }, diff --git a/infrastructure/bicep/parameters/prd.json b/infrastructure/bicep/parameters/prd.json index 33f1b6314b..ebebf2e9f5 100644 --- a/infrastructure/bicep/parameters/prd.json +++ b/infrastructure/bicep/parameters/prd.json @@ -254,9 +254,6 @@ "zchfGraphUrl": { "value": "https://ponder.frankencoin.3dotshub.com" }, - "zchfTvlUrl": { - "value": "https://api.llama.fi/tvl/frankencoin" - }, "zchfContractAddress": { "value": "0xB58E61C3098d85632Df34EecfB899A1Ed80921cB" }, diff --git a/src/config/config.ts b/src/config/config.ts index da9f8be9f3..75018eca9d 100644 --- a/src/config/config.ts +++ b/src/config/config.ts @@ -442,7 +442,6 @@ export class Configuration { zchfGatewayUrl: process.env.ZCHF_GATEWAY_URL, zchfApiKey: process.env.ALCHEMY_API_KEY, zchfGraphUrl: process.env.ZCHF_GRAPH_URL, - zchfTvlUrl: process.env.ZCHF_TVL_URL, contractAddress: { zchf: process.env.ZCHF_CONTRACT_ADDRESS, equity: process.env.ZCHF_EQUITY_CONTRACT_ADDRESS, @@ -455,7 +454,6 @@ export class Configuration { deuroApiKey: process.env.ALCHEMY_API_KEY, deuroChainId: +process.env.DEURO_CHAIN_ID, deuroGraphUrl: process.env.DEURO_GRAPH_URL, - deuroTvlUrl: process.env.DEURO_TVL_URL, }, ebel2x: { contractAddress: process.env.EBEL2X_CONTRACT_ADDRESS, diff --git a/src/integration/blockchain/deuro/deuro-client.ts b/src/integration/blockchain/deuro/deuro-client.ts index 97c475cd93..687b8038e1 100644 --- a/src/integration/blockchain/deuro/deuro-client.ts +++ b/src/integration/blockchain/deuro/deuro-client.ts @@ -13,10 +13,6 @@ export class DEuroClient { this.provider = new ethers.providers.JsonRpcProvider(providerUrl); } - async getTvl(): Promise { - return this.http.get(`${Config.blockchain.deuro.deuroTvlUrl}`); - } - async getPositionV2s(): Promise { const document = gql` { @@ -36,6 +32,8 @@ export class DEuroClient { minted reserveContribution expiration + closed + denied } } } diff --git a/src/integration/blockchain/deuro/deuro.service.ts b/src/integration/blockchain/deuro/deuro.service.ts index 35f495d3ea..bf7f368b5f 100644 --- a/src/integration/blockchain/deuro/deuro.service.ts +++ b/src/integration/blockchain/deuro/deuro.service.ts @@ -13,6 +13,7 @@ import { LogSeverity } from 'src/subdomains/supporting/log/log.entity'; import { LogService } from 'src/subdomains/supporting/log/log.service'; import { PricingService } from 'src/subdomains/supporting/pricing/services/pricing.service'; import { EvmUtil } from '../shared/evm/evm.util'; +import { FrankencoinBasedService } from '../shared/frankencoin/frankencoin-based.service'; import { DEuroClient } from './deuro-client'; import { DEuroInfoDto, @@ -23,7 +24,7 @@ import { } from './dto/deuro.dto'; @Injectable() -export class DEuroService implements OnModuleInit { +export class DEuroService extends FrankencoinBasedService implements OnModuleInit { private readonly logger = new DfxLogger(DEuroService); private static readonly LOG_SYSTEM = 'EvmInformation'; @@ -31,8 +32,6 @@ export class DEuroService implements OnModuleInit { private readonly client: DEuroClient; - private pricingService: PricingService; - private usd: Fiat; private eur: Fiat; @@ -44,6 +43,8 @@ export class DEuroService implements OnModuleInit { private readonly logService: LogService, private readonly fiatService: FiatService, ) { + super(); + const { deuroGatewayUrl, deuroApiKey, deuroChainId } = GetConfig().blockchain.deuro; this.client = new DEuroClient(http, deuroGatewayUrl, deuroApiKey); @@ -51,7 +52,7 @@ export class DEuroService implements OnModuleInit { } async onModuleInit() { - this.pricingService = this.moduleRef.get(PricingService, { strict: false }); + this.setup(this.moduleRef.get(PricingService, { strict: false })); this.usd = await this.fiatService.getFiatByName('USD'); this.eur = await this.fiatService.getFiatByName('EUR'); @@ -163,9 +164,18 @@ export class DEuroService implements OnModuleInit { } async getTvl(): Promise { - // TODO: Frankencoin TVL comes from "https://api.llama.fi/tvl/frankencoin" - // TODO: and DEuro TVL comes from "?????" - return 0; //this.client.getTvl(); + const positionV2s = await this.client.getPositionV2s(); + + const collaterals = positionV2s.map((p) => { + return { + collateral: p.collateral, + collateralSymbol: p.collateralSymbol, + collateralBalance: p.collateralBalance, + collateralDecimals: p.collateralDecimals, + }; + }); + + return this.getTvlByCollaterals(collaterals); } async getDEuroInfo(): Promise { @@ -185,7 +195,7 @@ export class DEuroService implements OnModuleInit { const deuroLog = JSON.parse(maxDEuroLogEntity.message); - const priceUsdToEur = await this.pricingService.getPrice(this.usd, this.eur, true); + const priceUsdToEur = await this.getPrice(this.usd, this.eur); return { totalSupplyDeuro: deuroLog.totalSupply, diff --git a/src/integration/blockchain/deuro/dto/deuro.dto.ts b/src/integration/blockchain/deuro/dto/deuro.dto.ts index b5caf421fc..0c04e6e827 100644 --- a/src/integration/blockchain/deuro/dto/deuro.dto.ts +++ b/src/integration/blockchain/deuro/dto/deuro.dto.ts @@ -1,18 +1,18 @@ -export interface DEuroPositionGraphDto { +import { FrankencoinBasedCollateralDto } from '../../shared/frankencoin/frankencoin-based.dto'; + +export interface DEuroPositionGraphDto extends FrankencoinBasedCollateralDto { id: string; position: string; owner: string; deuro: string; - collateral: string; price: string; - collateralSymbol: string; - collateralBalance: string; - collateralDecimals: number; limitForClones: string; availableForClones: string; minted: string; reserveContribution: number; expiration: string; + closed: boolean; + denied: boolean; } export interface DEuroDepsGraphDto { diff --git a/src/integration/blockchain/frankencoin/dto/frankencoin.dto.ts b/src/integration/blockchain/frankencoin/dto/frankencoin.dto.ts index ba50c66469..8ede41614a 100644 --- a/src/integration/blockchain/frankencoin/dto/frankencoin.dto.ts +++ b/src/integration/blockchain/frankencoin/dto/frankencoin.dto.ts @@ -1,18 +1,18 @@ -export interface FrankencoinPositionGraphDto { +import { FrankencoinBasedCollateralDto } from '../../shared/frankencoin/frankencoin-based.dto'; + +export interface FrankencoinPositionGraphDto extends FrankencoinBasedCollateralDto { id: string; position: string; owner: string; zchf: string; - collateral: string; price: string; - collateralSymbol: string; - collateralBalance: string; - collateralDecimals: number; limitForClones: string; availableForClones: string; minted: string; reserveContribution: number; expiration: string; + closed: boolean; + denied: boolean; } export interface FrankencoinChallengeGraphDto { diff --git a/src/integration/blockchain/frankencoin/frankencoin-client.ts b/src/integration/blockchain/frankencoin/frankencoin-client.ts index 87e681826c..3562863168 100644 --- a/src/integration/blockchain/frankencoin/frankencoin-client.ts +++ b/src/integration/blockchain/frankencoin/frankencoin-client.ts @@ -17,17 +17,13 @@ import { } from './dto/frankencoin.dto'; export class FrankencoinClient { - private provider: ethers.providers.JsonRpcProvider; + private readonly provider: ethers.providers.JsonRpcProvider; constructor(private readonly http: HttpService, gatewayUrl: string, apiKey: string) { const providerUrl = `${gatewayUrl}/${apiKey}`; this.provider = new ethers.providers.JsonRpcProvider(providerUrl); } - async getTvl(): Promise { - return this.http.get(`${Config.blockchain.frankencoin.zchfTvlUrl}`); - } - async getPositionV1s(): Promise { const document = gql` { @@ -47,6 +43,8 @@ export class FrankencoinClient { minted reserveContribution expiration + closed + denied } } } @@ -77,6 +75,8 @@ export class FrankencoinClient { minted reserveContribution expiration + closed + denied } } } diff --git a/src/integration/blockchain/frankencoin/frankencoin.service.ts b/src/integration/blockchain/frankencoin/frankencoin.service.ts index fe5e866b65..cd230f4351 100644 --- a/src/integration/blockchain/frankencoin/frankencoin.service.ts +++ b/src/integration/blockchain/frankencoin/frankencoin.service.ts @@ -13,6 +13,7 @@ import { LogSeverity } from 'src/subdomains/supporting/log/log.entity'; import { LogService } from 'src/subdomains/supporting/log/log.service'; import { PricingService } from 'src/subdomains/supporting/pricing/services/pricing.service'; import { EvmUtil } from '../shared/evm/evm.util'; +import { FrankencoinBasedService } from '../shared/frankencoin/frankencoin-based.service'; import { FrankencoinChallengeGraphDto, FrankencoinDelegationGraphDto, @@ -28,7 +29,7 @@ import { import { FrankencoinClient } from './frankencoin-client'; @Injectable() -export class FrankencoinService implements OnModuleInit { +export class FrankencoinService extends FrankencoinBasedService implements OnModuleInit { private readonly logger = new DfxLogger(FrankencoinService); private static readonly LOG_SYSTEM = 'EvmInformation'; @@ -36,8 +37,6 @@ export class FrankencoinService implements OnModuleInit { private readonly client: FrankencoinClient; - private pricingService: PricingService; - private usd: Fiat; private chf: Fiat; @@ -47,13 +46,15 @@ export class FrankencoinService implements OnModuleInit { private readonly logService: LogService, private readonly fiatService: FiatService, ) { + super(); + const { zchfGatewayUrl, zchfApiKey } = GetConfig().blockchain.frankencoin; this.client = new FrankencoinClient(http, zchfGatewayUrl, zchfApiKey); } async onModuleInit() { - this.pricingService = this.moduleRef.get(PricingService, { strict: false }); + this.setup(this.moduleRef.get(PricingService, { strict: false })); this.usd = await this.fiatService.getFiatByName('USD'); this.chf = await this.fiatService.getFiatByName('CHF'); @@ -216,7 +217,19 @@ export class FrankencoinService implements OnModuleInit { } async getTvl(): Promise { - return this.client.getTvl(); + const positionV1s = await this.client.getPositionV1s(); + const positionV2s = await this.client.getPositionV2s(); + + const collaterals = [...positionV1s, ...positionV2s].map((p) => { + return { + collateral: p.collateral, + collateralSymbol: p.collateralSymbol, + collateralBalance: p.collateralBalance, + collateralDecimals: p.collateralDecimals, + }; + }); + + return this.getTvlByCollaterals(collaterals); } async getFrankencoinInfo(): Promise { @@ -236,7 +249,7 @@ export class FrankencoinService implements OnModuleInit { const frankencoinLog = JSON.parse(maxFrankencoinLogEntity.message); - const priceUsdToChf = await this.pricingService.getPrice(this.usd, this.chf, true); + const priceUsdToChf = await this.getPrice(this.usd, this.chf); return { totalSupplyZchf: frankencoinLog.totalSupply, diff --git a/src/integration/blockchain/shared/frankencoin/frankencoin-based.dto.ts b/src/integration/blockchain/shared/frankencoin/frankencoin-based.dto.ts new file mode 100644 index 0000000000..9cc04d1fab --- /dev/null +++ b/src/integration/blockchain/shared/frankencoin/frankencoin-based.dto.ts @@ -0,0 +1,6 @@ +export interface FrankencoinBasedCollateralDto { + collateral: string; + collateralSymbol: string; + collateralBalance: string; + collateralDecimals: number; +} diff --git a/src/integration/blockchain/shared/frankencoin/frankencoin-based.service.ts b/src/integration/blockchain/shared/frankencoin/frankencoin-based.service.ts new file mode 100644 index 0000000000..6fa75f1f01 --- /dev/null +++ b/src/integration/blockchain/shared/frankencoin/frankencoin-based.service.ts @@ -0,0 +1,49 @@ +import { groupBy, sumBy } from 'lodash'; +import { Fiat } from 'src/shared/models/fiat/fiat.entity'; +import { Price } from 'src/subdomains/supporting/pricing/domain/entities/price'; +import { PriceSource } from 'src/subdomains/supporting/pricing/domain/entities/price-rule.entity'; +import { PricingService } from 'src/subdomains/supporting/pricing/services/pricing.service'; +import { EvmUtil } from '../evm/evm.util'; +import { FrankencoinBasedCollateralDto } from './frankencoin-based.dto'; + +export abstract class FrankencoinBasedService { + private pricingService: PricingService; + + setup(pricingService: PricingService) { + this.pricingService = pricingService; + } + + async getPrice(from: Fiat, to: Fiat): Promise { + return this.pricingService.getPrice(from, to, true); + } + + async getTvlByCollaterals(collaterals: FrankencoinBasedCollateralDto[]): Promise { + const groupedCollaterals = groupBy(collaterals, (i) => i.collateral); + + const collateralsWithTotalBalances = Object.keys(groupedCollaterals).map((key) => { + const first = groupedCollaterals[key][0]; + return { + address: first.collateral, + symbol: first.collateralSymbol, + totalBalance: sumBy(groupedCollaterals[key], (i) => + EvmUtil.fromWeiAmount(i.collateralBalance, i.collateralDecimals), + ), + }; + }); + + let tvl = 0; + + for (const collateralWithTotalBalance of collateralsWithTotalBalances) { + const price = await this.pricingService.getPriceFrom( + PriceSource.COIN_GECKO, + collateralWithTotalBalance.address.toLowerCase(), + 'usd', + 'contract', + ); + + if (price) tvl += collateralWithTotalBalance.totalBalance / price.price; + } + + return tvl; + } +} diff --git a/src/subdomains/supporting/pricing/services/integration/coin-gecko.service.ts b/src/subdomains/supporting/pricing/services/integration/coin-gecko.service.ts index 7ccd2f4228..9bc5bdf657 100644 --- a/src/subdomains/supporting/pricing/services/integration/coin-gecko.service.ts +++ b/src/subdomains/supporting/pricing/services/integration/coin-gecko.service.ts @@ -22,30 +22,45 @@ export class CoinGeckoService extends PricingProvider implements OnModuleInit { void this.client.simpleSupportedCurrencies().then((cs) => (this.currencies = cs)); } - async getPrice(from: string, to: string): Promise { + async getPrice(from: string, to: string, param: string): Promise { + if (param === 'contract') return this.getPriceFromContract(from, to); + + return this.getPriceFromToken(from, to); + } + + private async getPriceFromContract(contractAddress: string, to: string): Promise { + const toCurrency = this.getCurrency(to); + + return this.fetchPriceFromContract(contractAddress, toCurrency); + } + + private async getPriceFromToken(from: string, to: string): Promise { const fromCurrency = this.getCurrency(from); const toCurrency = this.getCurrency(to); if (fromCurrency && toCurrency) { const [priceFrom, priceTo] = await Promise.all([ - this.fetchPrice('tether', fromCurrency), - this.fetchPrice('tether', toCurrency), + this.fetchPriceFromToken('tether', fromCurrency), + this.fetchPriceFromToken('tether', toCurrency), ]); return Price.join(priceFrom.invert(), priceTo); } else if (fromCurrency) { - const price = await this.fetchPrice(to, fromCurrency); + const price = await this.fetchPriceFromToken(to, fromCurrency); return price.invert(); } else if (toCurrency) { - return this.fetchPrice(from, toCurrency); + return this.fetchPriceFromToken(from, toCurrency); } else { - const [priceFrom, priceTo] = await Promise.all([this.fetchPrice(from, 'usd'), this.fetchPrice(to, 'usd')]); + const [priceFrom, priceTo] = await Promise.all([ + this.fetchPriceFromToken(from, 'usd'), + this.fetchPriceFromToken(to, 'usd'), + ]); return Price.join(priceFrom, priceTo.invert()); } } // --- HELPER METHODS --- // - private async fetchPrice(token: string, currency: string): Promise { + private async fetchPriceFromToken(token: string, currency: string): Promise { try { const data = await this.client.simplePrice({ ids: token, vs_currencies: currency }); const price = data[token]?.[currency]; @@ -53,7 +68,27 @@ export class CoinGeckoService extends PricingProvider implements OnModuleInit { return Price.create(token, currency, 1 / price); } catch (e) { - this.logger.error(`Failed to get price for ${token} -> ${currency}:`, e); + this.logger.error(`Failed to get price for token ${token} -> ${currency}:`, e); + throw new ServiceUnavailableException(`Failed to get price`); + } + } + + private async fetchPriceFromContract(contractAddress: string, currency: string): Promise { + try { + const data = await this.client.simpleTokenPrice({ + id: 'ethereum', + contract_addresses: contractAddress, + vs_currencies: currency, + }); + const price = data[contractAddress]?.[currency]; + if (!price) { + this.logger.info(`No price for contract ${contractAddress} -> ${currency}`); + return; + } + + return Price.create(contractAddress, currency, 1 / price); + } catch (e) { + this.logger.error(`Failed to get price for contract ${contractAddress} -> ${currency}:`, e); throw new ServiceUnavailableException(`Failed to get price`); } } From 90e81e2e7a2f73a01597f69d42931e4f7ee5cc2b Mon Sep 17 00:00:00 2001 From: Yannick1712 Date: Tue, 14 Jan 2025 11:17:42 +0100 Subject: [PATCH 12/13] [NOTASK] add migration --- migration/1736848934721-addUserDataWallet.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 migration/1736848934721-addUserDataWallet.js diff --git a/migration/1736848934721-addUserDataWallet.js b/migration/1736848934721-addUserDataWallet.js new file mode 100644 index 0000000000..bad3ca9e85 --- /dev/null +++ b/migration/1736848934721-addUserDataWallet.js @@ -0,0 +1,15 @@ +const { MigrationInterface, QueryRunner } = require("typeorm"); + +module.exports = class addUserDataWallet1736848934721 { + name = 'addUserDataWallet1736848934721' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "dbo"."user_data" ADD "walletId" int`); + await queryRunner.query(`ALTER TABLE "dbo"."user_data" ADD CONSTRAINT "FK_dcf41efbd8bd1f2a80f369028b2" FOREIGN KEY ("walletId") REFERENCES "wallet"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "dbo"."user_data" DROP CONSTRAINT "FK_dcf41efbd8bd1f2a80f369028b2"`); + await queryRunner.query(`ALTER TABLE "dbo"."user_data" DROP COLUMN "walletId"`); + } +} From a1e7b2eb0c915aeaf606a0554e435fcfeddff64f Mon Sep 17 00:00:00 2001 From: David May Date: Tue, 14 Jan 2025 11:48:26 +0100 Subject: [PATCH 13/13] [NO-TASK] Refactoring --- .../core/buy-crypto/process/entities/buy-crypto.entity.ts | 2 +- src/subdomains/core/sell-crypto/process/buy-fiat.entity.ts | 2 +- src/subdomains/generic/admin/admin.service.ts | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/subdomains/core/buy-crypto/process/entities/buy-crypto.entity.ts b/src/subdomains/core/buy-crypto/process/entities/buy-crypto.entity.ts index d0297792d5..6ed3769a7d 100644 --- a/src/subdomains/core/buy-crypto/process/entities/buy-crypto.entity.ts +++ b/src/subdomains/core/buy-crypto/process/entities/buy-crypto.entity.ts @@ -162,7 +162,7 @@ export class BuyCrypto extends IEntity { inputReferenceAmountMinusFee?: number; @Column({ type: 'float', nullable: true }) - blockchainFee?: number; + blockchainFee?: number; //inputReferenceAsset @Column({ type: 'float', nullable: true }) paymentLinkFee?: number; diff --git a/src/subdomains/core/sell-crypto/process/buy-fiat.entity.ts b/src/subdomains/core/sell-crypto/process/buy-fiat.entity.ts index 7353a3a683..1365d8ef38 100644 --- a/src/subdomains/core/sell-crypto/process/buy-fiat.entity.ts +++ b/src/subdomains/core/sell-crypto/process/buy-fiat.entity.ts @@ -129,7 +129,7 @@ export class BuyFiat extends IEntity { totalFeeAmountChf?: number; @Column({ type: 'float', nullable: true }) - blockchainFee?: number; + blockchainFee?: number; //inputAsset @Column({ type: 'float', nullable: true }) paymentLinkFee?: number; diff --git a/src/subdomains/generic/admin/admin.service.ts b/src/subdomains/generic/admin/admin.service.ts index acf6bbc3a8..913e9a7168 100644 --- a/src/subdomains/generic/admin/admin.service.ts +++ b/src/subdomains/generic/admin/admin.service.ts @@ -60,10 +60,11 @@ export class AdminService { } } - @Cron(CronExpression.EVERY_5_MINUTES) + @Cron(CronExpression.EVERY_MINUTE) @Lock(3600) async completeLiquidityOrders() { - if (DisabledProcess(Process.LIQUIDITY_MANAGEMENT)) return; + if (DisabledProcess(Process.PAY_OUT)) return; + for (const context of Object.values(PayoutRequestContext)) { const lContext = context as unknown as LiquidityOrderContext; const pContext = context as unknown as PayoutOrderContext;