diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..e772d5f --- /dev/null +++ b/.env.example @@ -0,0 +1,8 @@ +# Default: https://laconicd.laconic.com/api +LACONICD_GQL_ENDPOINT= + +# Default: https://laconicd.laconic.com +LACONICD_RPC_ENDPOINT= + +# Default: laconic_9000-1 +LACONICD_CHAIN_ID= diff --git a/cli/README.md b/cli/README.md index 541eb72..722472b 100644 --- a/cli/README.md +++ b/cli/README.md @@ -1,4 +1,4 @@ -# map-subscribers +# cli * Install dependencies: @@ -6,11 +6,18 @@ yarn ``` -* Map subscribers with onboarded participants: +* Create required env configuration: ```bash - yarn ts-node cli/map-subscribers.ts --onboardedJson --subscribersCsv --output + # Update the values as required + cp .env.example .env + ``` + +* Map subscribers to onboarded participants: + + ```bash + yarn ts-node cli/map-subscribers-to-participants.ts --subscribersCsv --output # Example: - # yarn ts-node cli/map-subscribers.ts --onboardedJson onboarded-participants.json --subscribersCsv subscribers.csv --output result.csv + # yarn ts-node cli/map-subscribers-to-participants.ts --subscribersCsv subscribers.csv --output result.csv ``` diff --git a/cli/map-subscribers.ts b/cli/map-subscribers-to-participants.ts similarity index 64% rename from cli/map-subscribers.ts rename to cli/map-subscribers-to-participants.ts index 1d94728..172469f 100644 --- a/cli/map-subscribers.ts +++ b/cli/map-subscribers-to-participants.ts @@ -7,23 +7,23 @@ import { parse as csvParse } from 'csv-parse'; import * as csvWriter from 'csv-writer'; import dotenv from 'dotenv'; +import { StargateClient } from '@cosmjs/stargate'; import { Registry } from '@cerc-io/registry-sdk'; dotenv.config(); -const LACONICD_GQL_ENDPOINT = process.env.LACONICD_GQL_ENDPOINT || 'https://laconicd.laconic.com/api'; -const LACONICD_RPC_ENDPOINT = process.env.LACONICD_RPC_ENDPOINT || 'https://laconicd.laconic.com'; const LACONICD_CHAIN_ID = process.env.LACONICD_CHAIN_ID || 'laconic_9000-1'; async function main(): Promise { const argv = _getArgv(); const registry = new Registry(LACONICD_GQL_ENDPOINT, LACONICD_RPC_ENDPOINT, LACONICD_CHAIN_ID); + const client = await StargateClient.connect(LACONICD_RPC_ENDPOINT); const participants = await registry.getParticipants(); const subscribers = await readSubscribers(argv.subscribersCsv); - processSubscribers(participants, subscribers, argv.output); + processSubscribers(client, participants, subscribers, argv.output); } async function readSubscribers(subscribersCsvPath: string): Promise { @@ -37,7 +37,7 @@ function hashSubscriberId(subscriberId: string): string { return '0x' + crypto.createHash('sha256').update(subscriberId).digest('hex'); } -async function processSubscribers(participants: any[], subscribers: any[], outputPath: string) { +async function processSubscribers(client: StargateClient, participants: any[], subscribers: any[], outputPath: string) { // Map kyc_id to participant data const kycMap: Record = {}; participants.forEach((participant: any) => { @@ -45,23 +45,47 @@ async function processSubscribers(participants: any[], subscribers: any[], outpu }); const onboardedSubscribers: any[] = []; - subscribers.forEach((subscriber) => { + subscribers.forEach(async (subscriber) => { const hashedSubscriberId = hashSubscriberId(subscriber['subscriber_id']); const participant = kycMap[hashedSubscriberId]; if (!participant) { return; } + const participantAddresss = participant['cosmos_address']; + + // Fetch participant's Laconic pubkey + const participantAccount = await client.getAccount(participantAddresss); + const participantPubkey = participantAccount?.pubkey; + + // Skip participant if pubkey not found + // (account may have funds but hasn't done any tx till now) + if (!participantPubkey) { + return; + } + + // Skip participant if an onboarding tx not found + const onboardingTxs = await client.searchTx(`message.sender='${participantAddresss}' AND message.action='/cerc.onboarding.v1.MsgOnboardParticipant'`); + if (onboardingTxs.length === 0) { + return; + } + + const latestOnboardingTx = onboardingTxs.reduce((prev, current) => { + return current.height > prev.height ? current : prev; + }); + const onboardedSubscriber = { subscriber_id: subscriber['subscriber_id'], email: subscriber['email'], - cosmos_address: participant['cosmos_address'], + status: subscriber['status'], + 'premium?': subscriber['premium?'], + created_at: subscriber['created_at'], + cosmos_address: participantAddresss, nitro_address: participant['nitro_address'], role: participant['role'], hashed_subscriber_id: participant['kyc_id'], - status: subscriber['status'], - premium: subscriber['premium?'], - created_at: subscriber['created_at'] + laconic_pubkey: participantPubkey, + onboarding_height: latestOnboardingTx.height }; onboardedSubscribers.push(onboardedSubscriber); @@ -72,14 +96,17 @@ async function processSubscribers(participants: any[], subscribers: any[], outpu header: [ { id: 'subscriber_id', title: 'subscriber_id' }, { id: 'email', title: 'email' }, + { id: 'status', title: 'status' }, + { id: 'premium?', title: 'premium?' }, + { id: 'created_at', title: 'created_at' }, { id: 'cosmos_address', title: 'cosmos_address' }, { id: 'nitro_address', title: 'nitro_address' }, { id: 'role', title: 'role' }, { id: 'hashed_subscriber_id', title: 'hashed_subscriber_id' }, - { id: 'status', title: 'status' }, - { id: 'premium', title: 'premium' }, - { id: 'created_at', title: 'created_at' } - ] + { id: 'laconic_pubkey', title: 'laconic_pubkey' }, + { id: 'onboarding_height', title: 'onboarding_height' }, + ], + alwaysQuote: true }); await writer.writeRecords(onboardedSubscribers); diff --git a/package.json b/package.json index 26fda84..66ff668 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ }, "dependencies": { "@cerc-io/registry-sdk": "^0.2.6", + "@cosmjs/stargate": "^0.32.4", "csv-parse": "^5.5.6", "csv-parser": "^3.0.0", "csv-writer": "^1.6.0", diff --git a/yarn.lock b/yarn.lock index fca647e..d4ad5c4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -208,7 +208,7 @@ ws "^7" xstream "^11.14.0" -"@cosmjs/stargate@^0.32.2": +"@cosmjs/stargate@^0.32.2", "@cosmjs/stargate@^0.32.4": version "0.32.4" resolved "https://registry.yarnpkg.com/@cosmjs/stargate/-/stargate-0.32.4.tgz#bd0e4d3bf613b629addbf5f875d3d3b50f640af1" integrity sha512-usj08LxBSsPRq9sbpCeVdyLx2guEcOHfJS9mHGCLCXpdAPEIEQEtWLDpEUc0LEhWOx6+k/ChXTc5NpFkdrtGUQ==