diff --git a/package-lock.json b/package-lock.json index 9d87fc27..9a694b04 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,7 +30,9 @@ "gpt-tokenizer": "^2.1.1", "grammy": "^1.17.1", "jsqr": "^1.4.0", + "keccak": "^3.0.4", "litllm": "^3.0.0", + "lodash": "^4.17.21", "lokijs": "^1.5.12", "lru-cache": "^10.0.0", "moment": "^2.29.4", @@ -61,6 +63,8 @@ "@sentry/cli": "^2.20.7", "@types/express": "^4.17.14", "@types/jest": "^29.5.4", + "@types/keccak": "^3.0.2", + "@types/lodash": "^4.14.199", "@types/node": "^18.15.11", "@types/node-cron": "^3.0.8", "@types/node-fetch": "^2.6.2", @@ -76,6 +80,9 @@ "eslint-config-prettier": "^8.8.0", "eslint-config-standard-with-typescript": "^39.0.0", "eslint-plugin-compat": "^4.2.0", + "eslint-plugin-import": "^2.28.1", + "eslint-plugin-n": "^16.1.0", + "eslint-plugin-promise": "^6.1.1", "husky": "^8.0.3", "jest": "^29.6.4", "prettier": "2.8.7", @@ -4236,8 +4243,16 @@ "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "node_modules/@types/keccak": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/keccak/-/keccak-3.0.2.tgz", + "integrity": "sha512-3u0Se8xZ2If2vw1sCMD5668OKI3kInSV4hYw3kclr4I+/v/IBgSV4SDA2VtJHnNSNaZsfhZ7HEfDrPlant8mgg==", "dev": true, - "peer": true + "dependencies": { + "@types/node": "*" + } }, "node_modules/@types/keyv": { "version": "3.1.4", @@ -4247,6 +4262,12 @@ "@types/node": "*" } }, + "node_modules/@types/lodash": { + "version": "4.14.199", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.199.tgz", + "integrity": "sha512-Vrjz5N5Ia4SEzWWgIVwnHNEnb1UE1XMkvY5DGXrAeOGE9imk0hgTHh5GyDjLDJi9OTCn9oo9dXH1uToK1VRfrg==", + "dev": true + }, "node_modules/@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", @@ -5242,7 +5263,6 @@ "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", "dev": true, - "peer": true, "dependencies": { "call-bind": "^1.0.2", "is-array-buffer": "^3.0.1" @@ -5261,7 +5281,6 @@ "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", "dev": true, - "peer": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -5290,7 +5309,6 @@ "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz", "integrity": "sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==", "dev": true, - "peer": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -5310,7 +5328,6 @@ "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", "dev": true, - "peer": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -5329,7 +5346,6 @@ "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", "dev": true, - "peer": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -5348,7 +5364,6 @@ "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", "dev": true, - "peer": true, "dependencies": { "array-buffer-byte-length": "^1.0.0", "call-bind": "^1.0.2", @@ -5909,7 +5924,6 @@ "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", "dev": true, - "peer": true, "dependencies": { "semver": "^7.0.0" } @@ -7118,7 +7132,6 @@ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", "dev": true, - "peer": true, "dependencies": { "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" @@ -7485,7 +7498,6 @@ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.1.tgz", "integrity": "sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw==", "dev": true, - "peer": true, "dependencies": { "array-buffer-byte-length": "^1.0.0", "arraybuffer.prototype.slice": "^1.0.1", @@ -7539,7 +7551,6 @@ "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", "dev": true, - "peer": true, "dependencies": { "get-intrinsic": "^1.1.3", "has": "^1.0.3", @@ -7554,7 +7565,6 @@ "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", "dev": true, - "peer": true, "dependencies": { "has": "^1.0.3" } @@ -7564,7 +7574,6 @@ "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", "dev": true, - "peer": true, "dependencies": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -7758,7 +7767,6 @@ "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", "dev": true, - "peer": true, "dependencies": { "debug": "^3.2.7", "is-core-module": "^2.13.0", @@ -7770,7 +7778,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, - "peer": true, "dependencies": { "ms": "^2.1.1" } @@ -7780,7 +7787,6 @@ "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", "dev": true, - "peer": true, "dependencies": { "debug": "^3.2.7" }, @@ -7798,7 +7804,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, - "peer": true, "dependencies": { "ms": "^2.1.1" } @@ -7829,7 +7834,6 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.2.0.tgz", "integrity": "sha512-9dvv5CcvNjSJPqnS5uZkqb3xmbeqRLnvXKK7iI5+oK/yTusyc46zbBZKENGsOfojm/mKfszyZb+wNqNPAPeGXA==", "dev": true, - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.1.2", "@eslint-community/regexpp": "^4.6.0" @@ -7849,7 +7853,6 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.28.1.tgz", "integrity": "sha512-9I9hFlITvOV55alzoKBI+K9q74kv0iKMeY6av5+umsNwayt59fz692daGyjR+oStBQgx6nwR9rXldDev3Clw+A==", "dev": true, - "peer": true, "dependencies": { "array-includes": "^3.1.6", "array.prototype.findlastindex": "^1.2.2", @@ -7881,7 +7884,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, - "peer": true, "dependencies": { "ms": "^2.1.1" } @@ -7891,7 +7893,6 @@ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, - "peer": true, "dependencies": { "esutils": "^2.0.2" }, @@ -7904,7 +7905,6 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "peer": true, "bin": { "semver": "bin/semver.js" } @@ -7914,7 +7914,6 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-16.1.0.tgz", "integrity": "sha512-3wv/TooBst0N4ND+pnvffHuz9gNPmk/NkLwAxOt2JykTl/hcuECe6yhTtLJcZjIxtZwN+GX92ACp/QTLpHA3Hg==", "dev": true, - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "builtins": "^5.0.1", @@ -7941,7 +7940,6 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz", "integrity": "sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==", "dev": true, - "peer": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -8712,7 +8710,6 @@ "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", "dev": true, - "peer": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -8731,7 +8728,6 @@ "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true, - "peer": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -8810,7 +8806,6 @@ "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", "dev": true, - "peer": true, "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.1" @@ -8827,7 +8822,6 @@ "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.0.tgz", "integrity": "sha512-pmjiZ7xtB8URYm74PlGJozDNyhvsVLUcpBa8DZBG3bWHwaHa9bPiRpiSfovw+fjhwONSCWKRyk+JQHEGZmMrzw==", "dev": true, - "peer": true, "dependencies": { "resolve-pkg-maps": "^1.0.0" }, @@ -8908,7 +8902,6 @@ "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", "dev": true, - "peer": true, "dependencies": { "define-properties": "^1.1.3" }, @@ -9046,7 +9039,6 @@ "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", "dev": true, - "peer": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -9064,7 +9056,6 @@ "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", "dev": true, - "peer": true, "dependencies": { "get-intrinsic": "^1.1.1" }, @@ -9472,7 +9463,6 @@ "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", "dev": true, - "peer": true, "dependencies": { "get-intrinsic": "^1.2.0", "has": "^1.0.3", @@ -9515,7 +9505,6 @@ "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", "dev": true, - "peer": true, "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.2.0", @@ -9535,7 +9524,6 @@ "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", "dev": true, - "peer": true, "dependencies": { "has-bigints": "^1.0.1" }, @@ -9560,7 +9548,6 @@ "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", "dev": true, - "peer": true, "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -9605,7 +9592,6 @@ "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", "dev": true, - "peer": true, "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -9692,7 +9678,6 @@ "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", "dev": true, - "peer": true, "engines": { "node": ">= 0.4" }, @@ -9714,7 +9699,6 @@ "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", "dev": true, - "peer": true, "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -9739,7 +9723,6 @@ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", "dev": true, - "peer": true, "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -9756,7 +9739,6 @@ "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", "dev": true, - "peer": true, "dependencies": { "call-bind": "^1.0.2" }, @@ -9781,7 +9763,6 @@ "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", "dev": true, - "peer": true, "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -9797,7 +9778,6 @@ "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", "dev": true, - "peer": true, "dependencies": { "has-symbols": "^1.0.2" }, @@ -9832,7 +9812,6 @@ "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", "dev": true, - "peer": true, "dependencies": { "call-bind": "^1.0.2" }, @@ -9844,8 +9823,7 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true, - "peer": true + "dev": true }, "node_modules/isexe": { "version": "2.0.0", @@ -10718,9 +10696,9 @@ } }, "node_modules/keccak": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.3.tgz", - "integrity": "sha512-JZrLIAJWuZxKbCilMpNz5Vj7Vtb4scDG3dMXLOsbzBmQGyjwE61BbW7bJkfKKCShXiQZt3T6sBgALRtmd+nZaQ==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.4.tgz", + "integrity": "sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==", "hasInstallScript": true, "dependencies": { "node-addon-api": "^2.0.0", @@ -11746,7 +11724,6 @@ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true, - "peer": true, "engines": { "node": ">= 0.4" } @@ -11756,7 +11733,6 @@ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", "dev": true, - "peer": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -11775,7 +11751,6 @@ "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", "dev": true, - "peer": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -11793,7 +11768,6 @@ "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.1.tgz", "integrity": "sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==", "dev": true, - "peer": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -11806,7 +11780,6 @@ "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", "dev": true, - "peer": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -12931,7 +12904,6 @@ "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", "dev": true, - "peer": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -13124,7 +13096,6 @@ "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", "dev": true, - "peer": true, "funding": { "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } @@ -13247,7 +13218,6 @@ "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==", "dev": true, - "peer": true, "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.2.1", @@ -13290,7 +13260,6 @@ "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", "dev": true, - "peer": true, "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.3", @@ -13832,7 +13801,6 @@ "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", "dev": true, - "peer": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -13850,7 +13818,6 @@ "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", "dev": true, - "peer": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -13865,7 +13832,6 @@ "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", "dev": true, - "peer": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -14476,7 +14442,6 @@ "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", "dev": true, - "peer": true, "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.2", @@ -14489,7 +14454,6 @@ "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, - "peer": true, "dependencies": { "minimist": "^1.2.0" }, @@ -14582,7 +14546,6 @@ "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", "dev": true, - "peer": true, "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.2.1", @@ -14597,7 +14560,6 @@ "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", "dev": true, - "peer": true, "dependencies": { "call-bind": "^1.0.2", "for-each": "^0.3.3", @@ -14616,7 +14578,6 @@ "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", "dev": true, - "peer": true, "dependencies": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", @@ -14636,7 +14597,6 @@ "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", "dev": true, - "peer": true, "dependencies": { "call-bind": "^1.0.2", "for-each": "^0.3.3", @@ -14926,7 +14886,6 @@ "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", "dev": true, - "peer": true, "dependencies": { "call-bind": "^1.0.2", "has-bigints": "^1.0.2", @@ -15879,7 +15838,6 @@ "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", "dev": true, - "peer": true, "dependencies": { "is-bigint": "^1.0.1", "is-boolean-object": "^1.1.0", diff --git a/package.json b/package.json index 1789c438..c920702f 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,8 @@ "@sentry/cli": "^2.20.7", "@types/express": "^4.17.14", "@types/jest": "^29.5.4", + "@types/keccak": "^3.0.2", + "@types/lodash": "^4.14.199", "@types/node": "^18.15.11", "@types/node-cron": "^3.0.8", "@types/node-fetch": "^2.6.2", @@ -94,7 +96,9 @@ "gpt-tokenizer": "^2.1.1", "grammy": "^1.17.1", "jsqr": "^1.4.0", + "keccak": "^3.0.4", "litllm": "^3.0.0", + "lodash": "^4.17.21", "lokijs": "^1.5.12", "lru-cache": "^10.0.0", "moment": "^2.29.4", diff --git a/src/config.ts b/src/config.ts index ee677d2e..99dbbdd5 100644 --- a/src/config.ts +++ b/src/config.ts @@ -92,7 +92,30 @@ export default { : ['metamask', 'walletconnect'], registerPrefix: process.env.COUNTRY_PREFIX ? process.env.COUNTRY_PREFIX.split(',') - : ['+', '%'] + : ['+', '%'], + nameWrapperContract: + process.env.NAME_WRAPPER_CONTRACT ?? + '0x4Cd2563118e57B19179d8DC033f2B0C5B5D69ff5', + domainNftImagesPath: + 'https://storage.googleapis.com/radical-domain-nft-images', + domainMetadataPath: 'https://storage.googleapis.com/radical-domain-metadata', + domain: { + tiers: { + LEGENDARY: Number(process.env.TIER_LEGENDARY) || 1, + SUPER_RARE: Number(process.env.TIER_SUPER_RARE) || 6, + RARE: Number(process.env.TIER_RARE) || 9, + COMMON: Number(process.env.TIER_COMMON) || 10 + }, + reserved: Number(process.env.DOMAIN_RESERVED_LENGTH) || 6 + }, + explorer: { + explorerUrl: + process.env.EXPLORER_URL ?? 'https://explorer.harmony.one/#/tx/', + address: 'https://explorer.harmony.one/address/', + tx: 'https://explorer.harmony.one/tx/', + block: 'https://explorer.harmony.one/block/', + erc1155: 'https://explorer.harmony.one/inventory/erc1155/' + } }, voiceMemo: { isEnabled: Boolean(parseInt(process.env.VOICE_MEMO_ENABLED ?? '1')), diff --git a/src/modules/1country/api/countryUtils.ts b/src/modules/1country/api/countryUtils.ts new file mode 100644 index 00000000..639f4e3b --- /dev/null +++ b/src/modules/1country/api/countryUtils.ts @@ -0,0 +1,238 @@ +import * as ethers from 'ethers' +import { toBigInt } from 'web3-utils' +import createKeccakHash from 'keccak' +import axios from 'axios' +import _ from 'lodash' + +import { buildERC1155Uri } from './explorer' +import config from '../../../config' + +const SPECIAL_NAMES = ['0', '1'] +// prettier-ignore + +const RESERVED_NAMES = [ + ...SPECIAL_NAMES +] + +const isRestricted = (name: string): boolean => { + const phrases = config.country.restrictedPhrases + for (let i = 0; i < phrases.length; i++) { + if (name.includes(phrases[i])) return true + } + return false +} + +export const nameUtils = { + RESTRICTED_VALID_NAME: /[a-z0-9]+/, + VALID_NAME: /^[a-zA-Z0-9]{1,}((?!-)[a-zA-Z0-9]{0,}|-[a-zA-Z0-9]{1,})+$/, + SPECIAL_NAMES: ['0', '1'], + + isValidName: (name: string): boolean => { + return nameUtils.VALID_NAME.test(name) + }, + isValidLength: (name: string): boolean => { + return name.length < 64 + }, + isTaken: (name: string): boolean => { + return RESERVED_NAMES.includes(name) + }, + isRestricted: (name: string): boolean => { + return isRestricted(name) + }, + isReservedName: (name: string): boolean => { + return false + // name.length <= config.domain.reserved + } +} + +export const countryUtils = { + hexView: (bytes: Uint8Array) => { + return ( + bytes && + Array.from(bytes) + .map((x) => x.toString(16).padStart(2, '0')) + .join('') + ) + }, + + hexString: (bytes: Uint8Array) => { + return '0x' + countryUtils.hexView(bytes) + }, + + keccak: (bytes: Uint8Array | string) => { + const k = createKeccakHash('keccak256') + // assume Buffer is poly-filled or loaded from https://github.com/feross/buffer + const hash = k.update(Buffer.from(bytes)).digest() + return new Uint8Array(hash) + }, + + stringToBytes: (str: string) => { + return new TextEncoder().encode(str) + }, + + keccak256: (str: string, use0x: boolean) => { + const bytes = countryUtils.stringToBytes(str) + const hash = countryUtils.keccak(bytes) + return use0x ? countryUtils.hexString(hash) : countryUtils.hexView(hash) + }, + + namehash: (name: string) => { + const parts = name.split('.') + const empty = new Uint8Array(32) + if (!name) { + return empty + } + let hash = empty + for (let i = parts.length - 1; i >= 0; i--) { + const joined = new Uint8Array(64) + joined.set(hash) + joined.set(countryUtils.keccak(parts[i]), 32) + hash = countryUtils.keccak(joined) + } + return hash + }, + + buildTokenId: (domainName: string) => { + return toBigInt(countryUtils.hexString(countryUtils.namehash(domainName))).toString() + }, + + buildDomainExplorerURI: (domainName: string) => { + return buildERC1155Uri( + config.country.nameWrapperContract, + countryUtils.buildTokenId(domainName) + ) + }, + + buildDomainImageURI: (domainName: string): string => { + return `${config.country.domainNftImagesPath}/${domainName}.png` + }, + + buildMetadataURI: (domain: string): string => { + const name = domain.split('.country')[0] + const id = toBigInt( + ethers.utils.keccak256(ethers.utils.toUtf8Bytes(name)) + ).toString() // BigInt(w3utils.keccak256(name, true)).toString() + return `${config.country.domainMetadataPath}/erc721/${id}` + }, + + getMetadata: async (metadataUri: string): Promise => { + const { data } = await axios.get(metadataUri) + const { name, image, attributes } = data + if (attributes) { + const attr = attributes.reduce( + ( + acc: Record, + obj: { trait_type: string, value: any } + ) => { + acc[_.camelCase(obj.trait_type)] = obj.value + return acc + }, + {} + ) + return { + name, + image, + ...attr + } + } + return null + } +} + +export type DomainLevel = + | 'reserved' + | 'legendary' + | 'super_rare' + | 'rare' + | 'common' +export const getDomainLevel = (domainName: string): DomainLevel => { + const len = domainName.length + + // if (len === 1) { + // return 'reserved' + // } + + if (len <= config.country.domain.tiers.LEGENDARY) { + // (len === 1 || len === 2 || len === 3) { + return 'legendary' + } + + if (len <= config.country.domain.tiers.SUPER_RARE) { + return 'super_rare' + } + + if (len <= config.country.domain.tiers.RARE) { + return 'rare' + } + + return 'common' +} + +type ValidateDomainNameResult = { valid: false, error: string } | { valid: true, error: '' } + +export const validateDomainName = (domainName: string): ValidateDomainNameResult => { + if (!nameUtils.isValidName(domainName.toLowerCase())) { + return { + valid: false, + error: 'Domains can use a mix of letters and numbers' // Domains can use a mix of letters and numbers + } + } + if (!nameUtils.isValidLength(domainName)) { + return { + valid: false, + error: 'Domains must be under 64 characters long' + } + } + if (nameUtils.isTaken(domainName.toLowerCase())) { + return { + valid: false, + error: 'This domain name is reserved for special purpose' + } + } + if (nameUtils.isRestricted(domainName.toLocaleLowerCase())) { + return { + valid: false, + error: `${domainName} contains a restricted phrase and can't be registered` + } + } + if (nameUtils.isReservedName(domainName.toLowerCase())) { + return { + valid: false, + error: `1 to ${config.country.domain.reserved} letter domains will be available soon` // 'Available Soon', + } + } + return { + valid: true, + error: '' + } +} + +export const daysBetween = ( + date1: string | number, + date2: string | number +): number => { + const DAY_MILLISECONDS = 1000 * 60 * 60 * 24 + return (Number(date2) - Number(date1)) / DAY_MILLISECONDS +} + +export const getDaysFromTimestamp = (time: number): number => { + const DAY_MILLISECONDS = 1000 * 60 * 60 * 24 + return time / DAY_MILLISECONDS +} + +export const getEthersError = (error: Error): string => { + // @ts-expect-error TS2339: Property 'reason' does not exist on type 'Error'. + const message = error.reason ? error.reason : error.message + + if (message) { + return message + } + + return '' +} + +export const getUnwrappedTokenId = (sld: string): string => + ethers.utils.keccak256(ethers.utils.toUtf8Bytes(sld)) + +export const getWrappedTokenId = (sld: string): string => + ethers.utils.namehash(`${sld}${config.country.tld}`) diff --git a/src/modules/1country/api/d1dc.ts b/src/modules/1country/api/d1dc.ts index fc1a5901..627ce295 100644 --- a/src/modules/1country/api/d1dc.ts +++ b/src/modules/1country/api/d1dc.ts @@ -1,11 +1,52 @@ import { ethers } from 'ethers' -// import web3Utils from 'web3-utils' import Web3 from 'web3' import pino, { type Logger } from 'pino' -// import bn, { BigNumber } from 'bignumber.js' - import DCv2Abi from '../contracts/DCv2' import config from '../../../config' +import type { TransactionReceipt, TransactionResponse } from '@ethersproject/abstract-provider' +import { countryUtils } from './countryUtils' +import type { Account } from 'web3-core' +import type { ErrorCode } from '@ethersproject/logger' + +interface DCError extends Error { + reason: string + code: ErrorCode +} + +export interface CallbackProps { + onTransactionHash?: (txHash: string) => void + onFailed?: (error: Error | unknown, flag?: boolean) => void + onSuccess?: (tx: TransactionReceipt) => void +} + +export interface SendProps extends CallbackProps { + account: Account + amount?: string + methodName: string + parameters: unknown[] +} + +export type SendResult = { + txReceipt: TransactionReceipt + error: null // Error +} | { + txReceipt: null + error: DCError // Error +} + +interface CommitProps extends CallbackProps { + name: string + secret: string + account: Account +} + +interface RentProps extends CallbackProps { + name: string + owner: string + secret: string + amount: string + account: Account +} export interface DomainRecord { renter: string @@ -37,7 +78,7 @@ const defaultProvider = new ethers.providers.JsonRpcProvider( const EmptyAddress = '0x0000000000000000000000000000000000000000' -class DcClient { +export class DcClient { private readonly logger: Logger private readonly provider: | ethers.providers.Web3Provider @@ -133,6 +174,90 @@ class DcClient { const isAvailable = await this.contractReadOnly.available(name) return isAvailable?.toString()?.toLowerCase() === 'true' } + + async rent ({ + account, + name, + owner, + secret, + amount, + onFailed, + onSuccess, + onTransactionHash + }: RentProps): Promise { + const secretHash = countryUtils.keccak256(secret, true) + return await this.send({ + account, + amount, + parameters: [name, owner, secretHash], + methodName: 'register', + onFailed, + onSuccess, + onTransactionHash + }) + } + + async commit ({ + account, + name, + secret, + onFailed, + onSuccess, + onTransactionHash + }: CommitProps): Promise { + const wallet = new ethers.Wallet(account) + + const secretHash = countryUtils.keccak256(secret, true) + const commitment = await this.contractReadOnly.makeCommitment( + name, + wallet.address, + secretHash + ) + return await this.send({ + account, + onFailed, + onSuccess, + onTransactionHash, + methodName: 'commit', + parameters: [commitment] + }) + } + + async send ({ + amount, + account, + onFailed, + onTransactionHash = () => {}, + onSuccess, + methodName, + parameters + }: SendProps): Promise { + const wallet = new ethers.Wallet(account, defaultProvider) + const contract = this.contractReadOnly.connect(wallet) + + // const gasLimit = await contract.estimateGas[methodName](...parameters) + // console.log('### functionGasFees', gasLimit.toString()) + // const feeData = await defaultProvider.getFeeData() + + // const txGasPrice = gas.mul(feeData.gasPrice) + + try { + console.log('send', amount, parameters) + const txResponse = (await contract[methodName](...parameters, { + value: amount + // gasPrice: feeData.gasPrice, + // gasLimit: ethers.utils.hexlify(300000) + })) as TransactionResponse + onTransactionHash(txResponse.hash) + + const txReceipt = await txResponse.wait() + onSuccess?.(txReceipt) + return { txReceipt, error: null } + } catch (ex) { + onFailed?.(ex, true) + return { txReceipt: null, error: ex as DCError } + } + } } export const dcClient = new DcClient({ provider: defaultProvider }) diff --git a/src/modules/1country/api/explorer.ts b/src/modules/1country/api/explorer.ts new file mode 100644 index 00000000..1ee7a2e4 --- /dev/null +++ b/src/modules/1country/api/explorer.ts @@ -0,0 +1,11 @@ +import config from '../../../config' + +export const buildTxUri = (txHash: string): string => { + return config.country.explorer.tx + txHash +} +export const buildERC1155Uri = ( + contractAddress: string, + tokenId: string | number +): string => { + return `${config.country.explorer.erc1155}${contractAddress}/${tokenId}` +} diff --git a/src/modules/1country/api/relayApi.ts b/src/modules/1country/api/relayApi.ts index e77ba9c2..b15e3aaa 100644 --- a/src/modules/1country/api/relayApi.ts +++ b/src/modules/1country/api/relayApi.ts @@ -7,15 +7,35 @@ const base = axios.create({ timeout: 10000 }) +export type CheckDomainResult = { + isAvailable: any + renewPrice: any + responseText: any + isReserved: any + isRegistered: any + error: string + regPrice: any + restorePrice: any + transferPrice: any } | { error: string } export const relayApi = (): { enableSubdomains: (domainName: string) => Promise - checkDomain: ({ sld }: { sld: string }) => Promise<{ isAvailable: any, renewPrice: any, responseText: any, isReserved: any, isRegistered: any, error: string, regPrice: any, restorePrice: any, transferPrice: any } | { error: string }> + checkDomain: ({ sld }: { sld: string }) => Promise createCert: ({ domain, address, async }: { domain: string, address?: string, async?: boolean }) => Promise<{ success: any, sld: any, nakedJobId: any, error: any, mcJobId: any }> genNFT: ({ domain }: { domain: string }) => Promise<{ metadata: any, generated: any }> + purchaseDomain: (params: { + domain: string + txHash: string + address: string + }) => Promise<{ success: any + domainCreationDate: any + domainExpiryDate: any + traceId: any + reqTime: any + responseText: any }> } => { return { enableSubdomains: async (domainName: string) => { @@ -76,6 +96,26 @@ export const relayApi = (): { nakedJobId, error } + }, + purchaseDomain: async ({ domain, txHash, address }) => { + const { + data: { + success, + domainCreationDate, + domainExpiryDate, + traceId, + reqTime, + responseText + } + } = await base.post('/purchase', { domain, txHash, address, fast: 1 }) + return { + success, + domainCreationDate, + domainExpiryDate, + traceId, + reqTime, + responseText + } } } } diff --git a/src/modules/1country/api/reservedDomains.ts b/src/modules/1country/api/reservedDomains.ts new file mode 100644 index 00000000..09d9cb74 --- /dev/null +++ b/src/modules/1country/api/reservedDomains.ts @@ -0,0 +1,1498 @@ +export const RESERVED_DOMAINS = [ + '10k', + '1st', + '2nd', + '3rd', + '3x3', + '4th', + '5th', + '5x5', + '6th', + '7th', + '8th', + '9th', + 'aah', + 'aal', + 'aas', + 'aba', + 'abd', + 'abe', + 'abo', + 'abs', + 'abt', + 'abu', + 'abv', + 'aby', + 'ace', + 'ach', + 'act', + 'add', + 'ade', + 'adl', + 'adm', + 'ado', + 'adz', + 'aed', + 'aff', + 'afk', + 'aft', + 'aga', + 'age', + 'ago', + 'agp', + 'ags', + 'aha', + 'ahi', + 'ahs', + 'aid', + 'ail', + 'aim', + 'ain', + 'ais', + 'ait', + 'aja', + 'aji', + 'ala', + 'alb', + 'ale', + 'alf', + 'ali', + 'alp', + 'als', + 'alt', + 'ama', + 'ami', + 'amp', + 'amu', + 'amy', + 'ana', + 'and', + 'ane', + 'anh', + 'ani', + 'ann', + 'ant', + 'any', + 'apl', + 'apo', + 'app', + 'apr', + 'apt', + 'ara', + 'arc', + 'are', + 'arf', + 'ark', + 'arm', + 'arp', + 'ars', + 'asa', + 'ash', + 'ask', + 'aso', + 'asp', + 'asr', + 'ass', + 'ate', + 'atm', + 'atp', + 'att', + 'atv', + 'atx', + 'aud', + 'auk', + 'aul', + 'ava', + 'ave', + 'avi', + 'avm', + 'avo', + 'awa', + 'awe', + 'awk', + 'awl', + 'awn', + 'axe', + 'axs', + 'aye', + 'ayi', + 'ayr', + 'ays', + 'ayu', + 'aza', + 'azo', + 'baa', + 'bag', + 'bah', + 'bai', + 'bal', + 'bam', + 'ban', + 'bao', + 'bap', + 'bar', + 'bas', + 'bat', + 'bay', + 'baz', + 'bbc', + 'bbg', + 'bbj', + 'bbq', + 'bbs', + 'bbw', + 'bea', + 'bed', + 'bee', + 'beg', + 'bel', + 'ben', + 'bes', + 'bet', + 'bev', + 'bey', + 'bff', + 'bgg', + 'bib', + 'bid', + 'bil', + 'bin', + 'bio', + 'bis', + 'biz', + 'bls', + 'bmi', + 'bmp', + 'bmr', + 'bmx', + 'boa', + 'bob', + 'bod', + 'bog', + 'bok', + 'bon', + 'boo', + 'bop', + 'bor', + 'bos', + 'bow', + 'box', + 'boy', + 'bra', + 'brb', + 'bro', + 'brr', + 'bru', + 'btw', + 'bub', + 'bud', + 'bug', + 'bum', + 'bun', + 'bur', + 'bus', + 'but', + 'bux', + 'bye', + 'byk', + 'bys', + 'c60', + 'cab', + 'cad', + 'cal', + 'cam', + 'can', + 'cap', + 'cat', + 'caw', + 'cay', + 'cba', + 'cbj', + 'cbn', + 'ccv', + 'cdc', + 'cdn', + 'cdr', + 'cds', + 'cee', + 'cel', + 'ceo', + 'cep', + 'cfo', + 'cfs', + 'cga', + 'cgi', + 'cgo', + 'cha', + 'chi', + 'chu', + 'cif', + 'cig', + 'cil', + 'cim', + 'cio', + 'cis', + 'clu', + 'cms', + 'cob', + 'cod', + 'cof', + 'cog', + 'col', + 'con', + 'coo', + 'cop', + 'coq', + 'cor', + 'cos', + 'cot', + 'cow', + 'cox', + 'coy', + 'coz', + 'cpa', + 'cpc', + 'cpm', + 'cpr', + 'cps', + 'cpu', + 'crm', + 'cru', + 'cry', + 'css', + 'ctr', + 'cua', + 'cub', + 'cuc', + 'cud', + 'cue', + 'cum', + 'cup', + 'cur', + 'cut', + 'cvt', + 'cwm', + 'dab', + 'dad', + 'dag', + 'dah', + 'dak', + 'dal', + 'dam', + 'dan', + 'dap', + 'das', + 'daw', + 'day', + 'dcl', + 'ddf', + 'dds', + 'deb', + 'dee', + 'def', + 'del', + 'den', + 'dev', + 'dew', + 'dex', + 'dey', + 'dfk', + 'dia', + 'dib', + 'did', + 'die', + 'dif', + 'dig', + 'dim', + 'din', + 'dip', + 'dis', + 'dit', + 'div', + 'diy', + 'dna', + 'dnr', + 'dns', + 'dnw', + 'doc', + 'doe', + 'dog', + 'doi', + 'dol', + 'dom', + 'don', + 'dor', + 'dos', + 'dot', + 'dow', + 'dpi', + 'dry', + 'dsp', + 'dtf', + 'dtp', + 'dua', + 'dub', + 'dud', + 'due', + 'dug', + 'duh', + 'dui', + 'dun', + 'duo', + 'dup', + 'dvd', + 'dvi', + 'dvr', + 'dye', + 'ear', + 'eat', + 'eau', + 'ebb', + 'ebi', + 'ecg', + 'eco', + 'ecu', + 'eda', + 'ede', + 'edh', + 'eds', + 'eek', + 'eel', + 'eff', + 'efs', + 'eft', + 'egg', + 'egl', + 'ego', + 'egr', + 'eid', + 'eir', + 'eke', + 'ela', + 'eld', + 'elf', + 'eli', + 'elk', + 'ell', + 'elm', + 'els', + 'ely', + 'ema', + 'eme', + 'ems', + 'emu', + 'ena', + 'end', + 'eng', + 'ens', + 'eon', + 'era', + 'ere', + 'erg', + 'ern', + 'err', + 'ers', + 'esb', + 'ese', + 'esl', + 'esp', + 'ess', + 'est', + 'eta', + 'etf', + 'eun', + 'eva', + 'eve', + 'ewa', + 'ewe', + 'eye', + 'fab', + 'fad', + 'fae', + 'fag', + 'fan', + 'far', + 'fas', + 'fat', + 'fax', + 'fay', + 'fed', + 'fee', + 'feh', + 'fem', + 'fen', + 'fer', + 'fes', + 'fet', + 'feu', + 'few', + 'fey', + 'fez', + 'ffm', + 'fib', + 'fid', + 'fie', + 'fig', + 'fil', + 'fin', + 'fir', + 'fis', + 'fit', + 'fix', + 'fiz', + 'flo', + 'flu', + 'fly', + 'fml', + 'fob', + 'foe', + 'fog', + 'foh', + 'fon', + 'foo', + 'fop', + 'fou', + 'fox', + 'foy', + 'fro', + 'fry', + 'ftp', + 'ftw', + 'fub', + 'fud', + 'fug', + 'fur', + 'fut', + 'fwb', + 'fyi', + 'gab', + 'gac', + 'gad', + 'gae', + 'gag', + 'gal', + 'gam', + 'gan', + 'gap', + 'gar', + 'gas', + 'gat', + 'geb', + 'ged', + 'gee', + 'gel', + 'gem', + 'gen', + 'get', + 'gey', + 'gfe', + 'ghi', + 'gia', + 'gib', + 'gid', + 'gie', + 'gif', + 'gig', + 'gil', + 'gin', + 'gip', + 'git', + 'gna', + 'gnu', + 'goa', + 'gob', + 'god', + 'goo', + 'gor', + 'gos', + 'got', + 'gox', + 'goy', + 'gpa', + 'gps', + 'gtg', + 'gui', + 'gul', + 'gum', + 'gun', + 'gus', + 'gut', + 'guv', + 'guy', + 'gym', + 'gyp', + 'had', + 'hae', + 'hag', + 'hah', + 'hai', + 'haj', + 'hal', + 'ham', + 'han', + 'hao', + 'hap', + 'haq', + 'har', + 'has', + 'hat', + 'haw', + 'hay', + 'hdd', + 'hdl', + 'hee', + 'heh', + 'hel', + 'hem', + 'hen', + 'hep', + 'her', + 'hes', + 'het', + 'hew', + 'hex', + 'hey', + 'hic', + 'hid', + 'hie', + 'him', + 'hin', + 'hip', + 'his', + 'hit', + 'hiv', + 'hjo', + 'hmi', + 'hmm', + 'hmu', + 'hnv', + 'hoa', + 'hob', + 'hod', + 'hoe', + 'hog', + 'hon', + 'hop', + 'hor', + 'hos', + 'hot', + 'hou', + 'how', + 'hoy', + 'hpl', + 'hpv', + 'hub', + 'hud', + 'hue', + 'hug', + 'huh', + 'hui', + 'hum', + 'hun', + 'hup', + 'hut', + 'hwa', + 'hwp', + 'hye', + 'hyo', + 'hyp', + 'ian', + 'ibm', + 'ibn', + 'ibu', + 'ica', + 'ice', + 'ich', + 'ick', + 'icy', + 'ida', + 'ide', + 'idi', + 'idk', + 'idl', + 'ido', + 'ids', + 'ife', + 'iff', + 'ifs', + 'igg', + 'ika', + 'ike', + 'ila', + 'ilk', + 'ill', + 'ilm', + 'ilo', + 'ily', + 'ima', + 'imo', + 'imp', + 'ina', + 'inc', + 'ink', + 'inn', + 'ins', + 'inu', + 'iny', + 'ion', + 'ipa', + 'ipc', + 'ipo', + 'ipv', + 'ira', + 'irb', + 'ire', + 'irk', + 'irr', + 'isa', + 'ism', + 'iso', + 'ita', + 'its', + 'itt', + 'iva', + 'ivy', + 'iza', + 'jab', + 'jae', + 'jag', + 'jai', + 'jal', + 'jam', + 'jan', + 'jar', + 'jaw', + 'jay', + 'jed', + 'jee', + 'jen', + 'jet', + 'jeu', + 'jew', + 'jib', + 'jig', + 'jim', + 'jin', + 'job', + 'joe', + 'jog', + 'joi', + 'jon', + 'jot', + 'jow', + 'joy', + 'jud', + 'jug', + 'jul', + 'jun', + 'jus', + 'jut', + 'kab', + 'kae', + 'kaf', + 'kai', + 'kam', + 'kar', + 'kas', + 'kat', + 'kaw', + 'kay', + 'kea', + 'keb', + 'kef', + 'keg', + 'kek', + 'ken', + 'kep', + 'ker', + 'ket', + 'kew', + 'kex', + 'key', + 'khi', + 'kia', + 'kid', + 'kif', + 'kim', + 'kin', + 'kip', + 'kir', + 'kis', + 'kit', + 'kmt', + 'koa', + 'kob', + 'koi', + 'kop', + 'kor', + 'kos', + 'kpi', + 'ksi', + 'kue', + 'kum', + 'kun', + 'kye', + 'kym', + 'kyu', + 'lac', + 'lad', + 'lag', + 'lai', + 'lak', + 'lal', + 'lam', + 'lan', + 'lao', + 'lap', + 'lar', + 'las', + 'lat', + 'lav', + 'law', + 'lax', + 'lay', + 'lbo', + 'ldl', + 'lea', + 'led', + 'lee', + 'leg', + 'leh', + 'lei', + 'lek', + 'len', + 'leo', + 'les', + 'let', + 'leu', + 'lev', + 'lex', + 'ley', + 'lez', + 'lfk', + 'lgv', + 'lia', + 'lib', + 'lid', + 'lie', + 'lif', + 'lin', + 'lip', + 'lis', + 'lit', + 'liu', + 'liv', + 'liz', + 'llc', + 'llp', + 'lls', + 'loa', + 'lob', + 'log', + 'lol', + 'lon', + 'loo', + 'lop', + 'lot', + 'lou', + 'low', + 'lox', + 'loy', + 'lpc', + 'lsd', + 'lsm', + 'ltr', + 'lue', + 'lug', + 'lum', + 'lut', + 'luv', + 'lux', + 'luz', + 'lye', + 'lyn', + 'mab', + 'mac', + 'mad', + 'mae', + 'mag', + 'mai', + 'maj', + 'mal', + 'mam', + 'man', + 'mao', + 'mar', + 'mas', + 'mat', + 'mau', + 'maw', + 'max', + 'may', + 'mba', + 'mbi', + 'mcc', + 'med', + 'mee', + 'meg', + 'mei', + 'mel', + 'mem', + 'men', + 'met', + 'mew', + 'mhm', + 'mho', + 'mia', + 'mib', + 'mic', + 'mid', + 'mig', + 'mil', + 'mim', + 'min', + 'mir', + 'mis', + 'mix', + 'mll', + 'mls', + 'moa', + 'mob', + 'moc', + 'mod', + 'moe', + 'mog', + 'moh', + 'moi', + 'mol', + 'mom', + 'mon', + 'moo', + 'mop', + 'mor', + 'mos', + 'mot', + 'mou', + 'mow', + 'mri', + 'mud', + 'mug', + 'mui', + 'mul', + 'mum', + 'mun', + 'mus', + 'mut', + 'mvp', + 'myc', + 'nab', + 'nae', + 'nag', + 'nah', + 'nam', + 'nan', + 'nap', + 'nas', + 'nat', + 'naw', + 'nay', + 'neb', + 'ned', + 'nee', + 'neg', + 'net', + 'new', + 'nfl', + 'nga', + 'nia', + 'nib', + 'nil', + 'nim', + 'nip', + 'nis', + 'nit', + 'nix', + 'nlp', + 'nng', + 'nnn', + 'nnv', + 'nob', + 'nod', + 'noe', + 'nog', + 'noh', + 'nom', + 'noo', + 'nor', + 'nos', + 'not', + 'nqc', + 'nrl', + 'nsa', + 'nth', + 'nub', + 'nug', + 'nuh', + 'nun', + 'nur', + 'nus', + 'nut', + 'nvm', + 'nyc', + 'nye', + 'oaf', + 'oak', + 'oar', + 'oat', + 'oba', + 'obe', + 'obi', + 'obs', + 'oca', + 'oda', + 'odd', + 'ode', + 'ods', + 'oes', + 'off', + 'oft', + 'ohm', + 'oho', + 'ohs', + 'oik', + 'oka', + 'oke', + 'ola', + 'old', + 'ole', + 'olo', + 'olt', + 'oma', + 'omg', + 'omo', + 'oms', + 'ona', + 'ono', + 'ons', + 'oob', + 'ooh', + 'oop', + 'oot', + 'opa', + 'ope', + 'opl', + 'opp', + 'ops', + 'opt', + 'ora', + 'orb', + 'orc', + 'ord', + 'ore', + 'orr', + 'ors', + 'ort', + 'ose', + 'oss', + 'otb', + 'ote', + 'oto', + 'otr', + 'oud', + 'our', + 'ova', + 'ovo', + 'owc', + 'owe', + 'owl', + 'owo', + 'oxo', + 'oxy', + 'pac', + 'pad', + 'pah', + 'pai', + 'pal', + 'pam', + 'pan', + 'pap', + 'par', + 'pas', + 'pat', + 'pau', + 'paw', + 'pax', + 'paz', + 'pci', + 'pcs', + 'pea', + 'pec', + 'ped', + 'pee', + 'peg', + 'peh', + 'pei', + 'pen', + 'pep', + 'per', + 'pes', + 'pet', + 'pew', + 'pfc', + 'pft', + 'phd', + 'phi', + 'php', + 'pht', + 'pia', + 'pic', + 'pie', + 'pig', + 'pin', + 'pip', + 'pis', + 'pit', + 'piu', + 'pix', + 'ply', + 'pms', + 'png', + 'pod', + 'poh', + 'poi', + 'pok', + 'pol', + 'pom', + 'poo', + 'pop', + 'pos', + 'pot', + 'pov', + 'pow', + 'pox', + 'ppc', + 'ppd', + 'ppm', + 'ppp', + 'pre', + 'pro', + 'pry', + 'psi', + 'pst', + 'psu', + 'pub', + 'pud', + 'pug', + 'pul', + 'pun', + 'pup', + 'pur', + 'pus', + 'put', + 'pwn', + 'pya', + 'pye', + 'pyx', + 'qat', + 'qeb', + 'qis', + 'qom', + 'qua', + 'rad', + 'rae', + 'rag', + 'rah', + 'rai', + 'raj', + 'ran', + 'rao', + 'rap', + 'ras', + 'rat', + 'rau', + 'raw', + 'rax', + 'ray', + 'rbi', + 'rea', + 'reb', + 'rec', + 'red', + 'ree', + 'ref', + 'reg', + 'rei', + 'rem', + 'rep', + 'res', + 'ret', + 'reu', + 'rev', + 'rex', + 'rey', + 'rg3', + 'rgp', + 'rho', + 'ria', + 'rib', + 'rid', + 'rif', + 'rig', + 'rim', + 'rin', + 'rio', + 'rip', + 'rna', + 'roa', + 'rob', + 'roc', + 'rod', + 'roe', + 'roi', + 'rom', + 'ron', + 'ros', + 'rot', + 'row', + 'roy', + 'rpm', + 'rsp', + 'rss', + 'rtv', + 'rub', + 'rue', + 'rug', + 'rum', + 'run', + 'rut', + 'rwc', + 'rya', + 'rye', + 'ryu', + 'sab', + 'sac', + 'sad', + 'sae', + 'sag', + 'sah', + 'sai', + 'sal', + 'sam', + 'sao', + 'sap', + 'saq', + 'sas', + 'sat', + 'sau', + 'saw', + 'sax', + 'say', + 'sbs', + 'scr', + 'sea', + 'seb', + 'sec', + 'sed', + 'see', + 'seg', + 'sei', + 'sel', + 'sem', + 'sen', + 'seo', + 'ser', + 'set', + 'sew', + 'sha', + 'she', + 'shh', + 'shu', + 'shy', + 'sib', + 'sic', + 'sid', + 'sif', + 'sim', + 'sin', + 'sip', + 'sir', + 'sis', + 'sit', + 'siu', + 'six', + 'ska', + 'ski', + 'sky', + 'slt', + 'sly', + 'smh', + 'sns', + 'sob', + 'sod', + 'som', + 'son', + 'soo', + 'sop', + 'sos', + 'sot', + 'sou', + 'sow', + 'sox', + 'soy', + 'spa', + 'spy', + 'sri', + 'srt', + 'ssd', + 'ssl', + 'std', + 'sti', + 'sty', + 'sub', + 'sue', + 'sui', + 'suk', + 'sum', + 'sun', + 'sup', + 'suq', + 'syn', + 'tab', + 'tad', + 'tae', + 'tai', + 'taj', + 'tam', + 'tan', + 'tao', + 'tap', + 'tar', + 'tas', + 'tat', + 'tau', + 'tav', + 'taw', + 'tax', + 'tbh', + 'tca', + 'tcp', + 'tea', + 'ted', + 'tee', + 'teg', + 'tel', + 'tem', + 'ten', + 'tet', + 'tew', + 'thi', + 'tho', + 'thu', + 'thy', + 'tia', + 'tic', + 'tie', + 'til', + 'tim', + 'tin', + 'tip', + 'tis', + 'tit', + 'tko', + 'tmi', + 'tod', + 'toe', + 'tog', + 'tom', + 'ton', + 'too', + 'top', + 'tor', + 'tot', + 'tow', + 'toy', + 'try', + 'tsk', + 'tub', + 'tug', + 'tui', + 'tun', + 'tup', + 'tut', + 'tux', + 'tvs', + 'twa', + 'two', + 'tye', + 'tyr', + 'tzu', + 'uav', + 'ude', + 'udo', + 'ufo', + 'ugh', + 'uke', + 'ull', + 'ulm', + 'ulu', + 'umm', + 'ump', + 'una', + 'une', + 'uni', + 'uno', + 'uns', + 'upo', + 'ups', + 'ura', + 'urb', + 'urd', + 'url', + 'urn', + 'urp', + 'urs', + 'uru', + 'usa', + 'usb', + 'use', + 'uta', + 'ute', + 'uts', + 'uwa', + 'vac', + 'val', + 'van', + 'var', + 'vas', + 'vat', + 'vau', + 'vav', + 'vaw', + 'vdd', + 'vee', + 'veg', + 'vet', + 'vex', + 'vga', + 'vhs', + 'via', + 'vid', + 'vie', + 'vig', + 'vim', + 'vin', + 'vip', + 'vis', + 'viz', + 'vms', + 'vo2', + 'voe', + 'von', + 'vor', + 'vow', + 'vox', + 'vpn', + 'vps', + 'vru', + 'vtr', + 'vug', + 'vum', + 'wab', + 'wad', + 'wae', + 'wag', + 'wai', + 'wan', + 'wap', + 'war', + 'was', + 'wat', + 'waw', + 'wax', + 'way', + 'web', + 'wed', + 'wee', + 'wen', + 'wes', + 'wet', + 'wha', + 'who', + 'wig', + 'win', + 'wis', + 'wit', + 'wiz', + 'woe', + 'wog', + 'wok', + 'won', + 'woo', + 'wop', + 'wos', + 'wot', + 'wow', + 'wpg', + 'wry', + 'wtf', + 'wud', + 'www', + 'wye', + 'wyn', + 'xis', + 'xup', + 'xyz', + 'yag', + 'yah', + 'yak', + 'yam', + 'yan', + 'yap', + 'yar', + 'yaw', + 'yay', + 'yea', + 'yeh', + 'yen', + 'yep', + 'yes', + 'yet', + 'yew', + 'ygg', + 'yid', + 'yin', + 'yip', + 'ynu', + 'yob', + 'yod', + 'yoi', + 'yok', + 'yom', + 'yon', + 'yow', + 'yue', + 'yuk', + 'yum', + 'yup', + 'zag', + 'zap', + 'zas', + 'zax', + 'zed', + 'zee', + 'zek', + 'zen', + 'zep', + 'zev', + 'zia', + 'zig', + 'zin', + 'zip', + 'zit', + 'zoa', + 'zoe', + 'zoo', + 'zuz', + 'zyl', + 'zzz' +] diff --git a/src/modules/1country/index.ts b/src/modules/1country/index.ts index 7484c7c4..103fa690 100644 --- a/src/modules/1country/index.ts +++ b/src/modules/1country/index.ts @@ -15,6 +15,8 @@ import config from '../../config' import { MAX_TRIES, sendMessage } from '../open-ai/helpers' import { sleep } from '../sd-images/utils' import { isValidUrl } from '../open-ai/utils/web-crawler' +import { dcClient } from './api/d1dc' +import { ethers } from 'ethers' export const SupportedCommands = { register: { name: 'rent' }, @@ -247,42 +249,21 @@ export class OneCountryBot implements PayableBot { return } const { prompt } = getCommandNamePrompt(ctx, SupportedCommands) - const lastDomain = ctx.session.oneCountry.lastDomain + let msgId = 0 - if (!prompt && !lastDomain) { + + const domainName = this.cleanInput( + this.hasPrefix(prompt) ? prompt.slice(1) : prompt + ) + + if (!domainName) { await ctx.reply('Write a domain name', { message_thread_id: ctx.message?.message_thread_id }) ctx.session.analytics.actualResponseTime = process.hrtime.bigint() ctx.session.analytics.sessionState = SessionState.Error return } - if (!prompt && lastDomain) { - // ************** dc rent process ******************** - if ( - !(await this.payments.rent(ctx as OnMessageContext, lastDomain)) // to be implemented - ) { - await this.onNotBalanceMessage(ctx) - ctx.session.analytics.sessionState = SessionState.Error - ctx.session.analytics.actualResponseTime = process.hrtime.bigint() - } else { - const fullUrl = getUrl(lastDomain, true) - await ctx.reply(`The Domain ${fullUrl} was registered`, { - parse_mode: 'Markdown', - message_thread_id: ctx.message?.message_thread_id - }) - // await ctx.reply(`The Domain [${fullUrl}](${config.country.hostname}/new?domain=${lastDomain}) was registered`, { - // parse_mode: 'Markdown', - // message_thread_id: ctx.message?.message_thread_id, - // disable_web_page_preview: false - // }) - ctx.session.analytics.sessionState = SessionState.Success - ctx.session.analytics.actualResponseTime = process.hrtime.bigint() - return - } - } - const domain = this.cleanInput( - this.hasPrefix(prompt) ? prompt.slice(1) : prompt - ) - const validate = validateDomainName(domain) + + const validate = validateDomainName(domainName) if (!validate.valid) { await ctx.reply(validate.error, { parse_mode: 'Markdown', @@ -292,12 +273,12 @@ export class OneCountryBot implements PayableBot { ctx.session.analytics.sessionState = SessionState.Error return } - ctx.session.oneCountry.lastDomain = domain + ctx.session.oneCountry.lastDomain = domainName msgId = (await ctx.reply('Checking name...')).message_id ctx.session.analytics.firstResponseTime = process.hrtime.bigint() - const response = await isDomainAvailable(domain) + const response = await isDomainAvailable(domainName) const domainAvailable = response.isAvailable - let msg = `The name *${domain}* ` + let msg = `The name *${domainName}* ` if (!domainAvailable && response.isInGracePeriod) { msg += 'is in grace period ❌. Only the owner is able to renew the domain' } else if (!domainAvailable) { @@ -316,6 +297,101 @@ export class OneCountryBot implements PayableBot { if (ctx.chat?.id) { await ctx.api.editMessageText(ctx.chat.id, msgId, msg, { parse_mode: 'Markdown' }) } + + const domainInfo = await isDomainAvailable(domainName) + + if (!domainInfo.isAvailable) { + await ctx.reply('This domain name is already registered') + return + } + + const validateResult = validateDomainName(domainName) + + if (validateResult.error) { + await ctx.reply(validateResult.error) + return + } + + const accountId = this.payments.getAccountId(ctx as OnMessageContext) + const balance = await this.payments.getUserBalance(accountId) + const commissionFee = ethers.utils.parseUnits('2', 'ether') + + console.log('### balance', balance.toString()) + // console.log('### balance', ethers.utils.formatUnits(balance, 'ethers')) + + console.log('### domainInfo.priceOne', domainInfo.priceOne) + + if (balance.plus(commissionFee.toString()).lt(domainInfo.priceWei)) { + await this.onNotBalanceMessage(ctx) + return + } + + const account = this.payments.getUserAccount(accountId) + + if (!account) { + this.logger.error('account not found') + await ctx.reply('Unexpected error') + return + } + + const secret = Math.random().toString(26).slice(2) + const commitResult = await dcClient.commit({ account, name: domainName, secret }) + + console.log('### commitResult', commitResult) + if (!commitResult.txReceipt) { + Sentry.captureException(commitResult.error) + console.log('### commitResult', commitResult.error) + this.logger.error('commit error') + await ctx.reply('Unexpected error') + return + } + + await sleep(5000) + console.log('### rent', domainInfo.priceWei) + + const rentResult = await dcClient.rent({ + account, + name: domainName, + secret, + owner: account.address, + amount: domainInfo.priceWei + }) + + if (!rentResult.txReceipt) { + Sentry.captureException(rentResult.error) + console.log('### rentResult.error', rentResult.error) + await ctx.reply('Unexpected error') + return + } + + await relayApi().purchaseDomain({ + domain: domainName, + address: account.address, + txHash: rentResult.txReceipt.transactionHash + }) + + await relayApi().genNFT({ domain: domainName }) + + if (!rentResult) { + await this.onNotBalanceMessage(ctx) + ctx.session.analytics.sessionState = SessionState.Error + ctx.session.analytics.actualResponseTime = process.hrtime.bigint() + } else { + const fullUrl = getUrl(domainName, true) + await ctx.reply(`The Domain ${fullUrl} was registered`, { + parse_mode: 'Markdown', + message_thread_id: ctx.message?.message_thread_id + }) + // await ctx.reply(`The Domain [${fullUrl}](${config.country.hostname}/new?domain=${lastDomain}) was registered`, { + // parse_mode: 'Markdown', + // message_thread_id: ctx.message?.message_thread_id, + // disable_web_page_preview: false + // }) + ctx.session.analytics.sessionState = SessionState.Success + ctx.session.analytics.actualResponseTime = process.hrtime.bigint() + return + } + ctx.session.analytics.sessionState = SessionState.Success ctx.session.analytics.actualResponseTime = process.hrtime.bigint() } catch (e) { diff --git a/src/modules/1country/utils/domain.ts b/src/modules/1country/utils/domain.ts index 798dcb9c..0c63e55b 100644 --- a/src/modules/1country/utils/domain.ts +++ b/src/modules/1country/utils/domain.ts @@ -4,7 +4,7 @@ import { relayApi } from '../api/relayApi' import { getUSDPrice } from '../api/coingecko' import { formatONEAmount } from '.' -interface DomainInfo { isAvailable: boolean, priceOne: string, priceUSD: { price: string | null, error: string | null }, isInGracePeriod: boolean } +interface DomainInfo { isAvailable: boolean, priceOne: string, priceWei: string, priceUSD: { price: string | null, error: string | null }, isInGracePeriod: boolean } export const isDomainAvailable = async (domainName: string): Promise => { const nameExpired = await dcClient.checkNameExpired({ name: domainName }) @@ -14,8 +14,11 @@ export const isDomainAvailable = async (domainName: string): Promise (web2IsAvailable && web3IsAvailable) || // initial comparsion (nameExpired.isExpired && !nameExpired.isInGracePeriod)) as boolean let domainPrice = '' + let domainPriceWei = '' if (isAvailable) { - domainPrice = (await dcClient.getPrice({ name: domainName })).formatted + const priceInfo = await dcClient.getPrice({ name: domainName }) + domainPrice = priceInfo.formatted + domainPriceWei = priceInfo.amount } return { isAvailable: @@ -24,6 +27,7 @@ export const isDomainAvailable = async (domainName: string): Promise (nameExpired.isExpired && !nameExpired.isInGracePeriod)) as boolean, isInGracePeriod: nameExpired.isInGracePeriod, priceOne: domainPrice && formatONEAmount(domainPrice), + priceWei: domainPriceWei, priceUSD: domainPrice ? await getUSDPrice(domainPrice) : { price: '0', error: null } } }