diff --git a/the_last_indexer/apibara.config.ts b/the_last_indexer/apibara.config.ts index ef6a60f..e40e4bb 100644 --- a/the_last_indexer/apibara.config.ts +++ b/the_last_indexer/apibara.config.ts @@ -7,12 +7,6 @@ export default defineConfig({ streamUrl: "https://mainnet.starknet.a5a.ch", contractAddress: "0x01710ab6e17d6809cd9d5e9b22e6bb1d1d09ca40f50449ea7ac81d67bef80f31", - }, - crowdfunding: { - startingBlock: "0", - streamUrl: "https://mainnet.starknet.a5a.ch", - contractAddress: - "0x02c92666029b207dc882c267d7b55c3fe4178e9f550f7188cd49adb85f963623", } }, }); diff --git a/the_last_indexer/constants.ts b/the_last_indexer/constants.ts index 1e6dc34..278e987 100644 --- a/the_last_indexer/constants.ts +++ b/the_last_indexer/constants.ts @@ -7,3 +7,13 @@ export const USDC_TOKEN_ADDRESS = "0x053c91253bc9682c04929ca02ed00b3e423f6710d2e export const WBTC_TOKEN_ADDRESS = "0x03fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac"; export const TRANSFER_SELECTOR = getSelector("Transfer"); + +export const GROUP_ADDRESS = "0x01710ab6e17d6809cd9d5e9b22e6bb1d1d09ca40f50449ea7ac81d67bef80f31"; +export const CROWDFUNDING_ADDRESS = "0x02c92666029b207dc882c267d7b55c3fe4178e9f550f7188cd49adb85f963623"; + +// SELECTORS +export const POOL_CREATED_SELECTOR = getSelector("PoolCreated"); +export const POOL_PAID_SELECTOR = getSelector("PoolPaid"); +export const GROUP_CREATED_SELECTOR = getSelector("GroupCreated"); +export const SUBSCRIPTION_TOPPED_SELECTOR = getSelector("SubscriptionTopped"); +export const GROUP_PAID_SELECTOR = getSelector("GroupPaid"); \ No newline at end of file diff --git a/the_last_indexer/crowd_funding_functions.ts b/the_last_indexer/crowd_funding_functions.ts new file mode 100644 index 0000000..9d42360 --- /dev/null +++ b/the_last_indexer/crowd_funding_functions.ts @@ -0,0 +1,90 @@ + +// Cache exports +export const crowdFundingContractAddresses = await fetch( + `${process.env.API_URL}/crowdfunding/addresses`, + { + method: "GET", + headers: { "Content-Type": "application/json" }, + } +) + .then((response) => response.json()) + .then((data: any) => data); + +export const group_address_cache = await fetch( + `${process.env.API_URL}/groups/addresses`, + { + method: "GET", + headers: { "Content-Type": "application/json" }, + } +) + .then((response) => response.json()) + .then((data: any) => data); + +// Crowdfunding Functions +const create_crowd_funding = ( + pool_address: string, + creator_address: string, + name: string, + target_amount: string +) => { + fetch(`${process.env.API_URL}/crowdfunding`, { + method: "POST", + headers: { + "Content-Type": "application/json", + "paymesh-api-key": `${process.env.PAYMESH_API_KEY}`, + }, + body: JSON.stringify({ + creator_address: creator_address, + name: name, + pool_address: pool_address, + target_amount: target_amount, + }), + }); +}; + +const donate_to_crowd_funding = ( + crowd_funding_address: string, + amount: string, + donor_address: string, + token_address: string, + transaction_hash: string +) => { + fetch(`${process.env.API_URL}/crowdfunding/${crowd_funding_address}/donate`, { + method: "POST", + headers: { + "Content-Type": "application/json", + "paymesh-api-key": `${process.env.PAYMESH_API_KEY}`, + }, + body: JSON.stringify({ + amount: amount, + donor_address: donor_address, + token_address: token_address, + transaction_hash: transaction_hash, + }), + }); +}; + +const resolve_crowd_funding = ( + crowd_funding_address: string, + amount: string, + token_address: string, + transaction_hash: string, + withdrawn_by: string +) => { + fetch( + `${process.env.API_URL}/crowdfunding/${crowd_funding_address}/resolve`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + "paymesh-api-key": `${process.env.PAYMESH_API_KEY}`, + }, + body: JSON.stringify({ + amount: amount, + token_address: token_address, + transaction_hash: transaction_hash, + withdrawn_by: withdrawn_by, + }), + } + ); +}; diff --git a/the_last_indexer/group_functions.ts b/the_last_indexer/group_functions.ts new file mode 100644 index 0000000..44aded1 --- /dev/null +++ b/the_last_indexer/group_functions.ts @@ -0,0 +1,105 @@ + +// Group Functions +const create_group = ( + address: string, + creatorAddress: string, + groupName: string, + usageCount: number, + members: Array<{ addr: string; percentage: number }> +) => { + const body = JSON.stringify({ + created_by: creatorAddress, + group_address: address, + group_name: groupName, + members: members.map((member) => ({ + addr: member.addr, + percentage: Number(member.percentage), + })), + usage_remaining: Number(usageCount), + }); + + fetch(`${process.env.API_URL}/groups`, { + method: "POST", + headers: { + "Content-Type": "application/json", + "paymesh-api-key": `${process.env.PAYMESH_API_KEY}`, + }, + body: body, + }).catch((err) => { + console.error(`Create group error ${address}:`, err); + }); +}; + +const pay = ( + group_address: string, + from_address: string, + tx_hash: string, + token_amount: string, + token_address: string +) => { + const body = JSON.stringify({ + from_address, + token_address, + token_amount, + tx_hash, + }); + + fetch(`${process.env.API_URL}/groups/${group_address}/pay`, { + method: "POST", + headers: { + "Content-Type": "application/json", + "paymesh-api-key": `${process.env.PAYMESH_API_KEY}`, + }, + body: body, + }).catch((err) => { + console.error(`Payment error for ${group_address}:`, err); + }); +}; + +const store_distribution_history = ( + group_address: string, + token_address: string, + tx_hash: string, + usage_remaining: number, + token_amount: string, + members: Array<{ addr: string; share: string }> +) => { + const members_decoupled = members.map((member) => ({ + member_address: member.addr, + member_amount: member.share, + })); + + fetch( + `${process.env.API_URL}/groups/${group_address}/payment-distributions`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + "paymesh-api-key": `${process.env.PAYMESH_API_KEY}`, + }, + body: JSON.stringify({ + members: members_decoupled, + token_address: token_address, + token_amount: token_amount, + tx_hash: tx_hash, + usage_remaining: Number(usage_remaining), + }), + } + ); +}; + +const subsciption_topped = (group_address: string, usage_count: number) => { + const body = JSON.stringify({ + usage_count: usage_count, + }); + fetch(`${process.env.API_URL}/groups/${group_address}/subscription`, { + method: "POST", + headers: { + "Content-Type": "application/json", + "paymesh-api-key": `${process.env.PAYMESH_API_KEY}`, + }, + body: body, + }).catch((err) => { + console.error(`Subscription top up error for ${group_address}:`, err); + }); +}; diff --git a/the_last_indexer/helpers.ts b/the_last_indexer/helpers.ts index 11bfbee..f5ab0d9 100644 --- a/the_last_indexer/helpers.ts +++ b/the_last_indexer/helpers.ts @@ -1,11 +1,11 @@ export const startingBlock = await fetch( - "https://starknet-mainnet.public.blastapi.io", + "https://starknet-mainnet.g.alchemy.com/v2/2kcD_qHq9FJV5ZI-BHY0q", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ jsonrpc: "2.0", - id: 0, + id: 1, method: "starknet_blockNumber", }), } @@ -13,6 +13,12 @@ export const startingBlock = await fetch( .then((response) => response.json()) .then((data: any) => data.result); + // curl https://starknet-mainnet.g.alchemy.com/v2/2kcD_qHq9FJV5ZI-BHY0q \ + // --request POST \ + // --header 'accept: application/json' \ + // --header 'content-type: application/json' \ + // --data '{"id":1,"jsonrpc":"2.0","method":"starknet_blockNumber"}' + export function hexToString(hex: string): string { if (!hex || !hex.match(/^0x[0-9a-fA-F]*$/)) { return hex; diff --git a/the_last_indexer/indexers/crowdfunding.indexer.ts b/the_last_indexer/indexers/crowdfunding.indexer.ts deleted file mode 100644 index b76b045..0000000 --- a/the_last_indexer/indexers/crowdfunding.indexer.ts +++ /dev/null @@ -1,152 +0,0 @@ -// import { defineIndexer } from "apibara/indexer"; -// import { useLogger } from "apibara/plugins"; - -// import { FieldElement, StarknetStream, decodeEvent, getSelector } from "@apibara/starknet"; -// import type { ApibaraRuntimeConfig } from "apibara/types"; -// import { ETH_TOKEN_ADDRESS, STRK_TOKEN_ADDRESS, TRANSFER_SELECTOR, USDC_TOKEN_ADDRESS, USDT_TOKEN_ADDRESS, WBTC_TOKEN_ADDRESS } from "../constants"; -// import { crowdfunding_abi } from "crowdfunding_abi"; -// import { strk_abi } from "strk_abi"; -// import { hexToString, startingBlock } from "../helpers"; - -// export default function (runtimeConfig: ApibaraRuntimeConfig) { -// const { startingBlock: _, streamUrl, contractAddress } = (runtimeConfig as any)["crowdfunding"]; - -// const POOL_CREATED_SELECTOR = getSelector("PoolCreated"); -// const POOL_PAID_SELECTOR = getSelector("PoolPaid"); - -// let crowd_funding_cache = [...crowdFundingContractAddresses]; -// console.log("Crowd Funding Cache: ", crowd_funding_cache); - -// return defineIndexer(StarknetStream)({ -// streamUrl, -// finality: "accepted", -// startingBlock: BigInt(startingBlock), -// filter: { -// events: [ -// { -// address: contractAddress as FieldElement, -// keys: [], -// }, -// { -// address: STRK_TOKEN_ADDRESS, -// keys: [TRANSFER_SELECTOR] -// }, -// { -// address: ETH_TOKEN_ADDRESS, -// keys: [TRANSFER_SELECTOR] -// }, -// { -// address: USDT_TOKEN_ADDRESS, -// keys: [TRANSFER_SELECTOR] -// }, -// { -// address: USDC_TOKEN_ADDRESS, -// keys: [TRANSFER_SELECTOR] -// }, -// { -// address: WBTC_TOKEN_ADDRESS, -// keys: [TRANSFER_SELECTOR] -// }, -// ], -// }, -// plugins: [], -// async transform({ block }) { -// const logger = useLogger(); -// const { events: blockEvents, header } = block; -// logger.info(`Received mainnet block ${header.blockNumber}`); - -// for (const event of blockEvents) { -// const eventKey = event.keys[0]; - -// if (eventKey === TRANSFER_SELECTOR) { -// const { args } = decodeEvent({ strict: true, event, abi: strk_abi, eventName: "src::strk::erc20_lockable::ERC20Lockable::Transfer" }); -// const safeArgs = JSON.stringify(args, (_, v) => -// typeof v === "bigint" ? v.toString() : v -// ); -// if (crowd_funding_cache.includes(args.to)) { -// const {from, to, value} = JSON.parse(safeArgs); - -// logger.info(`\nšŸ’” Transfer event ${safeArgs}`); -// donate_to_crowd_funding(to, value, from, event.address, event.transactionHash) -// } - -// } else if (eventKey === POOL_CREATED_SELECTOR) { -// logger.info("Pool Created"); -// const { args } = decodeEvent({ strict: true, event, abi: crowdfunding_abi, eventName: "contract::base::events::PoolCreated" }); -// const safeArgs = JSON.stringify(args, (_, v) => -// typeof v === "bigint" ? v.toString() : v -// ); -// logger.info(`\nšŸ’” Pool created event ${safeArgs}`); -// const {pool_address, _, creator, pool_name, target_amount} = JSON.parse(safeArgs); -// crowd_funding_cache.push(args.pool_address); -// create_crowd_funding(pool_address, creator, hexToString(pool_name), target_amount) -// } -// else if (eventKey === POOL_PAID_SELECTOR) { -// logger.info("Pool Paid"); -// const { args } = decodeEvent({ strict: true, event, abi: crowdfunding_abi, eventName: "contract::base::events::PoolPaid" }); -// const safeArgs = JSON.stringify(args, (_, v) => -// typeof v === "bigint" ? v.toString() : v -// ); -// logger.info(`\nšŸ’” Pool paid event ${safeArgs}`); -// const {pool_address, amount, paid_by, _, token_address} = JSON.parse(safeArgs); -// resolve_crowd_funding(pool_address, amount, token_address, event.transactionHash, paid_by) -// } -// } -// }, -// }); -// } - -// // function to get all crowd funding contract addresses -// export const crowdFundingContractAddresses = await fetch( -// `${process.env.API_URL}/crowdfunding/addresses`, -// { -// method: "GET", -// headers: { "Content-Type": "application/json" }, -// }, -// ) -// .then((response) => response.json()) -// .then((data: any) => data); - -// const create_crowd_funding = (pool_address: string, creator_address: string, name: string, target_amount: string) => { fetch( `${process.env.API_URL}/crowdfunding`, { -// method: 'POST', -// headers: { -// 'Content-Type': 'application/json', -// 'paymesh-api-key': `${process.env.PAYMESH_API_KEY}` -// }, -// body: JSON.stringify({ -// creator_address: creator_address, -// name: name, -// pool_address: pool_address, -// target_amount: target_amount -// }) -// }) -// console.log("Crowd funding created: ", pool_address) -// } - -// const donate_to_crowd_funding = (crowd_funding_address: string, amount: string, donor_address: string, token_address: string, transaction_hash: string) => fetch(`${process.env.API_URL}/crowdfunding/${crowd_funding_address}/donate`, { -// method: 'POST', -// headers: { -// 'Content-Type': 'application/json', -// 'paymesh-api-key': `${process.env.PAYMESH_API_KEY}` -// }, -// body: JSON.stringify({ -// amount: amount, -// donor_address: donor_address, -// token_address: token_address, -// transaction_hash: transaction_hash -// }) -// }) - -// const resolve_crowd_funding = (crowd_funding_address: string, amount: string, token_address: string, transaction_hash: string, withdrawn_by: string) => fetch(`${process.env.API_URL}/crowdfunding/${crowd_funding_address}/resolve`, { -// method: 'POST', -// headers: { -// 'Content-Type': 'application/json', -// 'paymesh-api-key': `${process.env.PAYMESH_API_KEY}` -// }, -// body: JSON.stringify({ -// amount: amount, -// token_address: token_address, -// transaction_hash: transaction_hash, -// withdrawn_by: withdrawn_by -// }) -// }) diff --git a/the_last_indexer/indexers/paymesh-starknet.indexer.ts b/the_last_indexer/indexers/paymesh-starknet.indexer.ts index 89801c3..dbc38c7 100644 --- a/the_last_indexer/indexers/paymesh-starknet.indexer.ts +++ b/the_last_indexer/indexers/paymesh-starknet.indexer.ts @@ -5,7 +5,6 @@ import { FieldElement, StarknetStream, decodeEvent, - getSelector, } from "@apibara/starknet"; import type { ApibaraRuntimeConfig } from "apibara/types"; import { @@ -15,42 +14,38 @@ import { USDC_TOKEN_ADDRESS, USDT_TOKEN_ADDRESS, WBTC_TOKEN_ADDRESS, + GROUP_ADDRESS, + CROWDFUNDING_ADDRESS, + POOL_CREATED_SELECTOR, + POOL_PAID_SELECTOR, + GROUP_CREATED_SELECTOR, + SUBSCRIPTION_TOPPED_SELECTOR, + GROUP_PAID_SELECTOR } from "../constants"; + import { crowdfunding_abi } from "crowdfunding_abi"; import { myAbi } from "../abi"; import { strk_abi } from "strk_abi"; import { hexToString, startingBlock } from "../helpers"; +import { crowdFundingContractAddresses, group_address_cache } from "crowd_funding_functions"; export default function (runtimeConfig: ApibaraRuntimeConfig) { - const crowdfundingConfig = (runtimeConfig as any)["crowdfunding"]; - const groupConfig = runtimeConfig["paymeshStarknet"]; - - const POOL_CREATED_SELECTOR = getSelector("PoolCreated"); - const POOL_PAID_SELECTOR = getSelector("PoolPaid"); - const GROUP_CREATED_SELECTOR = getSelector("GroupCreated"); - const SUBSCRIPTION_TOPPED_SELECTOR = getSelector("SubscriptionTopped"); - const GROUP_PAID_SELECTOR = getSelector("GroupPaid"); let crowd_funding_cache = [...crowdFundingContractAddresses]; let group_cache = [...group_address_cache]; - - console.log("Crowd Funding Cache: ", crowd_funding_cache); - console.log("Group Cache: ", group_cache); - console.log("starting block ", startingBlock) - + return defineIndexer(StarknetStream)({ - streamUrl: crowdfundingConfig.streamUrl || groupConfig.streamUrl, + streamUrl: "https://mainnet.starknet.a5a.ch", finality: "accepted", - startingBlock: BigInt(3421017), + startingBlock: BigInt(startingBlock), + debug: true, filter: { events: [ { - address: crowdfundingConfig.contractAddress as FieldElement, - keys: [], + address: CROWDFUNDING_ADDRESS as FieldElement }, { - address: groupConfig.contractAddress as FieldElement, - keys: [], + address: GROUP_ADDRESS as FieldElement }, { address: STRK_TOKEN_ADDRESS, @@ -74,354 +69,187 @@ export default function (runtimeConfig: ApibaraRuntimeConfig) { }, ], }, - plugins: [], async transform({ block }) { const logger = useLogger(); const { events: blockEvents } = block; + logger.info(`\n V3 indexer has started`); + logger.info(`\n Starting form block ${startingBlock}`); + for (const event of blockEvents) { const eventKey = event.keys[0]; - // Crowdfunding Events - if (eventKey === POOL_CREATED_SELECTOR) { - const { args } = decodeEvent({ - strict: true, - event, - abi: crowdfunding_abi, - eventName: "contract::base::events::PoolCreated", - }); - const safeArgs = JSON.stringify(args, (_, v) => - typeof v === "bigint" ? v.toString() : v - ); - const { pool_address, _, creator, pool_name, target_amount } = - JSON.parse(safeArgs); - crowd_funding_cache.push(args.pool_address); - // create_crowd_funding(pool_address, creator, hexToString(pool_name), target_amount); - logger.info(`\nšŸ’” Crowdfunding created event ${pool_address}`); - } else if (eventKey === POOL_PAID_SELECTOR) { - const { args } = decodeEvent({ - strict: true, - event, - abi: crowdfunding_abi, - eventName: "contract::base::events::PoolPaid", - }); - const safeArgs = JSON.stringify(args, (_, v) => - typeof v === "bigint" ? v.toString() : v - ); - const { pool_address, amount, paid_by, _, token_address } = - JSON.parse(safeArgs); - resolve_crowd_funding( - pool_address, - amount, - token_address, - event.transactionHash, - paid_by - ); - logger.info(`\nšŸ’” Pool paid event ${pool_address}`); - } - // Group Events - else if (eventKey === GROUP_CREATED_SELECTOR) { - logger.info(`\nšŸ’” Group created event`); - const { args } = decodeEvent({ - strict: true, - event, - abi: myAbi, - eventName: "contract::base::events::GroupCreated", - }); - const safeArgs = JSON.stringify(args, (_, v) => - typeof v === "bigint" ? v.toString() : v - ); - const { group_address, _, creator, name, usage_count, members } = - JSON.parse(safeArgs); - - if (!group_cache.includes(group_address)) { - group_cache.push(group_address); - console.log(`āœ… Added group ${group_address} to cache`); - } - - create_group( - group_address, - creator, - hexToString(name), - usage_count, - members - ); - } else if (eventKey === GROUP_PAID_SELECTOR) { - const { args } = decodeEvent({ - strict: true, - event, - abi: myAbi, - eventName: "contract::base::events::GroupPaid", - }); - const safeArgs = JSON.stringify(args, (_, v) => - typeof v === "bigint" ? v.toString() : v - ); - const { - group_address, - amount, - paid_by, - paid_at, - members, - usage_count, - token_address, - } = JSON.parse(safeArgs); - logger.info(`\nšŸ’” Group paid event ${group_address}`); - let tx_hash = event.transactionHash; - store_distribution_history( - group_address, - token_address, - tx_hash, - usage_count, - amount, - members - ); - } else if (eventKey === SUBSCRIPTION_TOPPED_SELECTOR) { - logger.info(`\nšŸ’” Group top up subscribed`); - const { args } = decodeEvent({ - strict: true, - event, - abi: myAbi, - eventName: "contract::base::events::SubscriptionTopped", - }); - const safeArgs = JSON.stringify(args, (_, v) => - typeof v === "bigint" ? v.toString() : v - ); - const { group_address, usage_count } = JSON.parse(safeArgs); - subsciption_topped(group_address, Number(usage_count)); - } - // Transfer Event - handled for both crowdfunding and groups - else if (eventKey === TRANSFER_SELECTOR) { - const { args } = decodeEvent({ - strict: true, - event, - abi: strk_abi, - eventName: "src::strk::erc20_lockable::ERC20Lockable::Transfer", - }); - const safeArgs = JSON.stringify(args, (_, v) => - typeof v === "bigint" ? v.toString() : v - ); - - // Check if transfer is to crowdfunding pool - if (crowd_funding_cache.includes(args.to)) { - const { from, to, value } = JSON.parse(safeArgs); - donate_to_crowd_funding( - to, - value, - from, - event.address, - event.transactionHash + switch (eventKey) { + case POOL_CREATED_SELECTOR: { + const { args } = decodeEvent({ + strict: true, + event, + abi: crowdfunding_abi, + eventName: "contract::base::events::PoolPaid", + }); + const safeArgs = JSON.stringify(args, (_, v) => + typeof v === "bigint" ? v.toString() : v ); - logger.info(`\nšŸ’” Transfer event to crowdfunding ${to}`); + const { pool_address, amount, paid_by, _, token_address } = JSON.parse(safeArgs); + logger.info(`\n Pool paid event ${pool_address}`); + break; } - // Check if transfer is to group - else if (group_cache.includes(args.to)) { - console.log( - `šŸ’° Transfer to group ${args.to}, processing payment...` + case TRANSFER_SELECTOR: { + const { args } = decodeEvent({ + strict: true, + event, + abi: strk_abi, + eventName: "src::strk::erc20_lockable::ERC20Lockable::Transfer", + }); + const safeArgs = JSON.stringify(args, (_, v) => + typeof v === "bigint" ? v.toString() : v ); - let tx_hash = event.transactionHash; - pay(args.to, args.from, tx_hash, String(args.value), event.address); - } + if (crowd_funding_cache.includes(args.to)) { + const { from, to, value } = JSON.parse(safeArgs); + logger.info(`\n Transfer event to crowdfunding ${to}`); + } + break; + } + default: + logger.info(`\n Unhandled event with key`); } + // if (eventKey === POOL_CREATED_SELECTOR) { + // const { args } = decodeEvent({ + // strict: true, + // event, + // abi: crowdfunding_abi, + // eventName: "contract::base::events::PoolCreated", + // }); + // const safeArgs = JSON.stringify(args, (_, v) => + // typeof v === "bigint" ? v.toString() : v + // ); + // const { pool_address, _, creator, pool_name, target_amount } = + // JSON.parse(safeArgs); + // crowd_funding_cache.push(args.pool_address); + // create_crowd_funding(pool_address, creator, hexToString(pool_name), target_amount); + // logger.info(`\n Crowdfunding created event ${pool_address}`); + // } else if (eventKey === POOL_PAID_SELECTOR) { + // const { args } = decodeEvent({ + // strict: true, + // event, + // abi: crowdfunding_abi, + // eventName: "contract::base::events::PoolPaid", + // }); + // const safeArgs = JSON.stringify(args, (_, v) => + // typeof v === "bigint" ? v.toString() : v + // ); + // const { pool_address, amount, paid_by, _, token_address } = + // JSON.parse(safeArgs); + // resolve_crowd_funding( + // pool_address, + // amount, + // token_address, + // event.transactionHash, + // paid_by + // ); + // logger.info(`\n Pool paid event ${pool_address}`); + // } + // // Group Events + // else if (eventKey === GROUP_CREATED_SELECTOR) { + // logger.info(`\n Group created event`); + // const { args } = decodeEvent({ + // strict: true, + // event, + // abi: myAbi, + // eventName: "contract::base::events::GroupCreated", + // }); + // const safeArgs = JSON.stringify(args, (_, v) => + // typeof v === "bigint" ? v.toString() : v + // ); + // const { group_address, _, creator, name, usage_count, members } = + // JSON.parse(safeArgs); + + // if (!group_cache.includes(group_address)) { + // group_cache.push(group_address); + // } + + // create_group( + // group_address, + // creator, + // hexToString(name), + // usage_count, + // members + // ); + // } else if (eventKey === GROUP_PAID_SELECTOR) { + // const { args } = decodeEvent({ + // strict: true, + // event, + // abi: myAbi, + // eventName: "contract::base::events::GroupPaid", + // }); + // const safeArgs = JSON.stringify(args, (_, v) => + // typeof v === "bigint" ? v.toString() : v + // ); + // const { + // group_address, + // amount, + // paid_by, + // paid_at, + // members, + // usage_count, + // token_address, + // } = JSON.parse(safeArgs); + // logger.info(`\n Group paid event ${group_address}`); + // let tx_hash = event.transactionHash; + // store_distribution_history( + // group_address, + // token_address, + // tx_hash, + // usage_count, + // amount, + // members + // ); + // } else if (eventKey === SUBSCRIPTION_TOPPED_SELECTOR) { + // logger.info(`\n Group top up subscribed`); + // const { args } = decodeEvent({ + // strict: true, + // event, + // abi: myAbi, + // eventName: "contract::base::events::SubscriptionTopped", + // }); + // const safeArgs = JSON.stringify(args, (_, v) => + // typeof v === "bigint" ? v.toString() : v + // ); + // const { group_address, usage_count } = JSON.parse(safeArgs); + // subsciption_topped(group_address, Number(usage_count)); + // } + // // Transfer Event - handled for both crowdfunding and groups + // else if (eventKey === TRANSFER_SELECTOR) { + // const { args } = decodeEvent({ + // strict: true, + // event, + // abi: strk_abi, + // eventName: "src::strk::erc20_lockable::ERC20Lockable::Transfer", + // }); + // const safeArgs = JSON.stringify(args, (_, v) => + // typeof v === "bigint" ? v.toString() : v + // ); + + // // Check if transfer is to crowdfunding pool + // if (crowd_funding_cache.includes(args.to)) { + // const { from, to, value } = JSON.parse(safeArgs); + // donate_to_crowd_funding( + // to, + // value, + // from, + // event.address, + // event.transactionHash + // ); + // logger.info(`\n Transfer event to crowdfunding ${to}`); + // } + // // Check if transfer is to group + // else if (group_cache.includes(args.to)) { + // let tx_hash = event.transactionHash; + // pay(args.to, args.from, tx_hash, String(args.value), event.address); + // logger.info(`\n Transfer event to group ${args.to}`); + // } + // } } }, }); } - -// Cache exports -export const crowdFundingContractAddresses = await fetch( - `${process.env.API_URL}/crowdfunding/addresses`, - { - method: "GET", - headers: { "Content-Type": "application/json" }, - } -) - .then((response) => response.json()) - .then((data: any) => data); - -export const group_address_cache = await fetch( - `${process.env.API_URL}/groups/addresses`, - { - method: "GET", - headers: { "Content-Type": "application/json" }, - } -) - .then((response) => response.json()) - .then((data: any) => data); - -// Crowdfunding Functions -const create_crowd_funding = ( - pool_address: string, - creator_address: string, - name: string, - target_amount: string -) => { - fetch(`${process.env.API_URL}/crowdfunding`, { - method: "POST", - headers: { - "Content-Type": "application/json", - "paymesh-api-key": `${process.env.PAYMESH_API_KEY}`, - }, - body: JSON.stringify({ - creator_address: creator_address, - name: name, - pool_address: pool_address, - target_amount: target_amount, - }), - }); - console.log("Crowd funding created: ", pool_address); -}; - -const donate_to_crowd_funding = ( - crowd_funding_address: string, - amount: string, - donor_address: string, - token_address: string, - transaction_hash: string -) => { - fetch(`${process.env.API_URL}/crowdfunding/${crowd_funding_address}/donate`, { - method: "POST", - headers: { - "Content-Type": "application/json", - "paymesh-api-key": `${process.env.PAYMESH_API_KEY}`, - }, - body: JSON.stringify({ - amount: amount, - donor_address: donor_address, - token_address: token_address, - transaction_hash: transaction_hash, - }), - }); -}; - -const resolve_crowd_funding = ( - crowd_funding_address: string, - amount: string, - token_address: string, - transaction_hash: string, - withdrawn_by: string -) => { - fetch( - `${process.env.API_URL}/crowdfunding/${crowd_funding_address}/resolve`, - { - method: "POST", - headers: { - "Content-Type": "application/json", - "paymesh-api-key": `${process.env.PAYMESH_API_KEY}`, - }, - body: JSON.stringify({ - amount: amount, - token_address: token_address, - transaction_hash: transaction_hash, - withdrawn_by: withdrawn_by, - }), - } - ); -}; - -// Group Functions -const create_group = ( - address: string, - creatorAddress: string, - groupName: string, - usageCount: number, - members: Array<{ addr: string; percentage: number }> -) => { - const body = JSON.stringify({ - created_by: creatorAddress, - group_address: address, - group_name: groupName, - members: members.map((member) => ({ - addr: member.addr, - percentage: Number(member.percentage), - })), - usage_remaining: Number(usageCount), - }); - - fetch(`${process.env.API_URL}/groups`, { - method: "POST", - headers: { - "Content-Type": "application/json", - "paymesh-api-key": `${process.env.PAYMESH_API_KEY}`, - }, - body: body, - }).catch((err) => { - console.error(`Create group error ${address}:`, err); - }); -}; - -const pay = ( - group_address: string, - from_address: string, - tx_hash: string, - token_amount: string, - token_address: string -) => { - const body = JSON.stringify({ - from_address, - token_address, - token_amount, - tx_hash, - }); - - console.log(`payment data ${body}`); - fetch(`${process.env.API_URL}/groups/${group_address}/pay`, { - method: "POST", - headers: { - "Content-Type": "application/json", - "paymesh-api-key": `${process.env.PAYMESH_API_KEY}`, - }, - body: body, - }).catch((err) => { - console.error(`Payment error for ${group_address}:`, err); - }); -}; - -const store_distribution_history = ( - group_address: string, - token_address: string, - tx_hash: string, - usage_remaining: number, - token_amount: string, - members: Array<{ addr: string; share: string }> -) => { - const members_decoupled = members.map((member) => ({ - member_address: member.addr, - member_amount: member.share, - })); - - fetch( - `${process.env.API_URL}/groups/${group_address}/payment-distributions`, - { - method: "POST", - headers: { - "Content-Type": "application/json", - "paymesh-api-key": `${process.env.PAYMESH_API_KEY}`, - }, - body: JSON.stringify({ - members: members_decoupled, - token_address: token_address, - token_amount: token_amount, - tx_hash: tx_hash, - usage_remaining: Number(usage_remaining), - }), - } - ); -}; - -const subsciption_topped = (group_address: string, usage_count: number) => { - const body = JSON.stringify({ - usage_count: usage_count, - }); - console.log(`subscription topped data ${body}`); - - fetch(`${process.env.API_URL}/groups/${group_address}/subscription`, { - method: "POST", - headers: { - "Content-Type": "application/json", - "paymesh-api-key": `${process.env.PAYMESH_API_KEY}`, - }, - body: body, - }).catch((err) => { - console.error(`Subscription top up error for ${group_address}:`, err); - }); -};