faucetLunch.ts 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. import { forEachAsync, generateRandomString } from '../utils'
  2. import { DBClient } from '../singletons'
  3. import { Status } from '../models/Status'
  4. import polly from 'polly-js'
  5. import { MnemonicKey } from '@initia/initia.js'
  6. import { ethers } from 'ethers'
  7. import { v4 as uuidv4 } from 'uuid'
  8. import axios, { AxiosInstance } from 'axios'
  9. import xrpl from 'xrpl'
  10. import { InitiaClient } from '../InitiaClient'
  11. import { HttpsProxyAgent } from 'https-proxy-agent'
  12. export function getAndroidModel() {
  13. const models = [
  14. 'Mi 9',
  15. 'LIO-AN00',
  16. 'PCRT00',
  17. 'V1824A',
  18. 'SM-N9760',
  19. 'HD1900',
  20. 'SKW-A0',
  21. 'NX629J',
  22. 'M973Q',
  23. 'PCLM10',
  24. 'SM-N9810',
  25. 'SM-N9860',
  26. 'SM-F9160',
  27. 'SM-A7009',
  28. 'SM-A6060',
  29. 'SM-W2018',
  30. 'SM-P610',
  31. 'VTR-L29',
  32. 'M1903F2G',
  33. 'XQ-BE72',
  34. 'RMX3709',
  35. 'SM-E5260',
  36. 'SM-W2020',
  37. 'SHARK KSR-A0',
  38. 'G8HNN',
  39. 'SM-G973U',
  40. 'SM-G973U1',
  41. 'SM-G9738',
  42. 'SM-G981B',
  43. 'SM-G988U',
  44. 'SM-G9880',
  45. 'M2012K11G',
  46. 'M2006C3LG',
  47. '21061119BI',
  48. '22127RK46C',
  49. 'M2102J20SI',
  50. 'MCE91',
  51. 'L16',
  52. 'L10',
  53. 'L12',
  54. 'L13',
  55. 'M11A',
  56. 'N11',
  57. 'N12',
  58. ]
  59. return models[Math.floor(Math.random() * models.length)]
  60. }
  61. export function getAndroidOS() {
  62. const oses = ['9', '10', '11', '12', '12.1', '13']
  63. return `Android ${oses[Math.floor(Math.random() * oses.length)]}`
  64. }
  65. export function getIOS() {
  66. const iOSes = [
  67. '14',
  68. '16.7.8',
  69. '17.5',
  70. '17.4.1',
  71. '16.7.7',
  72. '15.8.2',
  73. '17.3.1',
  74. '15.0.2',
  75. '15.1.1',
  76. '16.0.3',
  77. '16.4.1',
  78. ]
  79. return `iOS ${iOSes[Math.floor(Math.random() * iOSes.length)]}`
  80. }
  81. export function formatDateTime(date) {
  82. function pad(number, length) {
  83. return number.toString().padStart(length, '0')
  84. }
  85. const offset = -date.getTimezoneOffset()
  86. const offsetSign = offset >= 0 ? '+' : '-'
  87. const offsetHours = pad(Math.floor(Math.abs(offset) / 60), 2)
  88. const offsetMinutes = pad(Math.abs(offset) % 60, 2)
  89. return (
  90. date.getFullYear() +
  91. '-' +
  92. pad(date.getMonth() + 1, 2) +
  93. '-' +
  94. pad(date.getDate(), 2) +
  95. 'T' +
  96. pad(date.getHours(), 2) +
  97. ':' +
  98. pad(date.getMinutes(), 2) +
  99. ':' +
  100. pad(date.getSeconds(), 2) +
  101. '.' +
  102. pad(date.getMilliseconds(), 3) +
  103. offsetSign +
  104. offsetHours +
  105. offsetMinutes
  106. )
  107. }
  108. export async function getDeviceId(
  109. isAndroid: boolean,
  110. model: string,
  111. httpsAgent: any,
  112. ): Promise<string> {
  113. const deviceId = generateRandomString(22)
  114. let client: AxiosInstance
  115. if (isAndroid) {
  116. client = axios.create({
  117. httpsAgent: httpsAgent,
  118. headers: {
  119. 'X-Android-Package': 'xyz.lunchlunch.app',
  120. 'x-firebase-client':
  121. 'H4sIAAAAAAAAAKtWykhNLCpJSk0sKVayio7VUSpLLSrOzM9TslIyUqoFAFyivEQfAAAA',
  122. 'X-Android-Cert': '841CB3E1F4FC6CD420202DD419E02D4EE2E2099B',
  123. 'x-goog-api-key': 'AIzaSyA1PYciMbJ03xonKRM3JBr4yTReQ67GeuU',
  124. 'User-Agent': `Dalvik/2.1.0 (Linux; U; ${getAndroidOS()}; ${model} Build/PQ3B.190801.05281822)`,
  125. },
  126. })
  127. } else {
  128. }
  129. await client.post(
  130. 'https://firebaseinstallations.googleapis.com/v1/projects/lunchlunch-fb95e/installations',
  131. {
  132. fid: deviceId,
  133. appId: '1:383319257117:android:1a7c776df5c7048bddd6f4',
  134. authVersion: 'FIS_v2',
  135. sdkVersion: 'a:18.0.0',
  136. },
  137. )
  138. return deviceId
  139. }
  140. export async function getRawMessage(address: string, message: string, duid: string) {
  141. const resp = await axios.post('https://rem.mtdao.io/create', {
  142. address,
  143. message,
  144. duid,
  145. })
  146. return resp.data
  147. }
  148. async function faucetLunch(concurrency: number = 8) {
  149. const now = new Date()
  150. const accounts = await DBClient.instance.account.findMany({
  151. where: {
  152. // address: 'init1muxa5dedmr2wcc9dkd4k8d54al9gsu5szyw9rd',
  153. lastRun: {
  154. lt: new Date(now.getTime() - 24 * 60 * 60 * 1000),
  155. },
  156. status: 0,
  157. },
  158. orderBy: {
  159. id: 'asc',
  160. },
  161. })
  162. await forEachAsync(accounts, concurrency, async (account, index) => {
  163. console.log(`${index}/${accounts.length}: processing ${account.address}`)
  164. account.gmail = 'cryptoky1998@gmail.com'
  165. account.duid = 'FBF66888-C389-4C27-B832-CB49A923CED6'
  166. // account.mnemonic= 'can similar vanish left sudden vocal plate acoustic humor toast observe tortoise demand cook ankle planet angle future detail scout rookie flock type top'
  167. try {
  168. if (!account.gmail) {
  169. account.gmail = `${generateRandomString(8)}@gmail.com`
  170. }
  171. if (!account.xrpPrivateKey) {
  172. account.xrpPrivateKey = xrpl.Wallet.generate().seed
  173. }
  174. const key = new MnemonicKey({ mnemonic: account.mnemonic })
  175. // const key = new MnemonicKey()
  176. // account.duid = uuidv4().toUpperCase()
  177. // const evmWallet = new ethers.Wallet(key.privateKey.toString('hex'))
  178. const evmWallet = ethers.Wallet.fromPhrase(account.mnemonic)
  179. // const evmWallet = ethers.Wallet.createRandom()
  180. const message = JSON.stringify({
  181. signedAt: formatDateTime(new Date()),
  182. })
  183. const evmSignedMessage = await evmWallet.signMessage(message)
  184. const proxyAgent = undefined
  185. // let isAndroid = Math.random() > 0.5
  186. let isAndroid = false
  187. if (account.duid) {
  188. isAndroid = !account.duid.includes('-')
  189. }
  190. if (isAndroid && !account.deviceModel) {
  191. account.deviceModel = getAndroidModel()
  192. }
  193. if (!account.duid) {
  194. account.duid = isAndroid
  195. ? await getDeviceId(isAndroid, account.deviceModel, proxyAgent)
  196. : uuidv4().toUpperCase()
  197. }
  198. if (!account.deviceOS) {
  199. account.deviceOS = isAndroid ? getAndroidOS() : getIOS()
  200. }
  201. const rawMessage = await getRawMessage(
  202. evmWallet.address,
  203. message,
  204. account.duid,
  205. )
  206. const client = isAndroid
  207. ? axios.create({
  208. headers: {
  209. 'Lunch-Language': 'EN',
  210. 'lunch-fiat-currency': 'USD',
  211. 'lunch-app-duid': account.duid,
  212. 'lunch-app-version': '0.17.3',
  213. 'lun-app-build': 46,
  214. 'Lunch-Device-Model': account.deviceModel,
  215. 'Lunch-Device-OS': account.deviceOS,
  216. 'Lunch-Platform': 'Android',
  217. 'user-agent': `lunch/0.17.3(46) (Linux; ${account.deviceOS}; ${account.deviceModel} Build/PQ3B.190801.05281822)`,
  218. },
  219. httpsAgent: proxyAgent,
  220. })
  221. : axios.create({
  222. headers: {
  223. 'lunch-language': 'en',
  224. 'lunch-app-platform': 'iOS',
  225. 'lunch-app-version': '45',
  226. 'lunch-fiat-currency': 'USD',
  227. 'lunch-app-duid': account.duid,
  228. 'user-agent': `Lunch/1.0 (xyz.lunchlunch.app; build:45; ${account.deviceOS}) Alamofire/5.8.0`,
  229. },
  230. })
  231. const resp = await client.post(
  232. 'https://api.lunchlunch.xyz/v1/auth/sign-in',
  233. {
  234. walletAddress: evmWallet.address,
  235. signedMessage: evmSignedMessage,
  236. rawMessage: rawMessage,
  237. },
  238. )
  239. console.log(`${index}: sign-in success.`)
  240. client.defaults.headers[
  241. 'authorization'
  242. ] = `Bearer ${resp.data.accessToken}`
  243. // await client.delete('http://api.lunchlunch.xyz/v1/member/delete')
  244. // return
  245. const xrplWallet = xrpl.Wallet.fromSeed(account.xrpPrivateKey)
  246. let needRegister = false
  247. try {
  248. const memberResp = await client.get(
  249. 'https://api.lunchlunch.xyz/v1/member',
  250. )
  251. } catch (e) {
  252. if (e.response.status === 404) {
  253. needRegister = true
  254. }
  255. }
  256. if (needRegister) {
  257. const register = await client.post(
  258. 'https://api.lunchlunch.xyz/v1/member/register',
  259. {
  260. evmWalletAddress: evmWallet.address,
  261. initiaWalletAddress: key.accAddress,
  262. isImportedWallet: true,
  263. firstInitiaWalletAddress: key.accAddress,
  264. email: account.gmail,
  265. xrplWalletAddress: xrplWallet.address,
  266. },
  267. )
  268. console.log(`${index}: register done`)
  269. }
  270. await polly()
  271. .waitAndRetry(10)
  272. .executeForPromise(async info => {
  273. if (info.count) console.log(`${index}: retry ${info.count}`)
  274. try {
  275. await client.post(
  276. 'https://api.lunchlunch.xyz/v1/dish/submit-action/airdrop',
  277. {
  278. dishId: 43,
  279. },
  280. )
  281. console.log(`${index}: airdrop done`)
  282. } catch (e) {
  283. console.log(e.response.status, e.response?.data)
  284. throw e
  285. }
  286. })
  287. await DBClient.instance.account.update({
  288. where: { id: account.id },
  289. data: {
  290. status: Status.Fauceted,
  291. lastRun: new Date(),
  292. xrpPrivateKey: account.xrpPrivateKey,
  293. gmail: account.gmail,
  294. duid: account.duid,
  295. deviceModel: account.deviceModel,
  296. deviceOS: account.deviceOS,
  297. },
  298. })
  299. } catch (e) {
  300. console.log(e)
  301. await DBClient.instance.account.update({
  302. where: { id: account.id },
  303. data: {
  304. status: Status.FaucetFailed,
  305. message: e.message,
  306. lastRun: new Date(),
  307. xrpPrivateKey: account.xrpPrivateKey,
  308. gmail: account.gmail,
  309. duid: account.duid,
  310. deviceModel: account.deviceModel,
  311. deviceOS: account.deviceOS,
  312. },
  313. })
  314. }
  315. })
  316. }
  317. await faucetLunch(1)
  318. //
  319. // const phase =
  320. // 'leave bone supply chair brain thunder giant fatigue winter shrimp father stairs'
  321. // const wallet = ethers.Wallet.fromPhrase(phase)
  322. // console.log(wallet.address)
  323. // const key = new MnemonicKey({
  324. // mnemonic: phase,
  325. // })
  326. // const rawMessage =
  327. // '809a55a47f136226b26cd6f12e61c4b641895e95f7eb43851005884cd8102bac2e231d14775fa9034745491d08910a1c0d0799ddf6926397dd05e733f62bcbb4'
  328. // const signedAmino = key.createSignatureAmino()