Shawn Lu 1 年間 前
コミット
9bbaa5fc08
9 ファイル変更165 行追加88 行削除
  1. 2 1
      package.json
  2. 1 1
      src/BaseClient.ts
  3. 95 0
      src/faucet/captcha.ts
  4. 35 4
      src/faucet/faucet.ts
  5. 0 25
      src/faucet/faucetTuc.ts
  6. 0 35
      src/faucet/recaptcha.ts
  7. 2 3
      src/models/Status.ts
  8. 9 4
      src/test.ts
  9. 21 15
      yarn.lock

+ 2 - 1
package.json

@@ -24,7 +24,7 @@
     "prestart": "npm run build",
     "start": "node build/src/main.js",
     "testShawn": "npm run build && node build/src/test.js",
-    "faucetTuc": "npm run build && node build/src/faucet/faucetTuc.js",
+    "faucet": "npm run build && node build/src/faucet/faucet.js",
     "clean": "rimraf coverage build tmp",
     "prebuild": "yarn prisma generate",
     "build": "tsc -p tsconfig.json && tsc-alias",
@@ -39,6 +39,7 @@
   "dependencies": {
     "@initia/initia.js": "^0.1.51",
     "@prisma/client": "^5.14.0",
+    "shawnlu96-altcha-lib": "0.3.4",
     "axios": "^1.6.8",
     "dotenv": "^16.4.5",
     "https-proxy-agent": "^7.0.4",

+ 1 - 1
src/BaseClient.ts

@@ -25,7 +25,7 @@ export abstract class BaseClient {
 
     const requester = new APIRequester(getProxyUrl())
     this.lcd = new LCDClient(
-      'https://api-initia-testnet.whispernode.com/',
+      'https://api.initiation.test.pfc.zone',
       {
         chainId: 'initiation-1',
       },

+ 95 - 0
src/faucet/captcha.ts

@@ -0,0 +1,95 @@
+import axios, { AxiosInstance } from 'axios'
+import dotenv from 'dotenv'
+import polly from 'polly-js'
+import { solveChallenge } from 'shawnlu96-altcha-lib'
+dotenv.config()
+
+const googlekey = '6LdLhtYpAAAAAOe1xmceNR-i6MTtzq7N6AYztoVI'
+const hCaptchaKey = '04d28d90-d5b9-4a90-94e5-a12c595bd4e2'
+const captchaApiKey = process.env.CAPTCHA_API_KEY
+
+export async function getRecaptcha(address: string) {
+  return await polly()
+    .waitAndRetry(2)
+    .executeForPromise(async () => {
+      const res = await axios.post('https://2captcha.com/in.php', {
+        method: 'userrecaptcha',
+        key: captchaApiKey,
+        googlekey,
+        pageUrl: `https://faucet.testnet.initia.xyz/?address=${address}`,
+        json: 1,
+        action: 'verify',
+      })
+      const request = res.data.request
+      return await polly()
+        .waitAndRetry([10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000])
+        .executeForPromise(async () => {
+          const captchaRes = await axios.get(
+            `https://2captcha.com/res.php?key=${captchaApiKey}&action=get&id=${request}&json=1`,
+          )
+          const token = captchaRes.data.request
+          console.log(token)
+          if (token === 'CAPCHA_NOT_READY') throw new Error('CAPCHA_NOT_READY')
+          if (!token) throw new Error('no result')
+          return token
+        })
+    })
+}
+
+export async function getAltchaPayload(client: AxiosInstance) {
+  return await polly()
+    .waitAndRetry(5)
+    .executeForPromise(async () => {
+      // console.log('retry:', info.count)
+      const challengeResp = await client.get(
+        'https://faucet-api.initiation-1.initia.xyz/create_challenge',
+      )
+      const challenge = challengeResp.data
+      // console.log(challenge)
+      const { promise } = solveChallenge(
+        challenge.challenge,
+        challenge.salt,
+        challenge.max,
+        challenge.start,
+      )
+      const solution = await promise
+      const payload = {
+        algorithm: 'SHA-256',
+        challenge: challenge.challenge,
+        number: solution.number,
+        salt: challenge.salt,
+        signature: challenge.signature,
+        took: solution.took,
+      }
+      console.log('challenge resolved')
+      return btoa(JSON.stringify(payload))
+    })
+}
+
+export async function solveHCaptcha(address: string) {
+  return await polly()
+    .waitAndRetry(2)
+    .executeForPromise(async () => {
+      const res = await axios.post('https://2captcha.com/in.php', {
+        method: 'hcaptcha',
+        sitekey: hCaptchaKey,
+        key: captchaApiKey,
+        pageUrl: `https://faucet.testnet.initia.xyz/?address=${address}`,
+        json: 1,
+      })
+      const request = res.data.request
+      return await polly()
+        .waitAndRetry([10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000])
+        .executeForPromise(async () => {
+          const captchaRes = await axios.get(
+            `https://2captcha.com/res.php?key=${captchaApiKey}&action=get&id=${request}&json=1`,
+          )
+          const token = captchaRes.data.request
+          // console.log(token)
+          if (token === 'CAPCHA_NOT_READY') throw new Error('CAPCHA_NOT_READY')
+          if (!token) throw new Error('no result')
+          console.log('hCaptcha solved')
+          return token
+        })
+    })
+}

+ 35 - 4
src/faucet/faucet.ts

@@ -1,16 +1,20 @@
-import { getAxiosClient } from '../utils'
-import { getCaptcha } from './recaptcha'
+import { forEachAsync, getAxiosClient } from '../utils'
+import { getAltchaPayload, getRecaptcha, solveHCaptcha } from './captcha'
+import { DBClient } from '../singletons'
+import { Status } from '../models/Status'
 
 export async function faucetAccount(address: string) {
   const client = getAxiosClient(true)
-  const captcha = await getCaptcha(address)
+  const altcha = await getAltchaPayload(client)
+  const hCaptcha = await solveHCaptcha(address)
   try {
     const res = await client.post(
       `https://faucet-api.initiation-1.initia.xyz/claim`,
       {
         address: address,
+        altcha_payload: altcha,
         denom: 'uinit',
-        response: captcha,
+        h_captcha: hCaptcha,
       },
     )
     console.log(JSON.stringify(res.data))
@@ -19,3 +23,30 @@ export async function faucetAccount(address: string) {
     throw e
   }
 }
+
+async function startFaucet(concurrency = 10) {
+  const accounts = await DBClient.instance.account.findMany({
+    where: {
+      status: Status.Inited,
+    },
+  })
+  await forEachAsync(accounts, concurrency, async (account, index) => {
+    console.log(`${index}/${accounts.length}: processing ${account.address}`)
+    try {
+      await faucetAccount(account.address)
+
+      await DBClient.instance.account.update({
+        where: { id: account.id },
+        data: { status: Status.Fauceted },
+      })
+    } catch (e) {
+      console.log(e)
+      await DBClient.instance.account.update({
+        where: { id: account.id },
+        data: { status: Status.FaucetFailed, message: e.message },
+      })
+    }
+  })
+}
+
+await startFaucet(40)

+ 0 - 25
src/faucet/faucetTuc.ts

@@ -21,29 +21,4 @@ async function faucetTuc(address: string) {
     })
 }
 
-async function startFaucetTuc(concurrency = 10) {
-  const accounts = await DBClient.instance.account.findMany({
-    where: {
-      status: Status.Inited,
-    },
-  })
-  await forEachAsync(accounts, concurrency, async (account, index) => {
-    console.log(`${index}/${accounts.length}: processing ${account.address}`)
-    try {
-      await faucetTuc(account.address)
 
-      await DBClient.instance.account.update({
-        where: { id: account.id },
-        data: { status: Status.TucFauceted },
-      })
-    } catch (e) {
-      console.log(e)
-      await DBClient.instance.account.update({
-        where: { id: account.id },
-        data: { status: Status.TucFaucetFailed, message: e.message },
-      })
-    }
-  })
-}
-
-await startFaucetTuc(40)

+ 0 - 35
src/faucet/recaptcha.ts

@@ -1,35 +0,0 @@
-import axios from 'axios'
-import dotenv from 'dotenv'
-import polly from 'polly-js'
-dotenv.config()
-
-const googlekey = '6LdLhtYpAAAAAOe1xmceNR-i6MTtzq7N6AYztoVI'
-const captchaApiKey = process.env.CAPTCHA_API_KEY
-
-export async function getCaptcha(address: string) {
-  return await polly()
-    .waitAndRetry(2)
-    .executeForPromise(async () => {
-      const res = await axios.post('https://2captcha.com/in.php', {
-        method: 'userrecaptcha',
-        key: captchaApiKey,
-        googlekey,
-        pageUrl: `https://faucet.testnet.initia.xyz/?address=${address}`,
-        json: 1,
-        action: 'verify',
-      })
-      const request = res.data.request
-      return await polly()
-        .waitAndRetry([10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000])
-        .executeForPromise(async () => {
-          const captchaRes = await axios.get(
-            `https://2captcha.com/res.php?key=${captchaApiKey}&action=get&id=${request}&json=1`,
-          )
-          const token = captchaRes.data.request
-          console.log(token)
-          if (token === 'CAPCHA_NOT_READY') throw new Error('CAPCHA_NOT_READY')
-          if (!token) throw new Error('no result')
-          return token
-        })
-    })
-}

+ 2 - 3
src/models/Status.ts

@@ -1,6 +1,5 @@
 export const Status = {
   Inited: 0,
-  TucFauceted: 1,
-  InitiaFauceted: 2,
-  TucFaucetFailed: -1,
+  Fauceted: 1,
+  FaucetFailed: -1,
 }

+ 9 - 4
src/test.ts

@@ -1,10 +1,12 @@
-import { getCaptcha } from './faucet/recaptcha'
 import { faucetAccount } from './faucet/faucet'
 
 import { MnemonicKey } from '@initia/initia.js'
 import { InitiaClient } from './InitiaClient'
 import polly from 'polly-js'
 import { DBClient } from './singletons'
+import { solveChallenge } from 'shawnlu96-altcha-lib'
+import { getAxiosClient } from './utils'
+import { getAltchaPayload, solveHCaptcha } from './faucet/captcha'
 
 // await polly()
 //   .waitAndRetry(4)
@@ -29,7 +31,10 @@ async function createAccounts(count: number) {
   await DBClient.instance.account.createMany({ data: accounts })
 }
 
-await createAccounts(20000)
-
-
+// await createAccounts(10000)
+// await faucetAccount('init1xj0ekwu5n3t4c8aj2xfxr9l94lwr0sssl4rkxy')
 
+// const client = new InitiaClient(
+//   'scheme address way popular shrug fall rail eyebrow buzz learn cross involve spatial rookie ostrich grocery chest ice glory security slogan summer also comfort',
+// )
+// console.log(client.key.accAddress)

+ 21 - 15
yarn.lock

@@ -260,22 +260,22 @@
 
 "@prisma/client@^5.14.0":
   version "5.14.0"
-  resolved "https://registry.yarnpkg.com/@prisma/client/-/client-5.14.0.tgz#dadca5bb1137ddcebb454bbdaf89423823d3363f"
+  resolved "https://registry.npmjs.org/@prisma/client/-/client-5.14.0.tgz"
   integrity sha512-akMSuyvLKeoU4LeyBAUdThP/uhVP3GuLygFE3MlYzaCb3/J8SfsYBE5PkaFuLuVpLyA6sFoW+16z/aPhNAESqg==
 
 "@prisma/debug@5.14.0":
   version "5.14.0"
-  resolved "https://registry.yarnpkg.com/@prisma/debug/-/debug-5.14.0.tgz#1227c705893c38284f7c63d72441480ebaa12605"
+  resolved "https://registry.npmjs.org/@prisma/debug/-/debug-5.14.0.tgz"
   integrity sha512-iq56qBZuFfX3fCxoxT8gBX33lQzomBU0qIUaEj1RebsKVz1ob/BVH1XSBwwwvRVtZEV1b7Fxx2eVu34Ge/mg3w==
 
 "@prisma/engines-version@5.14.0-25.e9771e62de70f79a5e1c604a2d7c8e2a0a874b48":
   version "5.14.0-25.e9771e62de70f79a5e1c604a2d7c8e2a0a874b48"
-  resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-5.14.0-25.e9771e62de70f79a5e1c604a2d7c8e2a0a874b48.tgz#019c3c75a5c3276e580685fe48cdbfd181176858"
+  resolved "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.14.0-25.e9771e62de70f79a5e1c604a2d7c8e2a0a874b48.tgz"
   integrity sha512-ip6pNkRo1UxWv+6toxNcYvItNYaqQjXdFNGJ+Nuk2eYtRoEdoF13wxo7/jsClJFFenMPVNVqXQDV0oveXnR1cA==
 
 "@prisma/engines@5.14.0":
   version "5.14.0"
-  resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-5.14.0.tgz#2ee91dd2220a726c27c906fbea788bbb3efdac6e"
+  resolved "https://registry.npmjs.org/@prisma/engines/-/engines-5.14.0.tgz"
   integrity sha512-lgxkKZ6IEygVcw6IZZUlPIfLQ9hjSYAtHjZ5r64sCLDgVzsPFCi2XBBJgzPMkOQ5RHzUD4E/dVdpn9+ez8tk1A==
   dependencies:
     "@prisma/debug" "5.14.0"
@@ -285,7 +285,7 @@
 
 "@prisma/fetch-engine@5.14.0":
   version "5.14.0"
-  resolved "https://registry.yarnpkg.com/@prisma/fetch-engine/-/fetch-engine-5.14.0.tgz#45297c118d4ec3fea55129886edd5a429da1f6da"
+  resolved "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.14.0.tgz"
   integrity sha512-VrheA9y9DMURK5vu8OJoOgQpxOhas3qF0IBHJ8G/0X44k82kc8E0w98HCn2nhnbOOMwbWsJWXfLC2/F8n5u0gQ==
   dependencies:
     "@prisma/debug" "5.14.0"
@@ -294,7 +294,7 @@
 
 "@prisma/get-platform@5.14.0":
   version "5.14.0"
-  resolved "https://registry.yarnpkg.com/@prisma/get-platform/-/get-platform-5.14.0.tgz#69112d3dde61905f59a65ed818f153e153ca40f0"
+  resolved "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.14.0.tgz"
   integrity sha512-/yAyBvcEjRv41ynZrhdrPtHgk47xLRRq/o5eWGcUpBJ1YrUZTYB8EoPiopnP7iQrMATK8stXQdPOoVlrzuTQZw==
   dependencies:
     "@prisma/debug" "5.14.0"
@@ -900,7 +900,7 @@ doctrine@^3.0.0:
 
 dotenv@^16.4.5:
   version "16.4.5"
-  resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f"
+  resolved "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz"
   integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==
 
 eastasianwidth@^0.2.0:
@@ -1172,7 +1172,7 @@ fs.realpath@^1.0.0:
 
 fsevents@~2.3.2:
   version "2.3.3"
-  resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
+  resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz"
   integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
 
 glob-parent@^5.1.2, glob-parent@~5.1.2:
@@ -1613,7 +1613,7 @@ node-addon-api@^5.0.0:
 
 node-cron@^3.0.3:
   version "3.0.3"
-  resolved "https://registry.yarnpkg.com/node-cron/-/node-cron-3.0.3.tgz#c4bc7173dd96d96c50bdb51122c64415458caff2"
+  resolved "https://registry.npmjs.org/node-cron/-/node-cron-3.0.3.tgz"
   integrity sha512-dOal67//nohNgYWb+nWmg5dkFdIwDm8EpeGYMekPMrngV3637lqnX0lbUcCtgibHTz6SEz7DAIjKvKDFYCnO1A==
   dependencies:
     uuid "8.3.2"
@@ -1697,9 +1697,9 @@ path-type@^4.0.0:
   integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
 
 picocolors@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz"
-  integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
+  version "1.0.1"
+  resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz"
+  integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==
 
 picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1:
   version "2.3.1"
@@ -1715,7 +1715,7 @@ plimit-lit@^1.2.6:
 
 polly-js@^1.8.3:
   version "1.8.3"
-  resolved "https://registry.yarnpkg.com/polly-js/-/polly-js-1.8.3.tgz#c1bfe878f676a78146e394a95b41b4ba5143300c"
+  resolved "https://registry.npmjs.org/polly-js/-/polly-js-1.8.3.tgz"
   integrity sha512-pFgSsipKs5bxtXMM+Vfw2p8kOEZhJ+Z9xDZLbiMjjw57WZdlg+6eTZdSIHDycNii+4+7xmzCfryQVIqwgeYX4g==
 
 prelude-ls@^1.2.1:
@@ -1746,7 +1746,7 @@ pretty-format@^29.0.0, pretty-format@^29.7.0:
 
 prisma@^5.14.0:
   version "5.14.0"
-  resolved "https://registry.yarnpkg.com/prisma/-/prisma-5.14.0.tgz#ffc4696a43b044b636c3303b7aa98c13c2ade4dd"
+  resolved "https://registry.npmjs.org/prisma/-/prisma-5.14.0.tgz"
   integrity sha512-gCNZco7y5XtjrnQYeDJTiVZmT/ncqCr5RY1/Cf8X2wgLRmyh9ayPAGBNziI4qEE4S6SxCH5omQLVo9lmURaJ/Q==
   dependencies:
     "@prisma/engines" "5.14.0"
@@ -1883,6 +1883,11 @@ sha.js@^2.4.0, sha.js@^2.4.8:
     inherits "^2.0.1"
     safe-buffer "^5.0.1"
 
+shawnlu96-altcha-lib@0.3.4:
+  version "0.3.4"
+  resolved "https://registry.yarnpkg.com/shawnlu96-altcha-lib/-/shawnlu96-altcha-lib-0.3.4.tgz#5991327359414d39c5dba5501ac4e848697be63f"
+  integrity sha512-Ku8nuTVGMqwX7Alaif1n/FuCrNgmwmfffnLwHn/SCpjhVjtdJ+kvWs6wtjqPn+9zCcevNk2HDOGqm+rHHVfMsg==
+
 shebang-command@^2.0.0:
   version "2.0.0"
   resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz"
@@ -1913,6 +1918,7 @@ stack-utils@^2.0.3:
     escape-string-regexp "^2.0.0"
 
 "string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0:
+  name string-width-cjs
   version "4.2.3"
   resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz"
   integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@@ -2069,7 +2075,7 @@ util-deprecate@^1.0.1:
 
 uuid@8.3.2:
   version "8.3.2"
-  resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
+  resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz"
   integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
 
 which@^2.0.1: