import { forEachAsync, generateRandomString } from '../utils' import { DBClient } from '../singletons' import { Status } from '../models/Status' import polly from 'polly-js' import { MnemonicKey } from '@initia/initia.js' import { ethers } from 'ethers' import { v4 as uuidv4 } from 'uuid' import axios, { AxiosInstance } from 'axios' import xrpl from 'xrpl' import { InitiaClient } from '../InitiaClient' import { HttpsProxyAgent } from 'https-proxy-agent' export function getAndroidModel() { const models = [ 'Mi 9', 'LIO-AN00', 'PCRT00', 'V1824A', 'SM-N9760', 'HD1900', 'SKW-A0', 'NX629J', 'M973Q', 'PCLM10', 'SM-N9810', 'SM-N9860', 'SM-F9160', 'SM-A7009', 'SM-A6060', 'SM-W2018', 'SM-P610', 'VTR-L29', 'M1903F2G', 'XQ-BE72', 'RMX3709', 'SM-E5260', 'SM-W2020', 'SHARK KSR-A0', 'G8HNN', 'SM-G973U', 'SM-G973U1', 'SM-G9738', 'SM-G981B', 'SM-G988U', 'SM-G9880', 'M2012K11G', 'M2006C3LG', '21061119BI', '22127RK46C', 'M2102J20SI', 'MCE91', 'L16', 'L10', 'L12', 'L13', 'M11A', 'N11', 'N12', ] return models[Math.floor(Math.random() * models.length)] } export function getAndroidOS() { const oses = ['9', '10', '11', '12', '12.1', '13'] return `Android ${oses[Math.floor(Math.random() * oses.length)]}` } export function getIOS() { const iOSes = [ '14', '16.7.8', '17.5', '17.4.1', '16.7.7', '15.8.2', '17.3.1', '15.0.2', '15.1.1', '16.0.3', '16.4.1', ] return `iOS ${iOSes[Math.floor(Math.random() * iOSes.length)]}` } export function formatDateTime(date) { function pad(number, length) { return number.toString().padStart(length, '0') } const offset = -date.getTimezoneOffset() const offsetSign = offset >= 0 ? '+' : '-' const offsetHours = pad(Math.floor(Math.abs(offset) / 60), 2) const offsetMinutes = pad(Math.abs(offset) % 60, 2) return ( date.getFullYear() + '-' + pad(date.getMonth() + 1, 2) + '-' + pad(date.getDate(), 2) + 'T' + pad(date.getHours(), 2) + ':' + pad(date.getMinutes(), 2) + ':' + pad(date.getSeconds(), 2) + '.' + pad(date.getMilliseconds(), 3) + offsetSign + offsetHours + offsetMinutes ) } export async function getDeviceId( isAndroid: boolean, model: string, httpsAgent: any, ): Promise { const deviceId = generateRandomString(22) let client: AxiosInstance if (isAndroid) { client = axios.create({ httpsAgent: httpsAgent, headers: { 'X-Android-Package': 'xyz.lunchlunch.app', 'x-firebase-client': 'H4sIAAAAAAAAAKtWykhNLCpJSk0sKVayio7VUSpLLSrOzM9TslIyUqoFAFyivEQfAAAA', 'X-Android-Cert': '841CB3E1F4FC6CD420202DD419E02D4EE2E2099B', 'x-goog-api-key': 'AIzaSyA1PYciMbJ03xonKRM3JBr4yTReQ67GeuU', 'User-Agent': `Dalvik/2.1.0 (Linux; U; ${getAndroidOS()}; ${model} Build/PQ3B.190801.05281822)`, }, }) } else { } await client.post( 'https://firebaseinstallations.googleapis.com/v1/projects/lunchlunch-fb95e/installations', { fid: deviceId, appId: '1:383319257117:android:1a7c776df5c7048bddd6f4', authVersion: 'FIS_v2', sdkVersion: 'a:18.0.0', }, ) return deviceId } export async function getRawMessage( address: string, message: string, duid: string, ) { const resp = await axios.post('https://rem.mtdao.io/create', { address, message, duid, }) return resp.data } async function faucetLunch(concurrency: number = 8) { const now = new Date() const accounts = await DBClient.instance.account.findMany({ where: { // address: 'init1muxa5dedmr2wcc9dkd4k8d54al9gsu5szyw9rd', lastRun: { lt: new Date(now.getTime() - 24 * 60 * 60 * 1000), }, status: 0, }, orderBy: { id: 'asc', }, }) await forEachAsync(accounts, concurrency, async (account, index) => { console.log(`${index}/${accounts.length}: processing ${account.address}`) account.gmail = 'cryptoky1998@gmail.com' account.duid = 'FBF66888-C389-4C27-B832-CB49A923CED6' // 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' try { if (!account.gmail) { account.gmail = `${generateRandomString(8)}@gmail.com` } if (!account.xrpPrivateKey) { account.xrpPrivateKey = xrpl.Wallet.generate().seed } const key = new MnemonicKey({ mnemonic: account.mnemonic }) // const key = new MnemonicKey() // account.duid = uuidv4().toUpperCase() // const evmWallet = new ethers.Wallet(key.privateKey.toString('hex')) const evmWallet = ethers.Wallet.fromPhrase(account.mnemonic) // const evmWallet = ethers.Wallet.createRandom() const message = JSON.stringify({ signedAt: formatDateTime(new Date()), }) const evmSignedMessage = await evmWallet.signMessage(message) const proxyAgent = undefined // let isAndroid = Math.random() > 0.5 let isAndroid = false if (account.duid) { isAndroid = !account.duid.includes('-') } if (isAndroid && !account.deviceModel) { account.deviceModel = getAndroidModel() } if (!account.duid) { account.duid = isAndroid ? await getDeviceId(isAndroid, account.deviceModel, proxyAgent) : uuidv4().toUpperCase() } if (!account.deviceOS) { account.deviceOS = isAndroid ? getAndroidOS() : getIOS() } const rawMessage = await getRawMessage( evmWallet.address, message, account.duid, ) const client = isAndroid ? axios.create({ headers: { 'Lunch-Language': 'EN', 'lunch-fiat-currency': 'USD', 'lunch-app-duid': account.duid, 'lunch-app-version': '0.17.3', 'lun-app-build': 46, 'Lunch-Device-Model': account.deviceModel, 'Lunch-Device-OS': account.deviceOS, 'Lunch-Platform': 'Android', 'user-agent': `lunch/0.17.3(46) (Linux; ${account.deviceOS}; ${account.deviceModel} Build/PQ3B.190801.05281822)`, }, httpsAgent: proxyAgent, }) : axios.create({ headers: { 'lunch-language': 'en', 'lunch-app-platform': 'iOS', 'lunch-app-version': '45', 'lunch-fiat-currency': 'USD', 'lunch-app-duid': account.duid, 'user-agent': `Lunch/1.0 (xyz.lunchlunch.app; build:45; ${account.deviceOS}) Alamofire/5.8.0`, }, }) const resp = await client.post( 'https://api.lunchlunch.xyz/v1/auth/sign-in', { walletAddress: evmWallet.address, signedMessage: evmSignedMessage, rawMessage: rawMessage, }, ) console.log(`${index}: sign-in success.`) client.defaults.headers[ 'authorization' ] = `Bearer ${resp.data.accessToken}` // await client.delete('http://api.lunchlunch.xyz/v1/member/delete') // return const xrplWallet = xrpl.Wallet.fromSeed(account.xrpPrivateKey) let needRegister = false try { const memberResp = await client.get( 'https://api.lunchlunch.xyz/v1/member', ) } catch (e) { if (e.response.status === 404) { needRegister = true } } if (needRegister) { const register = await client.post( 'https://api.lunchlunch.xyz/v1/member/register', { evmWalletAddress: evmWallet.address, initiaWalletAddress: key.accAddress, isImportedWallet: true, firstInitiaWalletAddress: key.accAddress, email: account.gmail, xrplWalletAddress: xrplWallet.address, }, ) console.log(`${index}: register done`) } await polly() .waitAndRetry(10) .executeForPromise(async info => { if (info.count) console.log(`${index}: retry ${info.count}`) try { await client.post( 'https://api.lunchlunch.xyz/v1/dish/submit-action/airdrop', { dishId: 43, }, ) console.log(`${index}: airdrop done`) } catch (e) { console.log(e.response.status, e.response?.data) throw e } }) await DBClient.instance.account.update({ where: { id: account.id }, data: { status: Status.Fauceted, lastRun: new Date(), xrpPrivateKey: account.xrpPrivateKey, gmail: account.gmail, duid: account.duid, deviceModel: account.deviceModel, deviceOS: account.deviceOS, }, }) } catch (e) { console.log(e) await DBClient.instance.account.update({ where: { id: account.id }, data: { status: Status.FaucetFailed, message: e.message, lastRun: new Date(), xrpPrivateKey: account.xrpPrivateKey, gmail: account.gmail, duid: account.duid, deviceModel: account.deviceModel, deviceOS: account.deviceOS, }, }) } }) } await faucetLunch(1) // // const phase = // 'leave bone supply chair brain thunder giant fatigue winter shrimp father stairs' // const wallet = ethers.Wallet.fromPhrase(phase) // console.log(wallet.address) // const key = new MnemonicKey({ // mnemonic: phase, // }) // const rawMessage = // '809a55a47f136226b26cd6f12e61c4b641895e95f7eb43851005884cd8102bac2e231d14775fa9034745491d08910a1c0d0799ddf6926397dd05e733f62bcbb4' // const signedAmino = key.createSignatureAmino()