mirror of
https://github.com/pezkuwichain/pezkuwi-telegram-miniapp.git
synced 2026-06-13 09:21:10 +00:00
feat: add multi-network USDT deposit (TON, Polkadot, TRC20 HD wallet)
This commit is contained in:
Generated
+519
-3
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "pezkuwi-telegram-miniapp",
|
||||
"version": "1.0.107",
|
||||
"version": "1.0.169",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "pezkuwi-telegram-miniapp",
|
||||
"version": "1.0.107",
|
||||
"version": "1.0.169",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@pezkuwi/api": "^16.5.36",
|
||||
@@ -14,6 +14,8 @@
|
||||
"@pezkuwi/util-crypto": "^14.0.25",
|
||||
"@supabase/supabase-js": "^2.93.1",
|
||||
"@tanstack/react-query": "^5.56.2",
|
||||
"@ton/crypto": "^3.3.0",
|
||||
"@ton/ton": "^16.2.2",
|
||||
"@types/qrcode": "^1.5.6",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
@@ -36,6 +38,7 @@
|
||||
"@vitejs/plugin-react-swc": "^3.5.0",
|
||||
"@vitest/coverage-v8": "^4.0.18",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"bip39": "^3.1.0",
|
||||
"eslint": "^9.39.2",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-prettier": "^5.5.5",
|
||||
@@ -48,6 +51,7 @@
|
||||
"postcss": "^8.4.47",
|
||||
"prettier": "^3.8.1",
|
||||
"tailwindcss": "^3.4.11",
|
||||
"tronweb": "^6.2.0",
|
||||
"typescript": "^5.5.3",
|
||||
"vite": "^5.4.1",
|
||||
"vitest": "^4.0.18"
|
||||
@@ -70,6 +74,13 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@adraffy/ens-normalize": {
|
||||
"version": "1.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz",
|
||||
"integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@alloc/quick-lru": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
|
||||
@@ -2331,6 +2342,94 @@
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@scure/bip32": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz",
|
||||
"integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@noble/curves": "~1.4.0",
|
||||
"@noble/hashes": "~1.4.0",
|
||||
"@scure/base": "~1.1.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@scure/bip32/node_modules/@noble/curves": {
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz",
|
||||
"integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@noble/hashes": "1.4.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@scure/bip32/node_modules/@noble/hashes": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz",
|
||||
"integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 16"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@scure/bip32/node_modules/@scure/base": {
|
||||
"version": "1.1.9",
|
||||
"resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz",
|
||||
"integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@scure/bip39": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz",
|
||||
"integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@noble/hashes": "~1.4.0",
|
||||
"@scure/base": "~1.1.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@scure/bip39/node_modules/@noble/hashes": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz",
|
||||
"integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 16"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@scure/bip39/node_modules/@scure/base": {
|
||||
"version": "1.1.9",
|
||||
"resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz",
|
||||
"integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/@standard-schema/spec": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz",
|
||||
@@ -2752,6 +2851,60 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@ton/core": {
|
||||
"version": "0.63.0",
|
||||
"resolved": "https://registry.npmjs.org/@ton/core/-/core-0.63.0.tgz",
|
||||
"integrity": "sha512-uBc0WQNYVzjAwPvIazf0Ryhpv4nJd4dKIuHoj766gUdwe8sVzGM+TxKKKJETL70hh/mxACyUlR4tAwN0LWDNow==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"peerDependencies": {
|
||||
"@ton/crypto": ">=3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@ton/crypto": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@ton/crypto/-/crypto-3.3.0.tgz",
|
||||
"integrity": "sha512-/A6CYGgA/H36OZ9BbTaGerKtzWp50rg67ZCH2oIjV1NcrBaCK9Z343M+CxedvM7Haf3f/Ee9EhxyeTp0GKMUpA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ton/crypto-primitives": "2.1.0",
|
||||
"jssha": "3.2.0",
|
||||
"tweetnacl": "1.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@ton/crypto-primitives": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ton/crypto-primitives/-/crypto-primitives-2.1.0.tgz",
|
||||
"integrity": "sha512-PQesoyPgqyI6vzYtCXw4/ZzevePc4VGcJtFwf08v10OevVJHVfW238KBdpj1kEDQkxWLeuNHEpTECNFKnP6tow==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"jssha": "3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@ton/ton": {
|
||||
"version": "16.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@ton/ton/-/ton-16.2.2.tgz",
|
||||
"integrity": "sha512-yEOw4IW3gpRZxJAcILMI4dQ1d5/eAAbD2VU/Iwc6z7f2jt1mLDWVED8yn2vLNucQfZr+1eaqYHLztYVFZ7PKmw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"axios": "^1.6.7",
|
||||
"dataloader": "^2.0.0",
|
||||
"zod": "^3.21.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ton/core": ">=0.63.0 <1.0.0",
|
||||
"@ton/crypto": ">=3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@ton/ton/node_modules/zod": {
|
||||
"version": "3.25.76",
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
|
||||
"integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/aria-query": {
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
|
||||
@@ -3246,6 +3399,13 @@
|
||||
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/aes-js": {
|
||||
"version": "4.0.0-beta.5",
|
||||
"resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz",
|
||||
"integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/agent-base": {
|
||||
"version": "7.1.4",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
|
||||
@@ -3562,6 +3722,12 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/autoprefixer": {
|
||||
"version": "10.4.24",
|
||||
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.24.tgz",
|
||||
@@ -3614,6 +3780,17 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.12.2",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz",
|
||||
"integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.6",
|
||||
"form-data": "^4.0.4",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
@@ -3661,6 +3838,16 @@
|
||||
"require-from-string": "^2.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/bignumber.js": {
|
||||
"version": "9.1.2",
|
||||
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz",
|
||||
"integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/binary-extensions": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
|
||||
@@ -3673,6 +3860,16 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/bip39": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/bip39/-/bip39-3.1.0.tgz",
|
||||
"integrity": "sha512-c9kiwdk45Do5GL0vJMe7tS95VjCii65mYAH7DfWl3uW8AVzXKQVUm64i3hzVybBDMp9r7j9iNxR85+ul8MdN/A==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@noble/hashes": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bn.js": {
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz",
|
||||
@@ -4246,6 +4443,18 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/commander": {
|
||||
"version": "14.0.3",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz",
|
||||
@@ -4530,6 +4739,12 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/dataloader": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/dataloader/-/dataloader-2.2.3.tgz",
|
||||
"integrity": "sha512-y2krtASINtPFS1rSDjacrFgn1dcUuoREVabwlOGOe4SdxenREqwjwjElAdwvbGM7kgZz9a3KVicWR7vcz8rnzA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/date-fns": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz",
|
||||
@@ -4614,6 +4829,15 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/dequal": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
|
||||
@@ -4915,7 +5139,6 @@
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
||||
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
@@ -5377,6 +5600,146 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ethereum-cryptography": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz",
|
||||
"integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@noble/curves": "1.4.2",
|
||||
"@noble/hashes": "1.4.0",
|
||||
"@scure/bip32": "1.4.0",
|
||||
"@scure/bip39": "1.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ethereum-cryptography/node_modules/@noble/curves": {
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz",
|
||||
"integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@noble/hashes": "1.4.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/ethereum-cryptography/node_modules/@noble/hashes": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz",
|
||||
"integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 16"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/ethers": {
|
||||
"version": "6.13.5",
|
||||
"resolved": "https://registry.npmjs.org/ethers/-/ethers-6.13.5.tgz",
|
||||
"integrity": "sha512-+knKNieu5EKRThQJWwqaJ10a6HE9sSehGeqWN65//wE7j47ZpFhKAnHB/JJFibwwg61I/koxaPsXbXpD/skNOQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/ethers-io/"
|
||||
},
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://www.buymeacoffee.com/ricmoo"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@adraffy/ens-normalize": "1.10.1",
|
||||
"@noble/curves": "1.2.0",
|
||||
"@noble/hashes": "1.3.2",
|
||||
"@types/node": "22.7.5",
|
||||
"aes-js": "4.0.0-beta.5",
|
||||
"tslib": "2.7.0",
|
||||
"ws": "8.17.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ethers/node_modules/@noble/curves": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz",
|
||||
"integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@noble/hashes": "1.3.2"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/ethers/node_modules/@noble/hashes": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz",
|
||||
"integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 16"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/ethers/node_modules/@types/node": {
|
||||
"version": "22.7.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz",
|
||||
"integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.19.2"
|
||||
}
|
||||
},
|
||||
"node_modules/ethers/node_modules/tslib": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz",
|
||||
"integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==",
|
||||
"dev": true,
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/ethers/node_modules/undici-types": {
|
||||
"version": "6.19.8",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
|
||||
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ethers/node_modules/ws": {
|
||||
"version": "8.17.1",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
|
||||
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
|
||||
"dev": true,
|
||||
"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/eventemitter3": {
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz",
|
||||
@@ -5562,6 +5925,26 @@
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.11",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
|
||||
"integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"debug": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/for-each": {
|
||||
"version": "0.3.5",
|
||||
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
|
||||
@@ -5577,6 +5960,22 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/form-data": {
|
||||
"version": "4.0.5",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
|
||||
"integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"es-set-tostringtag": "^2.1.0",
|
||||
"hasown": "^2.0.2",
|
||||
"mime-types": "^2.1.12"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/formdata-polyfill": {
|
||||
"version": "4.0.10",
|
||||
"resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
|
||||
@@ -5795,6 +6194,13 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/google-protobuf": {
|
||||
"version": "3.21.4",
|
||||
"resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.21.4.tgz",
|
||||
"integrity": "sha512-MnG7N936zcKTco4Jd2PX2U96Kf9PxygAPKBug+74LHzmHXmceN16MmRcdgZv+DGef/S9YvQAfRsNCn4cjf9yyQ==",
|
||||
"dev": true,
|
||||
"license": "(BSD-3-Clause AND Apache-2.0)"
|
||||
},
|
||||
"node_modules/gopd": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||
@@ -6766,6 +7172,15 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/jssha": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/jssha/-/jssha-3.2.0.tgz",
|
||||
"integrity": "sha512-QuruyBENDWdN4tZwJbQq7/eAK85FqrI4oDbXjy5IBhYD+2pTJyBUWZe8ctWaCkrV0gy6AaelgOZZBMeswEa/6Q==",
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/jsx-ast-utils": {
|
||||
"version": "3.3.5",
|
||||
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
|
||||
@@ -7056,6 +7471,27 @@
|
||||
"integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/mime-db": {
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-types": {
|
||||
"version": "2.1.35",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mime-db": "1.52.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/mimic-function": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz",
|
||||
@@ -8130,6 +8566,12 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/public-encrypt": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz",
|
||||
@@ -8344,6 +8786,13 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/regenerator-runtime": {
|
||||
"version": "0.14.1",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
|
||||
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/regexp.prototype.flags": {
|
||||
"version": "1.5.4",
|
||||
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz",
|
||||
@@ -9532,6 +9981,57 @@
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/tronweb": {
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tronweb/-/tronweb-6.2.0.tgz",
|
||||
"integrity": "sha512-09kyW6mqiFuSYXkR35ndxCeNF5rW1O18hKAClCLtVHP2xBFPYSGx3lDYC2hRKcuLiq6iLPxOVCrhzoKNGlFuQQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.26.10",
|
||||
"axios": "1.12.2",
|
||||
"bignumber.js": "9.1.2",
|
||||
"ethereum-cryptography": "2.2.1",
|
||||
"ethers": "6.13.5",
|
||||
"eventemitter3": "5.0.1",
|
||||
"google-protobuf": "3.21.4",
|
||||
"semver": "7.7.1",
|
||||
"validator": "13.15.23"
|
||||
}
|
||||
},
|
||||
"node_modules/tronweb/node_modules/@babel/runtime": {
|
||||
"version": "7.26.10",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.10.tgz",
|
||||
"integrity": "sha512-2WJMeRQPHKSPemqk/awGrAiuFfzBmOIPXKizAsVhWH9YJqLZ0H+HS4c8loHGgW6utJ3E/ejXQUsiGaQy2NZ9Fw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"regenerator-runtime": "^0.14.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tronweb/node_modules/eventemitter3": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz",
|
||||
"integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tronweb/node_modules/semver": {
|
||||
"version": "7.7.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
|
||||
"integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-api-utils": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz",
|
||||
@@ -9563,6 +10063,12 @@
|
||||
"integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tweetnacl": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz",
|
||||
"integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==",
|
||||
"license": "Unlicense"
|
||||
},
|
||||
"node_modules/type-check": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
||||
@@ -9771,6 +10277,16 @@
|
||||
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/validator": {
|
||||
"version": "13.15.23",
|
||||
"resolved": "https://registry.npmjs.org/validator/-/validator-13.15.23.tgz",
|
||||
"integrity": "sha512-4yoz1kEWqUjzi5zsPbAS/903QXSYp0UOtHsPpp7p9rHAw/W+dkInskAE386Fat3oKRROwO98d9ZB0G4cObgUyw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "5.4.21",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz",
|
||||
|
||||
+4
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "pezkuwi-telegram-miniapp",
|
||||
"version": "1.0.169",
|
||||
"version": "1.0.170",
|
||||
"type": "module",
|
||||
"description": "Pezkuwichain Telegram Mini App - Forum, Announcements, Rewards",
|
||||
"author": "Pezkuwichain Team",
|
||||
@@ -42,6 +42,8 @@
|
||||
"@pezkuwi/util-crypto": "^14.0.25",
|
||||
"@supabase/supabase-js": "^2.93.1",
|
||||
"@tanstack/react-query": "^5.56.2",
|
||||
"@ton/crypto": "^3.3.0",
|
||||
"@ton/ton": "^16.2.2",
|
||||
"@types/qrcode": "^1.5.6",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
@@ -64,6 +66,7 @@
|
||||
"@vitejs/plugin-react-swc": "^3.5.0",
|
||||
"@vitest/coverage-v8": "^4.0.18",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"bip39": "^3.1.0",
|
||||
"eslint": "^9.39.2",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-prettier": "^5.5.5",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Deposit USDT Modal
|
||||
* Allows users to deposit USDT (TRC20 or Polkadot) to get wUSDT on Asset Hub
|
||||
* Supports TON, Polkadot (recommended) and TRC20 (with fee warning)
|
||||
*/
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
@@ -13,43 +13,57 @@ import {
|
||||
Loader2,
|
||||
History,
|
||||
Plus,
|
||||
AlertTriangle,
|
||||
} from 'lucide-react';
|
||||
import { useTelegram } from '@/hooks/useTelegram';
|
||||
import { supabase } from '@/lib/supabase';
|
||||
|
||||
type Network = 'trc20' | 'polkadot';
|
||||
type Network = 'ton' | 'polkadot' | 'trc20';
|
||||
|
||||
interface NetworkInfo {
|
||||
id: Network;
|
||||
name: string;
|
||||
description: string;
|
||||
address: string;
|
||||
explorer: string;
|
||||
icon: string;
|
||||
minAmount: number;
|
||||
confirmations: number;
|
||||
recommended: boolean;
|
||||
fee: number;
|
||||
feeWarning?: string;
|
||||
explorer: string;
|
||||
minDeposit: number;
|
||||
}
|
||||
|
||||
const NETWORKS: NetworkInfo[] = [
|
||||
{
|
||||
id: 'trc20',
|
||||
name: 'TRC20 (TRON)',
|
||||
description: 'USDT li ser tora TRON',
|
||||
address: import.meta.env.VITE_DEPOSIT_TRON_ADDRESS || '',
|
||||
explorer: 'https://tronscan.org/#/transaction/',
|
||||
icon: '🔴',
|
||||
minAmount: 10,
|
||||
confirmations: 20,
|
||||
id: 'ton',
|
||||
name: 'TON',
|
||||
description: 'Telegram Wallet',
|
||||
icon: '💎',
|
||||
recommended: true,
|
||||
fee: 0.05,
|
||||
explorer: 'https://tonviewer.com/transaction/',
|
||||
minDeposit: 10,
|
||||
},
|
||||
{
|
||||
id: 'polkadot',
|
||||
name: 'Polkadot Asset Hub',
|
||||
description: 'USDT li ser Polkadot',
|
||||
address: import.meta.env.VITE_DEPOSIT_POLKADOT_ADDRESS || '',
|
||||
explorer: 'https://assethub-polkadot.subscan.io/extrinsic/',
|
||||
name: 'Polkadot',
|
||||
description: 'Asset Hub',
|
||||
icon: '⚪',
|
||||
minAmount: 10,
|
||||
confirmations: 1,
|
||||
recommended: true,
|
||||
fee: 0.05,
|
||||
explorer: 'https://assethub-polkadot.subscan.io/extrinsic/',
|
||||
minDeposit: 10,
|
||||
},
|
||||
{
|
||||
id: 'trc20',
|
||||
name: 'TRC20',
|
||||
description: 'TRON Network',
|
||||
icon: '🔴',
|
||||
recommended: false,
|
||||
fee: 3,
|
||||
feeWarning:
|
||||
'TRC20 ağ masrafı yaklaşık $3 civarındadır. 1000 USDT altındaki gönderimlerde verimli değildir. TON veya Polkadot ağını öneriyoruz.',
|
||||
explorer: 'https://tronscan.org/#/transaction/',
|
||||
minDeposit: 10,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -71,18 +85,35 @@ interface Props {
|
||||
export function DepositUSDTModal({ isOpen, onClose }: Props) {
|
||||
const { hapticImpact, showAlert } = useTelegram();
|
||||
|
||||
const [selectedNetwork, setSelectedNetwork] = useState<Network>('trc20');
|
||||
const [selectedNetwork, setSelectedNetwork] = useState<Network>('ton');
|
||||
const [depositCode, setDepositCode] = useState<string>('');
|
||||
const [depositAddress, setDepositAddress] = useState<string>('');
|
||||
const [copied, setCopied] = useState<'address' | 'memo' | null>(null);
|
||||
const [deposits, setDeposits] = useState<Deposit[]>([]);
|
||||
const [showHistory, setShowHistory] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [trc20Accepted, setTrc20Accepted] = useState(false);
|
||||
|
||||
const network = NETWORKS.find((n) => n.id === selectedNetwork) || NETWORKS[0];
|
||||
|
||||
// Fetch user's deposit code via edge function
|
||||
// Get deposit address based on network
|
||||
const getNetworkAddress = (networkId: Network): string => {
|
||||
switch (networkId) {
|
||||
case 'ton':
|
||||
return import.meta.env.VITE_DEPOSIT_TON_ADDRESS || '';
|
||||
case 'polkadot':
|
||||
return import.meta.env.VITE_DEPOSIT_POLKADOT_ADDRESS || '';
|
||||
case 'trc20':
|
||||
// TRC20 uses HD wallet - address comes from backend
|
||||
return depositAddress;
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
// Fetch user's deposit code and TRC20 address
|
||||
useEffect(() => {
|
||||
const fetchDepositCode = async () => {
|
||||
const fetchDepositInfo = async () => {
|
||||
if (!isOpen) return;
|
||||
|
||||
const initData = window.Telegram?.WebApp?.initData;
|
||||
@@ -93,25 +124,26 @@ export function DepositUSDTModal({ isOpen, onClose }: Props) {
|
||||
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const { data, error } = await supabase.functions.invoke('get-deposit-code', {
|
||||
const { data, error } = await supabase.functions.invoke('get-deposit-info', {
|
||||
body: { initData },
|
||||
});
|
||||
|
||||
if (error) {
|
||||
console.error('Error fetching deposit code:', error);
|
||||
console.error('Error fetching deposit info:', error);
|
||||
setDepositCode('---');
|
||||
} else if (data?.code) {
|
||||
setDepositCode(data.code);
|
||||
} else {
|
||||
if (data?.code) setDepositCode(data.code);
|
||||
if (data?.trc20Address) setDepositAddress(data.trc20Address);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Error fetching deposit code:', err);
|
||||
console.error('Error fetching deposit info:', err);
|
||||
setDepositCode('---');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchDepositCode();
|
||||
fetchDepositInfo();
|
||||
}, [isOpen]);
|
||||
|
||||
// Fetch deposits history
|
||||
@@ -179,6 +211,9 @@ export function DepositUSDTModal({ isOpen, onClose }: Props) {
|
||||
}
|
||||
};
|
||||
|
||||
const currentAddress = getNetworkAddress(selectedNetwork);
|
||||
const showTrc20Warning = selectedNetwork === 'trc20' && !trc20Accepted;
|
||||
|
||||
if (!isOpen) return null;
|
||||
|
||||
return (
|
||||
@@ -223,7 +258,13 @@ export function DepositUSDTModal({ isOpen, onClose }: Props) {
|
||||
<div className="flex justify-between items-start">
|
||||
<div>
|
||||
<div className="flex items-center gap-2">
|
||||
<span>{deposit.network === 'trc20' ? '🔴' : '⚪'}</span>
|
||||
<span>
|
||||
{deposit.network === 'ton'
|
||||
? '💎'
|
||||
: deposit.network === 'polkadot'
|
||||
? '⚪'
|
||||
: '🔴'}
|
||||
</span>
|
||||
<span className="font-mono">{deposit.amount} USDT</span>
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground mt-1">
|
||||
@@ -260,128 +301,210 @@ export function DepositUSDTModal({ isOpen, onClose }: Props) {
|
||||
{/* Network Selection */}
|
||||
<div>
|
||||
<label className="text-sm text-muted-foreground mb-2 block">Torê Hilbijêre</label>
|
||||
<div className="flex gap-2">
|
||||
<div className="grid grid-cols-3 gap-2">
|
||||
{NETWORKS.map((net) => (
|
||||
<button
|
||||
key={net.id}
|
||||
onClick={() => {
|
||||
setSelectedNetwork(net.id);
|
||||
setTrc20Accepted(false);
|
||||
hapticImpact('light');
|
||||
}}
|
||||
className={`flex-1 p-3 rounded-xl border transition-all ${
|
||||
className={`p-3 rounded-xl border transition-all relative ${
|
||||
selectedNetwork === net.id
|
||||
? 'border-green-500 bg-green-500/10'
|
||||
? net.recommended
|
||||
? 'border-green-500 bg-green-500/10'
|
||||
: 'border-yellow-500 bg-yellow-500/10'
|
||||
: 'border-border bg-muted/50'
|
||||
}`}
|
||||
>
|
||||
{net.recommended && (
|
||||
<span className="absolute -top-2 left-1/2 -translate-x-1/2 text-[10px] bg-green-500 text-white px-1.5 py-0.5 rounded">
|
||||
Pêşniyar
|
||||
</span>
|
||||
)}
|
||||
<div className="text-xl mb-1">{net.icon}</div>
|
||||
<div className="text-sm font-medium">{net.name}</div>
|
||||
<div className="text-xs text-muted-foreground">{net.description}</div>
|
||||
<div className="text-[10px] text-muted-foreground">{net.description}</div>
|
||||
<div
|
||||
className={`text-[10px] mt-1 ${net.fee > 1 ? 'text-yellow-400' : 'text-green-400'}`}
|
||||
>
|
||||
~${net.fee} fee
|
||||
</div>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Important Notice */}
|
||||
<div className="p-3 bg-yellow-500/10 border border-yellow-500/30 rounded-lg">
|
||||
<div className="flex gap-2">
|
||||
<AlertCircle className="w-5 h-5 text-yellow-400 flex-shrink-0" />
|
||||
<div className="text-sm text-yellow-400">
|
||||
<p className="font-medium">Girîng!</p>
|
||||
<ul className="list-disc list-inside text-xs mt-1 space-y-1">
|
||||
<li>
|
||||
Kêmtirîn: <strong>{network.minAmount} USDT</strong>
|
||||
</li>
|
||||
<li>Memo/Not qada de koda xwe binivîse</li>
|
||||
<li>Tenê USDT bişîne, tokenên din winda dibin</li>
|
||||
</ul>
|
||||
{/* TRC20 Warning */}
|
||||
{showTrc20Warning && (
|
||||
<div className="p-4 bg-yellow-500/10 border border-yellow-500/30 rounded-xl">
|
||||
<div className="flex gap-3">
|
||||
<AlertTriangle className="w-6 h-6 text-yellow-400 flex-shrink-0" />
|
||||
<div>
|
||||
<p className="text-sm text-yellow-400 font-medium mb-2">Dikkkat!</p>
|
||||
<p className="text-xs text-yellow-400/80 mb-3">{network.feeWarning}</p>
|
||||
<p className="text-xs text-yellow-400/80 mb-3">
|
||||
Mînak: 10 USDT bişîne → 7 wUSDT werbigire ($3 masraf)
|
||||
</p>
|
||||
<button
|
||||
onClick={() => {
|
||||
setTrc20Accepted(true);
|
||||
hapticImpact('medium');
|
||||
}}
|
||||
className="w-full py-2 bg-yellow-500/20 border border-yellow-500/50 rounded-lg text-yellow-400 text-sm font-medium"
|
||||
>
|
||||
Qebûl dikim, bi TRC20 bişîne
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Deposit Address */}
|
||||
<div className="bg-muted/50 rounded-xl p-4 space-y-4">
|
||||
{/* Address */}
|
||||
<div>
|
||||
<label className="text-xs text-muted-foreground">Navnîşana Depoyê</label>
|
||||
<div className="flex items-center gap-2 mt-1">
|
||||
<code className="flex-1 text-sm font-mono bg-background p-2 rounded-lg break-all">
|
||||
{network.address || 'Amade nîne'}
|
||||
</code>
|
||||
<button
|
||||
onClick={() => copyToClipboard(network.address, 'address')}
|
||||
disabled={!network.address}
|
||||
className="p-2 bg-background rounded-lg hover:bg-muted transition-colors"
|
||||
>
|
||||
{copied === 'address' ? (
|
||||
<CheckCircle className="w-5 h-5 text-green-400" />
|
||||
) : (
|
||||
<Copy className="w-5 h-5" />
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Memo/Reference */}
|
||||
<div>
|
||||
<label className="text-xs text-muted-foreground">Memo / Referans (PÊWÎST)</label>
|
||||
<div className="flex items-center gap-2 mt-1">
|
||||
{isLoading ? (
|
||||
<div className="flex-1 p-2 bg-background rounded-lg flex justify-center">
|
||||
<Loader2 className="w-5 h-5 animate-spin" />
|
||||
{/* Deposit Info - Show only when TRC20 is accepted or other networks */}
|
||||
{(selectedNetwork !== 'trc20' || trc20Accepted) && (
|
||||
<>
|
||||
{/* Important Notice */}
|
||||
<div className="p-3 bg-blue-500/10 border border-blue-500/30 rounded-lg">
|
||||
<div className="flex gap-2">
|
||||
<AlertCircle className="w-5 h-5 text-blue-400 flex-shrink-0" />
|
||||
<div className="text-sm text-blue-400">
|
||||
<p className="font-medium">Girîng!</p>
|
||||
<ul className="list-disc list-inside text-xs mt-1 space-y-1">
|
||||
<li>
|
||||
Kêmtirîn: <strong>{network.minDeposit} USDT</strong>
|
||||
</li>
|
||||
{selectedNetwork !== 'trc20' && (
|
||||
<li>Memo/Comment qada de koda xwe binivîse</li>
|
||||
)}
|
||||
<li>Tenê USDT bişîne, tokenên din winda dibin</li>
|
||||
{selectedNetwork === 'trc20' && (
|
||||
<li className="text-yellow-400">
|
||||
$3 masraf dê ji mîqdara we bê kêmkirin
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
) : (
|
||||
<code className="flex-1 text-lg font-mono font-bold bg-background p-2 rounded-lg text-center text-green-400">
|
||||
{depositCode || '---'}
|
||||
</code>
|
||||
)}
|
||||
<button
|
||||
onClick={() => copyToClipboard(depositCode, 'memo')}
|
||||
disabled={!depositCode || depositCode === '---'}
|
||||
className="p-2 bg-background rounded-lg hover:bg-muted transition-colors"
|
||||
>
|
||||
{copied === 'memo' ? (
|
||||
<CheckCircle className="w-5 h-5 text-green-400" />
|
||||
) : (
|
||||
<Copy className="w-5 h-5" />
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-xs text-red-400 mt-1">
|
||||
⚠️ Vê kodê di memo/not de binivîse, wekî din depoya te nayê nas kirin!
|
||||
|
||||
{/* Deposit Address */}
|
||||
<div className="bg-muted/50 rounded-xl p-4 space-y-4">
|
||||
{/* Address */}
|
||||
<div>
|
||||
<label className="text-xs text-muted-foreground">Navnîşana Depoyê</label>
|
||||
<div className="flex items-center gap-2 mt-1">
|
||||
{isLoading && selectedNetwork === 'trc20' ? (
|
||||
<div className="flex-1 p-2 bg-background rounded-lg flex justify-center">
|
||||
<Loader2 className="w-5 h-5 animate-spin" />
|
||||
</div>
|
||||
) : (
|
||||
<code className="flex-1 text-xs font-mono bg-background p-2 rounded-lg break-all">
|
||||
{currentAddress || 'Amade nîne'}
|
||||
</code>
|
||||
)}
|
||||
<button
|
||||
onClick={() => copyToClipboard(currentAddress, 'address')}
|
||||
disabled={!currentAddress}
|
||||
className="p-2 bg-background rounded-lg hover:bg-muted transition-colors"
|
||||
>
|
||||
{copied === 'address' ? (
|
||||
<CheckCircle className="w-5 h-5 text-green-400" />
|
||||
) : (
|
||||
<Copy className="w-5 h-5" />
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Memo/Reference - Not needed for TRC20 (unique address) */}
|
||||
{selectedNetwork !== 'trc20' && (
|
||||
<div>
|
||||
<label className="text-xs text-muted-foreground">
|
||||
Memo / Comment (PÊWÎST)
|
||||
</label>
|
||||
<div className="flex items-center gap-2 mt-1">
|
||||
{isLoading ? (
|
||||
<div className="flex-1 p-2 bg-background rounded-lg flex justify-center">
|
||||
<Loader2 className="w-5 h-5 animate-spin" />
|
||||
</div>
|
||||
) : (
|
||||
<code className="flex-1 text-lg font-mono font-bold bg-background p-2 rounded-lg text-center text-green-400">
|
||||
{depositCode || '---'}
|
||||
</code>
|
||||
)}
|
||||
<button
|
||||
onClick={() => copyToClipboard(depositCode, 'memo')}
|
||||
disabled={!depositCode || depositCode === '---'}
|
||||
className="p-2 bg-background rounded-lg hover:bg-muted transition-colors"
|
||||
>
|
||||
{copied === 'memo' ? (
|
||||
<CheckCircle className="w-5 h-5 text-green-400" />
|
||||
) : (
|
||||
<Copy className="w-5 h-5" />
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
<p className="text-xs text-red-400 mt-1">
|
||||
⚠️ Vê kodê di memo de binivîse, wekî din depoya te nayê nas kirin!
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{selectedNetwork === 'trc20' && (
|
||||
<p className="text-xs text-green-400">
|
||||
✅ Ev navnîşan tenê ya te ye. Memo ne pêwîst e.
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Steps */}
|
||||
<div className="bg-muted/30 rounded-xl p-4">
|
||||
<h4 className="text-sm font-medium mb-3">Çawa Depo Bikim?</h4>
|
||||
<ol className="text-xs text-muted-foreground space-y-2">
|
||||
<li className="flex gap-2">
|
||||
<span className="text-green-400 font-bold">1.</span>
|
||||
<span>Navnîşan kopî bike</span>
|
||||
</li>
|
||||
{selectedNetwork !== 'trc20' && (
|
||||
<li className="flex gap-2">
|
||||
<span className="text-green-400 font-bold">2.</span>
|
||||
<span>Memo kodê kopî bike</span>
|
||||
</li>
|
||||
)}
|
||||
<li className="flex gap-2">
|
||||
<span className="text-green-400 font-bold">
|
||||
{selectedNetwork === 'trc20' ? '2' : '3'}.
|
||||
</span>
|
||||
<span>
|
||||
{selectedNetwork === 'ton'
|
||||
? 'Telegram Wallet an cîzdana xwe veke'
|
||||
: selectedNetwork === 'polkadot'
|
||||
? 'Polkadot cîzdana xwe veke'
|
||||
: 'TronLink an cîzdana xwe veke'}
|
||||
</span>
|
||||
</li>
|
||||
<li className="flex gap-2">
|
||||
<span className="text-green-400 font-bold">
|
||||
{selectedNetwork === 'trc20' ? '3' : '4'}.
|
||||
</span>
|
||||
<span>USDT bişîne navnîşana jorîn</span>
|
||||
</li>
|
||||
<li className="flex gap-2">
|
||||
<span className="text-green-400 font-bold">
|
||||
{selectedNetwork === 'trc20' ? '4' : '5'}.
|
||||
</span>
|
||||
<span>wUSDT dê di nav çend hûrdeman de li hesabê te be</span>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
{/* Processing Time */}
|
||||
<p className="text-center text-xs text-muted-foreground">
|
||||
Dema pêvajoyê: ~1-5 hûrdem
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Steps */}
|
||||
<div className="bg-muted/30 rounded-xl p-4">
|
||||
<h4 className="text-sm font-medium mb-3">Çawa Depo Bikim?</h4>
|
||||
<ol className="text-xs text-muted-foreground space-y-2">
|
||||
<li className="flex gap-2">
|
||||
<span className="text-green-400 font-bold">1.</span>
|
||||
<span>Navnîşan û memo kopî bike</span>
|
||||
</li>
|
||||
<li className="flex gap-2">
|
||||
<span className="text-green-400 font-bold">2.</span>
|
||||
<span>Di cîzdana xwe de ({network.name}) USDT bişîne navnîşana jorîn</span>
|
||||
</li>
|
||||
<li className="flex gap-2">
|
||||
<span className="text-green-400 font-bold">3.</span>
|
||||
<span>
|
||||
<strong>MEMO qada de koda xwe binivîse!</strong>
|
||||
</span>
|
||||
</li>
|
||||
<li className="flex gap-2">
|
||||
<span className="text-green-400 font-bold">4.</span>
|
||||
<span>Piştî {network.confirmations} pejirandinê, wUSDT dê li Asset Hub be</span>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
{/* Processing Time */}
|
||||
<p className="text-center text-xs text-muted-foreground">
|
||||
Dema pêvajoyê: ~5-30 hûrdem li gorî torê
|
||||
</p>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "1.0.169",
|
||||
"buildTime": "2026-02-07T22:14:22.046Z",
|
||||
"buildNumber": 1770502462047
|
||||
"version": "1.0.170",
|
||||
"buildTime": "2026-02-07T23:00:20.055Z",
|
||||
"buildNumber": 1770505220056
|
||||
}
|
||||
|
||||
@@ -0,0 +1,290 @@
|
||||
/**
|
||||
* Get Deposit Info - Returns user's deposit code and TRC20 HD wallet address
|
||||
*/
|
||||
|
||||
import { serve } from 'https://deno.land/std@0.177.0/http/server.ts';
|
||||
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';
|
||||
import { createHmac } from 'https://deno.land/std@0.177.0/node/crypto.ts';
|
||||
import { HDKey } from 'https://esm.sh/@scure/bip32@1.3.2';
|
||||
import * as bip39 from 'https://esm.sh/@scure/bip39@1.2.1';
|
||||
import { wordlist } from 'https://esm.sh/@scure/bip39@1.2.1/wordlists/english';
|
||||
import { keccak_256 } from 'https://esm.sh/@noble/hashes@1.3.2/sha3';
|
||||
import { sha256 } from 'https://esm.sh/@noble/hashes@1.3.2/sha256';
|
||||
import { bytesToHex, hexToBytes } from 'https://esm.sh/@noble/hashes@1.3.2/utils';
|
||||
import { secp256k1 } from 'https://esm.sh/@noble/curves@1.2.0/secp256k1';
|
||||
|
||||
const ALLOWED_ORIGIN = 'https://telegram.pezkuwichain.io';
|
||||
const BASE58_ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
|
||||
|
||||
function getCorsHeaders(): Record<string, string> {
|
||||
return {
|
||||
'Access-Control-Allow-Origin': ALLOWED_ORIGIN,
|
||||
'Access-Control-Allow-Headers':
|
||||
'authorization, x-client-info, apikey, content-type, x-supabase-client-platform',
|
||||
'Access-Control-Allow-Methods': 'POST, OPTIONS',
|
||||
};
|
||||
}
|
||||
|
||||
interface TelegramUser {
|
||||
id: number;
|
||||
first_name: string;
|
||||
}
|
||||
|
||||
function validateInitData(initData: string, botToken: string): TelegramUser | null {
|
||||
try {
|
||||
const params = new URLSearchParams(initData);
|
||||
const hash = params.get('hash');
|
||||
if (!hash) return null;
|
||||
|
||||
params.delete('hash');
|
||||
|
||||
const sortedParams = Array.from(params.entries())
|
||||
.sort(([a], [b]) => a.localeCompare(b))
|
||||
.map(([key, value]) => `${key}=${value}`)
|
||||
.join('\n');
|
||||
|
||||
const secretKey = createHmac('sha256', 'WebAppData').update(botToken).digest();
|
||||
const calculatedHash = createHmac('sha256', secretKey).update(sortedParams).digest('hex');
|
||||
|
||||
if (calculatedHash !== hash) return null;
|
||||
|
||||
const authDate = parseInt(params.get('auth_date') || '0');
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
if (now - authDate > 86400) return null;
|
||||
|
||||
const userStr = params.get('user');
|
||||
if (!userStr) return null;
|
||||
|
||||
return JSON.parse(userStr) as TelegramUser;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function generateDepositCode(): string {
|
||||
const chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
|
||||
let result = 'PEZ-';
|
||||
for (let i = 0; i < 8; i++) {
|
||||
result += chars.charAt(Math.floor(Math.random() * chars.length));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Base58Check encode
|
||||
function base58CheckEncode(payload: Uint8Array): string {
|
||||
// Double SHA256 for checksum
|
||||
const hash1 = sha256(payload);
|
||||
const hash2 = sha256(hash1);
|
||||
const checksum = hash2.slice(0, 4);
|
||||
|
||||
// Combine payload and checksum
|
||||
const data = new Uint8Array(payload.length + 4);
|
||||
data.set(payload);
|
||||
data.set(checksum, payload.length);
|
||||
|
||||
// Count leading zeros
|
||||
let zeros = 0;
|
||||
for (let i = 0; i < data.length && data[i] === 0; i++) {
|
||||
zeros++;
|
||||
}
|
||||
|
||||
// Convert to base58
|
||||
let num = BigInt('0x' + bytesToHex(data));
|
||||
let result = '';
|
||||
|
||||
while (num > 0n) {
|
||||
const remainder = Number(num % 58n);
|
||||
result = BASE58_ALPHABET[remainder] + result;
|
||||
num = num / 58n;
|
||||
}
|
||||
|
||||
// Add leading '1's for zeros
|
||||
return '1'.repeat(zeros) + result;
|
||||
}
|
||||
|
||||
// Derive TRC20 address from HD wallet
|
||||
function deriveTronAddress(mnemonic: string, index: number): string {
|
||||
try {
|
||||
// Convert mnemonic to seed
|
||||
const seed = bip39.mnemonicToSeedSync(mnemonic, '');
|
||||
|
||||
// Create HD key from seed
|
||||
const hdKey = HDKey.fromMasterSeed(seed);
|
||||
|
||||
// Derive path: m/44'/195'/0'/0/{index}
|
||||
// 195 is TRON's coin type
|
||||
const derivedKey = hdKey.derive(`m/44'/195'/0'/0/${index}`);
|
||||
|
||||
if (!derivedKey.privateKey) {
|
||||
throw new Error('Failed to derive private key');
|
||||
}
|
||||
|
||||
// Get uncompressed public key
|
||||
const publicKey = secp256k1.getPublicKey(derivedKey.privateKey, false);
|
||||
|
||||
// Skip the 0x04 prefix and hash with keccak256
|
||||
const publicKeyWithoutPrefix = publicKey.slice(1);
|
||||
const hash = keccak_256(publicKeyWithoutPrefix);
|
||||
|
||||
// Take last 20 bytes for address
|
||||
const addressBytes = hash.slice(-20);
|
||||
|
||||
// Add TRON mainnet prefix (0x41)
|
||||
const addressWithPrefix = new Uint8Array(21);
|
||||
addressWithPrefix[0] = 0x41;
|
||||
addressWithPrefix.set(addressBytes, 1);
|
||||
|
||||
// Base58Check encode
|
||||
return base58CheckEncode(addressWithPrefix);
|
||||
} catch (err) {
|
||||
console.error('Error deriving TRON address:', err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
serve(async (req) => {
|
||||
const corsHeaders = getCorsHeaders();
|
||||
|
||||
if (req.method === 'OPTIONS') {
|
||||
return new Response('ok', { headers: corsHeaders });
|
||||
}
|
||||
|
||||
try {
|
||||
const body = await req.json();
|
||||
const { initData } = body;
|
||||
|
||||
if (!initData) {
|
||||
return new Response(JSON.stringify({ error: 'Missing initData' }), {
|
||||
status: 400,
|
||||
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
|
||||
});
|
||||
}
|
||||
|
||||
const supabaseUrl = Deno.env.get('SUPABASE_URL')!;
|
||||
const supabaseServiceKey = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!;
|
||||
const botToken = Deno.env.get('TELEGRAM_BOT_TOKEN');
|
||||
const tronHdMnemonic = Deno.env.get('DEPOSIT_TRON_HD_MNEMONIC');
|
||||
|
||||
if (!botToken) {
|
||||
return new Response(JSON.stringify({ error: 'Server configuration error' }), {
|
||||
status: 500,
|
||||
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
|
||||
});
|
||||
}
|
||||
|
||||
const telegramUser = validateInitData(initData, botToken);
|
||||
if (!telegramUser) {
|
||||
return new Response(JSON.stringify({ error: 'Invalid Telegram data' }), {
|
||||
status: 401,
|
||||
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
|
||||
});
|
||||
}
|
||||
|
||||
const supabase = createClient(supabaseUrl, supabaseServiceKey, {
|
||||
auth: { autoRefreshToken: false, persistSession: false },
|
||||
});
|
||||
|
||||
// Get or create user
|
||||
let userId: string;
|
||||
let depositIndex: number;
|
||||
|
||||
const { data: existingUser } = await supabase
|
||||
.from('tg_users')
|
||||
.select('id, deposit_index')
|
||||
.eq('telegram_id', telegramUser.id)
|
||||
.single();
|
||||
|
||||
if (existingUser) {
|
||||
userId = existingUser.id;
|
||||
depositIndex = existingUser.deposit_index ?? -1;
|
||||
|
||||
// Ensure deposit_index exists
|
||||
if (depositIndex < 0) {
|
||||
// Get next available index
|
||||
const { data: maxIndexData } = await supabase
|
||||
.from('tg_users')
|
||||
.select('deposit_index')
|
||||
.not('deposit_index', 'is', null)
|
||||
.order('deposit_index', { ascending: false })
|
||||
.limit(1)
|
||||
.single();
|
||||
|
||||
depositIndex = (maxIndexData?.deposit_index ?? -1) + 1;
|
||||
|
||||
await supabase.from('tg_users').update({ deposit_index: depositIndex }).eq('id', userId);
|
||||
}
|
||||
} else {
|
||||
// Get next available index
|
||||
const { data: maxIndexData } = await supabase
|
||||
.from('tg_users')
|
||||
.select('deposit_index')
|
||||
.not('deposit_index', 'is', null)
|
||||
.order('deposit_index', { ascending: false })
|
||||
.limit(1)
|
||||
.single();
|
||||
|
||||
depositIndex = (maxIndexData?.deposit_index ?? -1) + 1;
|
||||
|
||||
const { data: newUser, error: createError } = await supabase
|
||||
.from('tg_users')
|
||||
.insert({
|
||||
telegram_id: telegramUser.id,
|
||||
first_name: telegramUser.first_name,
|
||||
deposit_index: depositIndex,
|
||||
})
|
||||
.select('id')
|
||||
.single();
|
||||
|
||||
if (createError || !newUser) {
|
||||
return new Response(JSON.stringify({ error: 'Failed to create user' }), {
|
||||
status: 500,
|
||||
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
|
||||
});
|
||||
}
|
||||
userId = newUser.id;
|
||||
}
|
||||
|
||||
// Get or create deposit code
|
||||
let depositCode: string;
|
||||
const { data: existingCode } = await supabase
|
||||
.from('tg_user_deposit_codes')
|
||||
.select('code')
|
||||
.eq('user_id', userId)
|
||||
.single();
|
||||
|
||||
if (existingCode) {
|
||||
depositCode = existingCode.code;
|
||||
} else {
|
||||
depositCode = generateDepositCode();
|
||||
await supabase.from('tg_user_deposit_codes').insert({
|
||||
user_id: userId,
|
||||
code: depositCode,
|
||||
});
|
||||
}
|
||||
|
||||
// Generate TRC20 address from HD wallet
|
||||
let trc20Address = '';
|
||||
if (tronHdMnemonic && depositIndex >= 0) {
|
||||
try {
|
||||
trc20Address = deriveTronAddress(tronHdMnemonic, depositIndex);
|
||||
} catch (err) {
|
||||
console.error('Error deriving TRC20 address:', err);
|
||||
}
|
||||
}
|
||||
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
code: depositCode,
|
||||
trc20Address,
|
||||
depositIndex,
|
||||
}),
|
||||
{ headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
|
||||
);
|
||||
} catch (err) {
|
||||
console.error('Get deposit info error:', err);
|
||||
return new Response(JSON.stringify({ error: 'Internal server error' }), {
|
||||
status: 500,
|
||||
headers: { ...corsHeaders, 'Content-Type': 'application/json' },
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,201 @@
|
||||
/**
|
||||
* Process Deposits - Cron job to check for incoming USDT deposits
|
||||
* Checks TRC20 (TRON) and Polkadot Asset Hub for incoming transfers
|
||||
* Then transfers wUSDT to user's Asset Hub address
|
||||
*/
|
||||
|
||||
import { serve } from 'https://deno.land/std@0.177.0/http/server.ts';
|
||||
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';
|
||||
|
||||
const TRON_API = 'https://api.trongrid.io';
|
||||
const USDT_TRC20_CONTRACT = 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t'; // USDT TRC20 contract
|
||||
|
||||
interface TRC20Transfer {
|
||||
transaction_id: string;
|
||||
from: string;
|
||||
to: string;
|
||||
value: string;
|
||||
block_timestamp: number;
|
||||
}
|
||||
|
||||
interface DepositCode {
|
||||
code: string;
|
||||
user_id: string;
|
||||
user_address: string;
|
||||
}
|
||||
|
||||
serve(async (req) => {
|
||||
// Verify this is called by Supabase cron or with secret
|
||||
const authHeader = req.headers.get('Authorization');
|
||||
const cronSecret = Deno.env.get('CRON_SECRET');
|
||||
|
||||
if (cronSecret && authHeader !== `Bearer ${cronSecret}`) {
|
||||
// Also allow service role
|
||||
const supabaseServiceKey = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY');
|
||||
if (authHeader !== `Bearer ${supabaseServiceKey}`) {
|
||||
return new Response(JSON.stringify({ error: 'Unauthorized' }), {
|
||||
status: 401,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const supabaseUrl = Deno.env.get('SUPABASE_URL')!;
|
||||
const supabaseServiceKey = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!;
|
||||
const tronAddress = Deno.env.get('DEPOSIT_TRON_ADDRESS');
|
||||
const polkadotAddress = Deno.env.get('DEPOSIT_POLKADOT_ADDRESS');
|
||||
|
||||
const supabase = createClient(supabaseUrl, supabaseServiceKey, {
|
||||
auth: { autoRefreshToken: false, persistSession: false },
|
||||
});
|
||||
|
||||
const results = {
|
||||
trc20: { checked: 0, found: 0, processed: 0, errors: [] as string[] },
|
||||
polkadot: { checked: 0, found: 0, processed: 0, errors: [] as string[] },
|
||||
};
|
||||
|
||||
// Get all deposit codes with user addresses
|
||||
const { data: depositCodes } = await supabase.from('tg_user_deposit_codes').select(`
|
||||
code,
|
||||
user_id,
|
||||
tg_users!inner(wallet_address)
|
||||
`);
|
||||
|
||||
const codeMap = new Map<string, { userId: string; walletAddress: string }>();
|
||||
if (depositCodes) {
|
||||
for (const dc of depositCodes) {
|
||||
const userAddress = (dc as any).tg_users?.wallet_address;
|
||||
if (userAddress) {
|
||||
codeMap.set(dc.code, { userId: dc.user_id, walletAddress: userAddress });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== TRC20 DEPOSITS ====================
|
||||
if (tronAddress) {
|
||||
try {
|
||||
// Get recent TRC20 transfers to our deposit address
|
||||
const response = await fetch(
|
||||
`${TRON_API}/v1/accounts/${tronAddress}/transactions/trc20?limit=50&contract_address=${USDT_TRC20_CONTRACT}`,
|
||||
{
|
||||
headers: { 'TRON-PRO-API-KEY': Deno.env.get('TRONGRID_API_KEY') || '' },
|
||||
}
|
||||
);
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
const transfers = (data.data || []) as TRC20Transfer[];
|
||||
results.trc20.checked = transfers.length;
|
||||
|
||||
for (const tx of transfers) {
|
||||
// Only incoming transfers
|
||||
if (tx.to.toLowerCase() !== tronAddress.toLowerCase()) continue;
|
||||
|
||||
// Check if already processed
|
||||
const { data: existing } = await supabase
|
||||
.from('tg_deposits')
|
||||
.select('id')
|
||||
.eq('tx_hash', tx.transaction_id)
|
||||
.single();
|
||||
|
||||
if (existing) continue;
|
||||
|
||||
results.trc20.found++;
|
||||
|
||||
// USDT has 6 decimals
|
||||
const amount = parseInt(tx.value) / 1e6;
|
||||
|
||||
// For TRC20, we need to check the memo in the transaction
|
||||
// Unfortunately, TRC20 transfers don't have memo field directly
|
||||
// We'll need to match by amount or create pending deposits that admin confirms
|
||||
|
||||
// Create pending deposit for manual review or amount matching
|
||||
const { error: insertError } = await supabase.from('tg_deposits').insert({
|
||||
user_id: null, // Will be matched later
|
||||
network: 'trc20',
|
||||
amount,
|
||||
tx_hash: tx.transaction_id,
|
||||
status: 'confirming',
|
||||
created_at: new Date(tx.block_timestamp).toISOString(),
|
||||
});
|
||||
|
||||
if (insertError) {
|
||||
results.trc20.errors.push(`Insert error: ${insertError.message}`);
|
||||
} else {
|
||||
results.trc20.processed++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
results.trc20.errors.push(`TRC20 error: ${err}`);
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== POLKADOT DEPOSITS ====================
|
||||
if (polkadotAddress) {
|
||||
try {
|
||||
// Use Subscan API for Polkadot Asset Hub
|
||||
const subscanResponse = await fetch(
|
||||
'https://assethub-polkadot.api.subscan.io/api/v2/scan/transfers',
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-API-Key': Deno.env.get('SUBSCAN_API_KEY') || '',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
address: polkadotAddress,
|
||||
direction: 'received',
|
||||
row: 50,
|
||||
page: 0,
|
||||
asset_symbol: 'USDT',
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
||||
if (subscanResponse.ok) {
|
||||
const data = await subscanResponse.json();
|
||||
const transfers = data.data?.transfers || [];
|
||||
results.polkadot.checked = transfers.length;
|
||||
|
||||
for (const tx of transfers) {
|
||||
// Check if already processed
|
||||
const { data: existing } = await supabase
|
||||
.from('tg_deposits')
|
||||
.select('id')
|
||||
.eq('tx_hash', tx.hash)
|
||||
.single();
|
||||
|
||||
if (existing) continue;
|
||||
|
||||
results.polkadot.found++;
|
||||
|
||||
// Polkadot USDT has 6 decimals
|
||||
const amount = parseFloat(tx.amount) / 1e6;
|
||||
|
||||
// Create pending deposit
|
||||
const { error: insertError } = await supabase.from('tg_deposits').insert({
|
||||
user_id: null,
|
||||
network: 'polkadot',
|
||||
amount,
|
||||
tx_hash: tx.hash,
|
||||
status: 'confirming',
|
||||
created_at: new Date(tx.block_timestamp * 1000).toISOString(),
|
||||
});
|
||||
|
||||
if (insertError) {
|
||||
results.polkadot.errors.push(`Insert error: ${insertError.message}`);
|
||||
} else {
|
||||
results.polkadot.processed++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
results.polkadot.errors.push(`Polkadot error: ${err}`);
|
||||
}
|
||||
}
|
||||
|
||||
return new Response(JSON.stringify({ success: true, results }), {
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
-- Add deposit_index column for TRC20 HD wallet derivation
|
||||
ALTER TABLE tg_users ADD COLUMN IF NOT EXISTS deposit_index INTEGER UNIQUE;
|
||||
|
||||
-- Create index for faster lookups
|
||||
CREATE INDEX IF NOT EXISTS idx_users_deposit_index ON tg_users(deposit_index);
|
||||
|
||||
-- Assign deposit_index to existing users
|
||||
WITH numbered_users AS (
|
||||
SELECT id, ROW_NUMBER() OVER (ORDER BY created_at) - 1 as idx
|
||||
FROM tg_users
|
||||
WHERE deposit_index IS NULL
|
||||
)
|
||||
UPDATE tg_users
|
||||
SET deposit_index = numbered_users.idx
|
||||
FROM numbered_users
|
||||
WHERE tg_users.id = numbered_users.id;
|
||||
Reference in New Issue
Block a user