diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..cbac5697 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "deno.enable": true +} diff --git a/apps/indexer/.env.example b/apps/indexer/.env.example new file mode 100644 index 00000000..ebacfa1b --- /dev/null +++ b/apps/indexer/.env.example @@ -0,0 +1,2 @@ +AUTH_TOKEN=dna_xxx +POSTGRES_CONNECTION_STRING=postgresql://admin:postgres@localhost:5432/indexer \ No newline at end of file diff --git a/apps/indexer/Dockerfile b/apps/indexer/Dockerfile index e5fa3914..79e6de98 100644 --- a/apps/indexer/Dockerfile +++ b/apps/indexer/Dockerfile @@ -11,4 +11,8 @@ FROM quay.io/apibara/sink-postgres:0.7.0-x86_64 WORKDIR /app COPY ./src/* /app +ARG POSTGRES_CONNECTION_STRING + +ENV POSTGRES_CONNECTION_STRING=${POSTGRES_CONNECTION_STRING} + ENTRYPOINT ["/nix/store/rh1g8pb7wfnyr527jfmkkc5lm3sa1f0l-apibara-sink-postgres-0.7.0/bin/apibara-sink-postgres"] diff --git a/apps/indexer/README.md b/apps/indexer/README.md index 0f159b8a..ba2dbc4e 100644 --- a/apps/indexer/README.md +++ b/apps/indexer/README.md @@ -5,16 +5,15 @@ ## Install Postgres and Init the tables ``` -docker run --name afk-indexer -e POSTGRES_PASSWORD=postgres -d -p 5432:5432 -v /afk-indexer:/docker-entrypoint-initdb.d postgres:16 +docker run --name afk-indexer -e POSTGRES_PASSWORD=postgres -e POSTGRES_USER=admin -e POSTGRES_DB=indexer -d -p 5432:5432 -v ./:/docker-entrypoint-initdb.d postgres:latest ``` # Test -unrugmeme_deploy +buy-token deploy ``` -apibara run ./src/pump-buy-coin.js -A dna_XXX - +apibara run ./src/buy-token.ts --allow-env .env -A dna_xxx ``` @@ -27,4 +26,4 @@ apibara run ./src/pump-buy-coin.js -A dna_XXX ``` ### Run it - docker run -it --env-file ./.env afk-indexer run /app/pump-deploy-coin.js --tls-accept-invalid-certificates=true --connection-string POSTGRES:INDEXER_DATABASE_URL \ No newline at end of file + docker run -it --env-file ./.env afk-indexer run /app/buy-token.ts --tls-accept-invalid-certificates=true --allow-env-from-env POSTGRES_CONNECTION_STRING \ No newline at end of file diff --git a/apps/indexer/docker-compose.yml b/apps/indexer/docker-compose.yml index 4f603978..3c5137dc 100644 --- a/apps/indexer/docker-compose.yml +++ b/apps/indexer/docker-compose.yml @@ -6,7 +6,7 @@ services: environment: POSTGRES_DB: indexer POSTGRES_USER: admin - POSTGRES_PASSWORD: password + POSTGRES_PASSWORD: postgres ports: - '5432:5432' volumes: @@ -17,8 +17,9 @@ services: unruggableMemecoin-deploy-indexer: environment: - AUTH_TOKEN=${AUTH_TOKEN} + - POSTGRES_CONNECTION_STRING=postgresql://admin:postgres@postgres:5432/indexer image: quay.io/apibara/sink-postgres:latest - command: 'run ./indexer/unruggableMemecoin-deploy.indexer.js --connection-string postgresql://admin:password@postgres:5432/indexer -A ${AUTH_TOKEN}' + command: 'run ./indexer/unruggableMemecoin-deploy.indexer.ts --allow-env-from-env AUTH_TOKEN,POSTGRES_CONNECTION_STRING -A ${AUTH_TOKEN}' volumes: - ./src:/indexer depends_on: @@ -30,8 +31,9 @@ services: unruggableMemecoin-launch-indexer: environment: - AUTH_TOKEN=${AUTH_TOKEN} + - POSTGRES_CONNECTION_STRING=postgresql://admin:postgres@postgres:5432/indexer image: quay.io/apibara/sink-postgres:latest - command: 'run ./indexer/unruggableMemecoin-launch.indexer.js --connection-string postgresql://admin:password@postgres:5432/indexer -A ${AUTH_TOKEN}' + command: 'run ./indexer/unruggableMemecoin-launch.indexer.ts --allow-env-from-env AUTH_TOKEN,POSTGRES_CONNECTION_STRING -A ${AUTH_TOKEN}' volumes: - ./src:/indexer depends_on: @@ -43,8 +45,9 @@ services: unruggableMemecoin-transfers-indexer: environment: - AUTH_TOKEN=${AUTH_TOKEN} + - POSTGRES_CONNECTION_STRING=postgresql://admin:postgres@postgres:5432/indexer image: quay.io/apibara/sink-postgres:latest - command: 'run ./indexer/unruggableMemecoin-transfers.indexer.js --connection-string postgresql://admin:password@postgres:5432/indexer -A ${AUTH_TOKEN}' + command: 'run ./indexer/unruggableMemecoin-transfers.indexer.ts --allow-env-from-env AUTH_TOKEN,POSTGRES_CONNECTION_STRING -A ${AUTH_TOKEN}' volumes: - ./src:/indexer depends_on: @@ -56,8 +59,9 @@ services: buy-indexer: environment: - AUTH_TOKEN=${AUTH_TOKEN} + - POSTGRES_CONNECTION_STRING=postgresql://admin:postgres@postgres:5432/indexer image: quay.io/apibara/sink-postgres:latest - command: 'run ./indexer/buy-token.js --connection-string postgresql://admin:password@postgres:5432/indexer -A ${AUTH_TOKEN}' + command: 'run ./indexer/buy-token.ts --allow-env-from-env AUTH_TOKEN,POSTGRES_CONNECTION_STRING -A ${AUTH_TOKEN}' volumes: - ./src:/indexer depends_on: @@ -70,8 +74,9 @@ services: sell-indexer: environment: - AUTH_TOKEN=${AUTH_TOKEN} + - POSTGRES_CONNECTION_STRING=postgresql://admin:postgres@postgres:5432/indexer image: quay.io/apibara/sink-postgres:latest - command: 'run ./indexer/sell-token.js --connection-string postgresql://admin:password@postgres:5432/indexer -A ${AUTH_TOKEN}' + command: 'run ./indexer/sell-token.ts --allow-env-from-env AUTH_TOKEN,POSTGRES_CONNECTION_STRING -A ${AUTH_TOKEN}' volumes: - ./src:/indexer depends_on: @@ -83,8 +88,9 @@ services: token-indexer: environment: - AUTH_TOKEN=${AUTH_TOKEN} + - POSTGRES_CONNECTION_STRING=postgresql://admin:postgres@postgres:5432/indexer image: quay.io/apibara/sink-postgres:latest - command: 'run ./indexer/token-launch.js --connection-string postgresql://admin:password@postgres:5432/indexer -A ${AUTH_TOKEN}' + command: 'run ./indexer/token-launch.ts --allow-env-from-env AUTH_TOKEN,POSTGRES_CONNECTION_STRING -A ${AUTH_TOKEN}' volumes: - ./src:/indexer depends_on: @@ -96,8 +102,9 @@ services: deploy-indexer: environment: - AUTH_TOKEN=${AUTH_TOKEN} + - POSTGRES_CONNECTION_STRING=postgresql://admin:postgres@postgres:5432/indexer image: quay.io/apibara/sink-postgres:latest - command: 'run ./indexer/deploy-token.js --connection-string postgresql://admin:password@postgres:5432/indexer -A ${AUTH_TOKEN}' + command: 'run ./indexer/deploy-token.ts --allow-env-from-env AUTH_TOKEN,POSTGRES_CONNECTION_STRING -A ${AUTH_TOKEN}' volumes: - ./src:/indexer depends_on: diff --git a/apps/indexer/init.sql b/apps/indexer/init.sql index 1344bb05..feacd7d7 100644 --- a/apps/indexer/init.sql +++ b/apps/indexer/init.sql @@ -12,10 +12,8 @@ create table token_launch( current_supply text, liquidity_raised text, price text, - _cursor bigint - timestamp TIMESTAMP, - - + _cursor bigint, + time_stamp TEXT ); create table token_deploy( @@ -32,8 +30,8 @@ create table token_deploy( initial_supply text, total_supply text, created_at timestamp default current_timestamp, - _cursor bigint - timestamp TIMESTAMP, + _cursor bigint, + time_stamp TEXT ); @@ -57,10 +55,11 @@ CREATE TABLE token_transactions ( current_supply TEXT, liquidity_raised TEXT, price TEXT, + protocol_fee TEXT, amount TEXT, - timestamp TIMESTAMP, - _cursor bigint, - transaction_type TEXT NOT NULL CHECK (transaction_type IN ('buy', 'sell')),, + _cursor BIGINT, + transaction_type TEXT NOT NULL CHECK (transaction_type IN ('buy', 'sell')), + time_stamp TEXT ); diff --git a/apps/indexer/src/buy-token.js b/apps/indexer/src/buy-token.js deleted file mode 100644 index df2a7af8..00000000 --- a/apps/indexer/src/buy-token.js +++ /dev/null @@ -1,67 +0,0 @@ -import { hash, uint256 } from "https://esm.run/starknet@5.14"; -import { STARTING_BLOCK, LAUNCHPAD_ADDRESS } from "./constants"; - -const filter = { - header: { - weak: true, - }, - events: [ - { - fromAddress: LAUNCHPAD_ADDRESS.SEPOLIA, - keys: [hash.getSelectorFromName('BuyToken')], - includeReceipt: false, - }, - ], -} - -export const config = { - streamUrl: 'https://sepolia.starknet.a5a.ch', - startingBlock: STARTING_BLOCK, - network: 'starknet', - finality: 'DATA_STATUS_ACCEPTED', - filter, - sinkType: 'postgres', - sinkOptions: { - connectionString: '', // Specify your PostgreSQL connection string here - tableName: 'token_transactions', - }, -} - -export default function DecodeBuyToken({ header, events }) { - const { blockNumber, blockHash, timestamp } = header; - - return (events ?? []).map(({ event, transaction }) => { - if (!event.data) return; - - const transactionHash = transaction.meta.hash; - const [ - caller, - token_address, - amount_low, amount_high, - price_low, price_high, - protocol_fee_low, protocol_fee_high, - initial_supply_low, initial_supply_high, - ] = event.data; - - const amount = uint256.uint256ToBN({ low: amount_low, high: amount_high }).toString(); - const price = uint256.uint256ToBN({ low: price_low, high: price_high }).toString(); - const protocol_fee = uint256.uint256ToBN({ low: protocol_fee_low, high: protocol_fee_high }).toString(); - const initial_supply = uint256.uint256ToBN({ low: initial_supply_low, high: initial_supply_high }).toString(); - - return { - transaction_type: 'buy', - network: 'starknet-sepolia', - block_hash: blockHash, - block_number: Number(blockNumber), - block_timestamp: timestamp, - transaction_hash: transactionHash, - memecoin_address: token_address, - owner_address: caller, - initial_supply, - price, - protocol_fee, - timestamp: new Date(timestamp * 1000).toISOString(), // UNIX timestamp to ISO string - created_at: new Date().toISOString(), - }; - }); -} \ No newline at end of file diff --git a/apps/indexer/src/buy-token.ts b/apps/indexer/src/buy-token.ts new file mode 100644 index 00000000..9de2420d --- /dev/null +++ b/apps/indexer/src/buy-token.ts @@ -0,0 +1,89 @@ +import { Block, hash, uint256 } from "./deps.ts"; +import { STARTING_BLOCK, LAUNCHPAD_ADDRESS } from "./constants.ts"; + +const filter = { + header: { + weak: true + }, + events: [ + { + fromAddress: LAUNCHPAD_ADDRESS.SEPOLIA, + keys: [hash.getSelectorFromName("BuyToken")], + includeReceipt: false + } + ] +}; + +export const config = { + streamUrl: "https://sepolia.starknet.a5a.ch", + startingBlock: STARTING_BLOCK, + network: "starknet", + finality: "DATA_STATUS_ACCEPTED", + filter, + sinkType: "postgres", + sinkOptions: { + connectionString: Deno.env.get("POSTGRES_CONNECTION_STRING"), + tableName: "token_transactions" + } +}; + +export default function DecodeBuyToken({ header, events }: Block) { + const { blockNumber, blockHash, timestamp: block_timestamp } = header!; + + return (events ?? []).map(({ event, transaction }) => { + if (!event.data) return; + + const transactionHash = transaction.meta.hash; + const transfer_id = `${transactionHash}_${event.index}`; + + const [caller, token_address] = event.keys!; + + const [ + amount_low, + amount_high, + price_low, + price_high, + protocol_fee_low, + protocol_fee_high, + last_price_low, + last_price_high, + timestamp, + quote_amount_low, + quote_amount_high + ] = event.data; + + const amount = uint256 + .uint256ToBN({ low: amount_low, high: amount_high }) + .toString(); + const price = uint256 + .uint256ToBN({ low: price_low, high: price_high }) + .toString(); + const protocol_fee = uint256 + .uint256ToBN({ low: protocol_fee_low, high: protocol_fee_high }) + .toString(); + const last_price = uint256 + .uint256ToBN({ low: last_price_low, high: last_price_high }) + .toString(); + const quote_amount = uint256 + .uint256ToBN({ low: quote_amount_low, high: quote_amount_high }) + .toString(); + + return { + transfer_id, + network: "starknet-sepolia", + block_hash: blockHash, + block_number: Number(blockNumber), + block_timestamp: block_timestamp, + transaction_hash: transactionHash, + memecoin_address: token_address, + owner_address: caller, + last_price, + quote_amount, + price, + amount, + protocol_fee, + time_stamp: timestamp, + transaction_type: "buy" + }; + }); +} diff --git a/apps/indexer/src/constants.js b/apps/indexer/src/constants.js deleted file mode 100644 index c5ec894b..00000000 --- a/apps/indexer/src/constants.js +++ /dev/null @@ -1,7 +0,0 @@ -export const FACTORY_ADDRESS = '0x01a46467a9246f45c8c340f1f155266a26a71c07bd55d36e8d1c7d0d438a2dbc' -export const STARTING_BLOCK = 100_000 -export const LAUNCHPAD_ADDRESS = { - // SEPOLIA:"0x74acb6752abb734a7b3388567429217988e02409d9bf43c5586dc2c4f8baf40", - // SEPOLIA:"0x29a532e6933a6d6f9939e59469d96b52b7c38561745331302e1a29f035e4dd0", - SEPOLIA:"0x3798921000573bfc442d8153fc088db97bd3794f5ed19ea8c0846db5378f4af" -} diff --git a/apps/indexer/src/constants.ts b/apps/indexer/src/constants.ts new file mode 100644 index 00000000..93b2a494 --- /dev/null +++ b/apps/indexer/src/constants.ts @@ -0,0 +1,8 @@ +export const FACTORY_ADDRESS = + "0x01a46467a9246f45c8c340f1f155266a26a71c07bd55d36e8d1c7d0d438a2dbc"; +export const STARTING_BLOCK = 140_000; +export const LAUNCHPAD_ADDRESS = { + // SEPOLIA:"0x74acb6752abb734a7b3388567429217988e02409d9bf43c5586dc2c4f8baf40", + // SEPOLIA:"0x29a532e6933a6d6f9939e59469d96b52b7c38561745331302e1a29f035e4dd0", + SEPOLIA: "0x3798921000573bfc442d8153fc088db97bd3794f5ed19ea8c0846db5378f4af" +}; diff --git a/apps/indexer/src/deploy-token.js b/apps/indexer/src/deploy-token.js deleted file mode 100644 index b2e88bb0..00000000 --- a/apps/indexer/src/deploy-token.js +++ /dev/null @@ -1,70 +0,0 @@ -import { LAUNCHPAD_ADDRESS, STARTING_BLOCK } from './constants.js' -import { hash, uint256, shortString } from "https://esm.run/starknet@5.14"; - -const filter = { - header: { - weak: true, - }, - events: [ - { - fromAddress: LAUNCHPAD_ADDRESS.SEPOLIA, - keys: [hash.getSelectorFromName('CreateToken')], - includeReceipt: false, - }, - ], -} - -export const config = { - streamUrl: 'https://sepolia.starknet.a5a.ch', - startingBlock: STARTING_BLOCK, - network: 'starknet', - finality: 'DATA_STATUS_ACCEPTED', - filter, - sinkType: 'postgres', - sinkOptions: { - connectionString: '', - tableName: 'token_deploy', - }, -} - -export default function DecodeTokenDeploy({ header, events }) { - const { blockNumber, blockHash, timestamp } = header; - - return (events ?? []).map(({ event, transaction }) => { - if (!event.data || !event.keys) return; - - const transactionHash = transaction.meta.hash; - const [caller, token_address, - // name, symbol - ] = event.keys; - - const [ - initial_supply_low, initial_supply_high, - total_supply_low, total_supply_high, - symbol, name - ] = event.data; - - const initial_supply = uint256.uint256ToBN({ low: initial_supply_low, high: initial_supply_high }).toString(); - const total_supply = uint256.uint256ToBN({ low: total_supply_low, high: total_supply_high }).toString(); - const name_decoded = shortString.decodeShortString(name); - const symbol_decoded = shortString.decodeShortString(symbol); - - return { - network: 'starknet-sepolia', - block_hash: blockHash, - block_number: Number(blockNumber), - block_timestamp: timestamp, - transaction_hash: transactionHash, - memecoin_address: token_address, - owner_address: caller, - name: name_decoded, - symbol: symbol_decoded, - initial_supply, - total_supply, - created_at: new Date().toISOString(), - _cursor: transaction.meta.cursor, - timestamp: new Date(timestamp * 1000).toISOString(), - - }; - }); -} \ No newline at end of file diff --git a/apps/indexer/src/deploy-token.ts b/apps/indexer/src/deploy-token.ts new file mode 100644 index 00000000..dcf32007 --- /dev/null +++ b/apps/indexer/src/deploy-token.ts @@ -0,0 +1,91 @@ +import { LAUNCHPAD_ADDRESS, STARTING_BLOCK } from "./constants.ts"; +import { Block, hash, uint256, shortString } from "./deps.ts"; + +const filter = { + header: { + weak: true + }, + events: [ + { + fromAddress: LAUNCHPAD_ADDRESS.SEPOLIA, + keys: [hash.getSelectorFromName("CreateToken")], + includeReceipt: false + } + ] +}; + +export const config = { + streamUrl: "https://sepolia.starknet.a5a.ch", + startingBlock: STARTING_BLOCK, + network: "starknet", + finality: "DATA_STATUS_ACCEPTED", + filter, + sinkType: "postgres", + sinkOptions: { + connectionString: Deno.env.get("POSTGRES_CONNECTION_STRING"), + tableName: "token_deploy" + } +}; + +export default function DecodeTokenDeploy({ header, events }: Block) { + const { blockNumber, blockHash, timestamp } = header!; + + return (events ?? []).map(({ event, transaction }) => { + if (!event.data || !event.keys) return; + + const transactionHash = transaction.meta.hash; + const [caller, token_address] = event.keys; + + const [ + symbol, + name, + initial_supply_low, + initial_supply_high, + total_supply_low, + total_supply_high + ] = event.data; + + const symbol_decoded = token_address + ? shortString.decodeShortString(symbol.replace(/0x0+/, "0x")) + : ""; + const name_decoded = name + ? shortString.decodeShortString(name.replace(/0x0+/, "0x")) + : ""; + const initial_supply = uint256 + .uint256ToBN({ low: initial_supply_low, high: initial_supply_high }) + .toString(); + const total_supply = uint256 + .uint256ToBN({ low: total_supply_low, high: total_supply_high }) + .toString(); + + console.log({ + memecoin_address: token_address, + network: "starknet-sepolia", + block_hash: blockHash, + block_number: Number(blockNumber), + block_timestamp: timestamp, + transaction_hash: transactionHash, + owner_address: caller, + name: name_decoded, + symbol: symbol_decoded, + initial_supply, + total_supply, + time_stamp: timestamp + }); + + return { + memecoin_address: token_address, + network: "starknet-sepolia", + block_hash: blockHash, + block_number: Number(blockNumber), + block_timestamp: timestamp, + transaction_hash: transactionHash, + owner_address: caller, + name: name_decoded, + symbol: symbol_decoded, + initial_supply, + total_supply, + time_stamp: timestamp + }; + }); +} diff --git a/apps/indexer/src/deps.js b/apps/indexer/src/deps.js deleted file mode 100644 index b7b93c9e..00000000 --- a/apps/indexer/src/deps.js +++ /dev/null @@ -1,6 +0,0 @@ -export { ec, hash, uint256, shortString } from 'https://esm.sh/starknet@5.14' -export { formatUnits } from 'https://esm.sh/viem@1.4' - -export { Block, FieldElement, Filter } from 'https://esm.sh/@apibara/indexer@0.3/starknet' -// export { Config, NetworkOptions } from "https://esm.sh/@apibara/indexer"; -// export { Console } from "https://esm.sh/@apibara/indexer/sink/console"; \ No newline at end of file diff --git a/apps/indexer/src/deps.ts b/apps/indexer/src/deps.ts new file mode 100644 index 00000000..70496773 --- /dev/null +++ b/apps/indexer/src/deps.ts @@ -0,0 +1,13 @@ +export { + ec, + hash, + uint256, + shortString, + cairo +} from "https://esm.sh/starknet@5.14.1"; +export { formatUnits } from "https://esm.sh/viem@1.4.2"; +export type { + Block, + FieldElement, + Filter +} from "https://esm.sh/@apibara/indexer@0.3.1/starknet"; diff --git a/apps/indexer/src/script.js b/apps/indexer/src/script.js deleted file mode 100644 index 476627be..00000000 --- a/apps/indexer/src/script.js +++ /dev/null @@ -1,18 +0,0 @@ -export const config = { - streamUrl: "https://sepolia.starknet.a5a.ch", - startingBlock: 10_000, - network: "starknet", - finality: "DATA_STATUS_ACCEPTED", - filter: { - header: {}, - }, - // sinkType: "console", - sinkType: "postgres", - sinkOptions: {}, - }; - - // This transform does nothing. - export default function transform(block) { - return block; -} - diff --git a/apps/indexer/src/script.ts b/apps/indexer/src/script.ts new file mode 100644 index 00000000..73584065 --- /dev/null +++ b/apps/indexer/src/script.ts @@ -0,0 +1,18 @@ +import { Block } from "./deps.ts"; + +export const config = { + streamUrl: "https://sepolia.starknet.a5a.ch", + startingBlock: 10_000, + network: "starknet", + finality: "DATA_STATUS_ACCEPTED", + filter: { + header: {} + }, + sinkType: "postgres", + sinkOptions: {} +}; + +// This transform does nothing. +export default function transform(block: Block) { + return block; +} diff --git a/apps/indexer/src/sell-token.js b/apps/indexer/src/sell-token.js deleted file mode 100644 index f93ffd3c..00000000 --- a/apps/indexer/src/sell-token.js +++ /dev/null @@ -1,74 +0,0 @@ -import { hash, uint256 } from "https://esm.run/starknet@5.14"; -import { STARTING_BLOCK, LAUNCHPAD_ADDRESS } from "./constants"; - -const filter = { - header: { - weak: true, - }, - events: [ - { - fromAddress: LAUNCHPAD_ADDRESS.SEPOLIA, - keys: [hash.getSelectorFromName('SellToken')], - includeReceipt: false, - }, - ], -} - -export const config = { - streamUrl: 'https://sepolia.starknet.a5a.ch', - startingBlock: STARTING_BLOCK, - network: 'starknet', - finality: 'DATA_STATUS_ACCEPTED', - filter, - sinkType: 'postgres', - sinkOptions: { - connectionString: '', // Your PostgreSQL connection string - tableName: 'token_transactions', // Using the same table for buy and sell - }, -} - -export default function DecodeSellToken({ header, events }) { - const { blockNumber, blockHash, timestamp } = header; - - return (events ?? []).map(({ event, transaction }) => { - if (!event.data) return; - - const transactionHash = transaction.meta.hash; - const [ - seller, - token_address, - amount_low, amount_high, - price_low, price_high, - protocol_fee_low, protocol_fee_high, - total_supply_low, total_supply_high, - ] = event.data; - - const amount = uint256.uint256ToBN({ low: amount_low, high: amount_high }).toString(); - const price = uint256.uint256ToBN({ low: price_low, high: price_high }).toString(); - const protocol_fee = uint256.uint256ToBN({ low: protocol_fee_low, high: protocol_fee_high }).toString(); - const total_supply = uint256.uint256ToBN({ low: total_supply_low, high: total_supply_high }).toString(); - - return { - transaction_type: 'sell', - network: 'starknet-sepolia', - block_hash: blockHash, - block_number: Number(blockNumber), - block_timestamp: timestamp, - transaction_hash: transactionHash, - memecoin_address: token_address, - owner_address: seller, - last_price: price, - quote_amount: '', - coin_received: '', - initial_supply: '', - total_supply, - price, - amount, - timestamp: new Date(timestamp * 1000).toISOString(), - created_at: new Date().toISOString(), - }; - }); -} - - - diff --git a/apps/indexer/src/sell-token.ts b/apps/indexer/src/sell-token.ts new file mode 100644 index 00000000..7269eaab --- /dev/null +++ b/apps/indexer/src/sell-token.ts @@ -0,0 +1,89 @@ +import { Block, hash, uint256 } from "./deps.ts"; +import { STARTING_BLOCK, LAUNCHPAD_ADDRESS } from "./constants.ts"; + +const filter = { + header: { + weak: true + }, + events: [ + { + fromAddress: LAUNCHPAD_ADDRESS.SEPOLIA, + keys: [hash.getSelectorFromName("SellToken")], + includeReceipt: false + } + ] +}; + +export const config = { + streamUrl: "https://sepolia.starknet.a5a.ch", + startingBlock: STARTING_BLOCK, + network: "starknet", + finality: "DATA_STATUS_ACCEPTED", + filter, + sinkType: "postgres", + sinkOptions: { + connectionString: Deno.env.get("POSTGRES_CONNECTION_STRING"), // Your PostgreSQL connection string + tableName: "token_transactions" // Using the same table for buy and sell + } +}; + +export default function DecodeSellToken({ header, events }: Block) { + const { blockNumber, blockHash, timestamp: block_timestamp } = header!; + + return (events ?? []).map(({ event, transaction }) => { + if (!event.data) return; + + const transactionHash = transaction.meta.hash; + const transfer_id = `${transactionHash}_${event.index}`; + + const [caller, token_address] = event.keys!; + + const [ + amount_low, + amount_high, + price_low, + price_high, + protocol_fee_low, + protocol_fee_high, + last_price_low, + last_price_high, + timestamp, + quote_amount_low, + quote_amount_high + ] = event.data; + + const amount = uint256 + .uint256ToBN({ low: amount_low, high: amount_high }) + .toString(); + const price = uint256 + .uint256ToBN({ low: price_low, high: price_high }) + .toString(); + const protocol_fee = uint256 + .uint256ToBN({ low: protocol_fee_low, high: protocol_fee_high }) + .toString(); + const last_price = uint256 + .uint256ToBN({ low: last_price_low, high: last_price_high }) + .toString(); + const quote_amount = uint256 + .uint256ToBN({ low: quote_amount_low, high: quote_amount_high }) + .toString(); + + return { + transfer_id, + network: "starknet-sepolia", + block_hash: blockHash, + block_number: Number(blockNumber), + block_timestamp: block_timestamp, + transaction_hash: transactionHash, + memecoin_address: token_address, + owner_address: caller, + last_price, + quote_amount, + price, + amount, + protocol_fee, + time_stamp: timestamp, + transaction_type: "sell" + }; + }); +} diff --git a/apps/indexer/src/token-launch.js b/apps/indexer/src/token-launch.js deleted file mode 100644 index 559db270..00000000 --- a/apps/indexer/src/token-launch.js +++ /dev/null @@ -1,83 +0,0 @@ -// import { Block, hash, shortString, uint256 } from './deps.js' -import { FACTORY_ADDRESS, LAUNCHPAD_ADDRESS, STARTING_BLOCK } from './constants.js' -import { hash, uint256, shortString, cairo } from "https://esm.run/starknet@5.14"; -import { formatUnits } from "https://esm.run/viem@1.4"; - -const filter = { - header: { - weak: true, - }, - events: [ - { - fromAddress: LAUNCHPAD_ADDRESS.SEPOLIA, - keys: [hash.getSelectorFromName('CreateLaunch')], - includeReceipt: false, - }, - ], -} - -export const config = { - streamUrl: 'https://sepolia.starknet.a5a.ch', - startingBlock: STARTING_BLOCK, - network: 'starknet', - finality: 'DATA_STATUS_ACCEPTED', - filter, - sinkType: 'postgres', - sinkOptions: { - connectionString: '', - tableName: 'token_launch', - }, -} - -export default function DecodeTokenLaunchDeploy({ header, events }) { - const { blockNumber, blockHash, timestamp } = header; - - return (events ?? []).map(({ event, transaction }) => { - if (!event.data) return - - const transactionHash = transaction.meta.hash - console.log("event data", event?.data) - - const [owner, token_address, ] = event.keys - const [name, symbol, initial_supply_low, initial_supply_high, total_supply_low, total_supply_high] = event.data - console.log("owner", owner) - console.log("token_address", token_address) - console.log("name", name) - console.log("symbol", symbol) - console.log("initial_supply_low", initial_supply_low) - console.log("total_supply_low", total_supply_low) - - const name_decoded = shortString.decodeShortString(name.replace(/0x0+/, '0x')) - const symbol_decoded = shortString.decodeShortString(symbol.replace(/0x0+/, '0x')) - const quote_token_decoded = token_address ? shortString.decodeShortString(token_address.replace(/0x0+/, '0x')) : ''; - const exchange_name_decoded = exchange_name ? shortString.decodeShortString(exchange_name.replace(/0x0+/, '0x')) : ''; - const price_decoded = price ? shortString.decodeShortString(price.replace(/0x0+/, '0x')) : ''; - const liquidity_raised_decoded = liquidity_raised ? uint256.uint256ToBN({ low: liquidity_raised, high: 0 }).toString() : '0'; - - let total_supply= cairo.uint256(0) - if(total_supply_high && total_supply_low) { - total_supply = uint256.uint256ToBN({ low: total_supply_low, high: total_supply_high }).toString() - - } - console.log("total_supply", total_supply) - - return { - network: 'starknet-sepolia', - block_hash: blockHash, - block_number: Number(blockNumber), - block_timestamp: timestamp, - transaction_hash: transactionHash, - memecoin_address: token_address, - quote_token: quote_token_decoded, - exchange_name: exchange_name_decoded, - created_at: new Date().toISOString(), - total_supply, - current_supply, - liquidity_raised: liquidity_raised_decoded, - price: price_decoded, - _cursor: transaction.meta.cursor, - timestamp: new Date(timestamp * 1000).toISOString(), - - } - }) -} diff --git a/apps/indexer/src/token-launch.ts b/apps/indexer/src/token-launch.ts new file mode 100644 index 00000000..f013d8d6 --- /dev/null +++ b/apps/indexer/src/token-launch.ts @@ -0,0 +1,86 @@ +import { + FACTORY_ADDRESS, + LAUNCHPAD_ADDRESS, + STARTING_BLOCK +} from "./constants.ts"; +import { Block, hash, uint256, shortString, cairo } from "./deps.ts"; + +const filter = { + header: { + weak: true + }, + events: [ + { + fromAddress: LAUNCHPAD_ADDRESS.SEPOLIA, + keys: [hash.getSelectorFromName("CreateLaunch")], + includeReceipt: false + } + ] +}; + +export const config = { + streamUrl: "https://sepolia.starknet.a5a.ch", + startingBlock: STARTING_BLOCK, + network: "starknet", + finality: "DATA_STATUS_ACCEPTED", + filter, + sinkType: "postgres", + sinkOptions: { + connectionString: Deno.env.get("POSTGRES_CONNECTION_STRING"), + tableName: "token_launch" + } +}; + +export default function DecodeTokenLaunchDeploy({ header, events }: Block) { + const { blockNumber, blockHash, timestamp } = header!; + + return (events ?? []).map(({ event, transaction }) => { + if (!event.data) return; + + const transactionHash = transaction.meta.hash; + + const [caller, token_address] = event.keys!; + const [ + amount_low, + amount_high, + price, + total_supply_low, + total_supply_high, + slope_low, + slope_high, + threshold_liquidity_low, + threshold_liquidity_high + ] = event.data; + + const amount = uint256 + .uint256ToBN({ low: amount_low, high: amount_high }) + .toString(); + const price_decoded = price + ? shortString.decodeShortString(price.replace(/0x0+/, "0x")) + : ""; + const total_supply = uint256 + .uint256ToBN({ low: total_supply_low, high: total_supply_high }) + .toString(); + const slope = uint256 + .uint256ToBN({ low: slope_low, high: slope_high }) + .toString(); + const threshold_liquidity = uint256 + .uint256ToBN({ + low: threshold_liquidity_low, + high: threshold_liquidity_high + }) + .toString(); + + return { + memecoin_address: token_address, + network: "starknet-sepolia", + block_hash: blockHash, + block_number: Number(blockNumber), + block_timestamp: timestamp, + transaction_hash: transactionHash, + total_supply, + price: price_decoded, + time_stamp: timestamp + }; + }); +} diff --git a/apps/indexer/src/transfer.js b/apps/indexer/src/transfer.ts similarity index 64% rename from apps/indexer/src/transfer.js rename to apps/indexer/src/transfer.ts index c18c1096..a2f760b1 100644 --- a/apps/indexer/src/transfer.js +++ b/apps/indexer/src/transfer.ts @@ -1,5 +1,4 @@ -import { hash, uint256 } from "https://esm.run/starknet@5.14"; -import { formatUnits } from "https://esm.run/viem@1.4"; +import { hash, uint256, formatUnits, Block } from "./deps.ts"; const DECIMALS = 18; @@ -13,39 +12,40 @@ export const config = { { fromAddress: "0x03e85bfbb8e2a42b7bead9e88e9a1b19dbccf661471061807292120462396ec9", - keys: [hash.getSelectorFromName("Transfer")], - }, - ], + keys: [hash.getSelectorFromName("Transfer")] + } + ] }, sinkType: "postgres", sinkOptions: { - tableName: "transfers", - }, + connectionString: Deno.env.get("POSTGRES_CONNECTION_STRING"), + tableName: "transfers" + } }; -export default function transform({ header, events }) { - const { blockNumber, blockHash, timestamp } = header; - return events.map(({ event, receipt }) => { +export default function transform({ header, events }: Block) { + const { blockNumber, blockHash, timestamp } = header!; + + return (events ?? []).map(({ event, receipt }) => { const { transactionHash } = receipt; const transferId = `${transactionHash}_${event.index}`; - const [fromAddress, toAddress, amountLow, amountHigh] = event.data; + const [fromAddress, toAddress, amountLow, amountHigh] = event.data!; const amountRaw = uint256.uint256ToBN({ low: amountLow, high: amountHigh }); const amount = formatUnits(amountRaw, DECIMALS); - // Convert to snake_case because it works better with postgres. return { network: "starknet-sepolia", symbol: "ETH", block_hash: blockHash, - block_number: +blockNumber, + block_number: Number(blockNumber), block_timestamp: timestamp, transaction_hash: transactionHash, transfer_id: transferId, from_address: fromAddress, to_address: toAddress, amount: amount, - amount_raw: amountRaw.toString(), + amount_raw: amountRaw.toString() }; }); } diff --git a/apps/indexer/src/unruggableMemecoin-deploy.indexer.js b/apps/indexer/src/unruggableMemecoin-deploy.indexer.js deleted file mode 100644 index afd86604..00000000 --- a/apps/indexer/src/unruggableMemecoin-deploy.indexer.js +++ /dev/null @@ -1,58 +0,0 @@ -import { hash, shortString, uint256 } from './deps.ts' -import { FACTORY_ADDRESS, STARTING_BLOCK } from './constants.ts' - -const filter = { - header: { - weak: true, - }, - events: [ - { - fromAddress: FACTORY_ADDRESS, - keys: [hash.getSelectorFromName('MemecoinCreated')], - includeReceipt: false, - }, - ], -} - -export const config = { - streamUrl: 'https://mainnet.starknet.a5a.ch', - startingBlock: STARTING_BLOCK, - network: 'starknet', - finality: 'DATA_STATUS_ACCEPTED', - filter, - sinkType: 'postgres', - sinkOptions: { - connectionString: '', - tableName: 'unrugmeme_deploy', - }, -} - -export default function DecodeUnruggableMemecoinDeploy({ header, events }) { - const { blockNumber, blockHash, timestamp } = header - - return (events ?? []).map(({ event, transaction }) => { - if (!event.data) return - - const transactionHash = transaction.meta.hash - - const [owner, name, symbol, initial_supply_low, initial_supply_high, memecoin_address] = event.data - - const name_decoded = shortString.decodeShortString(name.replace(/0x0+/, '0x')) - const symbol_decoded = shortString.decodeShortString(symbol.replace(/0x0+/, '0x')) - const initial_supply = uint256.uint256ToBN({ low: initial_supply_low, high: initial_supply_high }).toString() - - return { - network: 'starknet-mainnet', - block_hash: blockHash, - block_number: Number(blockNumber), - block_timestamp: timestamp, - transaction_hash: transactionHash, - memecoin_address: memecoin_address, - owner_address: owner, - name: name_decoded, - symbol: symbol_decoded, - initial_supply: initial_supply, - created_at: new Date().toISOString(), - } - }) -} diff --git a/apps/indexer/src/unruggableMemecoin-deploy.indexer.ts b/apps/indexer/src/unruggableMemecoin-deploy.indexer.ts new file mode 100644 index 00000000..3e1abbed --- /dev/null +++ b/apps/indexer/src/unruggableMemecoin-deploy.indexer.ts @@ -0,0 +1,74 @@ +import { Block, hash, shortString, uint256 } from "./deps.ts"; +import { FACTORY_ADDRESS, STARTING_BLOCK } from "./constants.ts"; + +const filter = { + header: { + weak: true + }, + events: [ + { + fromAddress: FACTORY_ADDRESS, + keys: [hash.getSelectorFromName("MemecoinCreated")], + includeReceipt: false + } + ] +}; + +export const config = { + streamUrl: "https://mainnet.starknet.a5a.ch", + startingBlock: STARTING_BLOCK, + network: "starknet", + finality: "DATA_STATUS_ACCEPTED", + filter, + sinkType: "postgres", + sinkOptions: { + connectionString: Deno.env.get("POSTGRES_CONNECTION_STRING"), + tableName: "unrugmeme_deploy" + } +}; + +export default function DecodeUnruggableMemecoinDeploy({ + header, + events +}: Block) { + const { blockNumber, blockHash, timestamp } = header!; + + return (events ?? []).map(({ event, transaction }) => { + if (!event.data) return; + + const transactionHash = transaction.meta.hash; + + const [ + owner, + name, + symbol, + initial_supply_low, + initial_supply_high, + memecoin_address + ] = event.data; + + const name_decoded = shortString.decodeShortString( + name.replace(/0x0+/, "0x") + ); + const symbol_decoded = shortString.decodeShortString( + symbol.replace(/0x0+/, "0x") + ); + const initial_supply = uint256 + .uint256ToBN({ low: initial_supply_low, high: initial_supply_high }) + .toString(); + + return { + network: "starknet-mainnet", + block_hash: blockHash, + block_number: Number(blockNumber), + block_timestamp: timestamp, + transaction_hash: transactionHash, + memecoin_address: memecoin_address, + owner_address: owner, + name: name_decoded, + symbol: symbol_decoded, + initial_supply: initial_supply, + created_at: new Date().toISOString() + }; + }); +} diff --git a/apps/indexer/src/unruggableMemecoin-launch.indexer.js b/apps/indexer/src/unruggableMemecoin-launch.indexer.js deleted file mode 100644 index 6ccb8678..00000000 --- a/apps/indexer/src/unruggableMemecoin-launch.indexer.js +++ /dev/null @@ -1,54 +0,0 @@ -import { Block, hash, shortString } from './deps.js' -import { FACTORY_ADDRESS, STARTING_BLOCK } from './constants.js' - -const filter = { - header: { - weak: true, - }, - events: [ - { - fromAddress: FACTORY_ADDRESS, - keys: [hash.getSelectorFromName('MemecoinLaunched')], - includeReceipt: false, - }, - ], -} - -export const config = { - streamUrl: 'https://mainnet.starknet.a5a.ch', - startingBlock: STARTING_BLOCK, - network: 'starknet', - finality: 'DATA_STATUS_ACCEPTED', - filter, - sinkType: 'postgres', - sinkOptions: { - connectionString: '', - tableName: 'unrugmeme_launch', - }, -} - -export default function DecodeUnruggableMemecoinLaunch({ header, events }) { - const { blockNumber, blockHash, timestamp } = header - - return (events ?? []).map(({ event, transaction }) => { - if (!event.data) return - - const transactionHash = transaction.meta.hash - - const [memecoin_address, quote_token, exchange_name] = event.data - - const exchange_name_decoded = shortString.decodeShortString(exchange_name.replace(/0x0+/, '0x')) - - return { - network: 'starknet-mainnet', - block_hash: blockHash, - block_number: Number(blockNumber), - block_timestamp: timestamp, - transaction_hash: transactionHash, - memecoin_address: memecoin_address, - quote_token: quote_token, - exchange_name: exchange_name_decoded, - created_at: new Date().toISOString(), - } - }) -} diff --git a/apps/indexer/src/unruggableMemecoin-launch.indexer.ts b/apps/indexer/src/unruggableMemecoin-launch.indexer.ts new file mode 100644 index 00000000..31a957a1 --- /dev/null +++ b/apps/indexer/src/unruggableMemecoin-launch.indexer.ts @@ -0,0 +1,59 @@ +import { Block, hash, shortString } from "./deps.ts"; +import { FACTORY_ADDRESS, STARTING_BLOCK } from "./constants.ts"; + +const filter = { + header: { + weak: true + }, + events: [ + { + fromAddress: FACTORY_ADDRESS, + keys: [hash.getSelectorFromName("MemecoinLaunched")], + includeReceipt: false + } + ] +}; + +export const config = { + streamUrl: "https://mainnet.starknet.a5a.ch", + startingBlock: STARTING_BLOCK, + network: "starknet", + finality: "DATA_STATUS_ACCEPTED", + filter, + sinkType: "postgres", + sinkOptions: { + connectionString: Deno.env.get("POSTGRES_CONNECTION_STRING"), + tableName: "unrugmeme_launch" + } +}; + +export default function DecodeUnruggableMemecoinLaunch({ + header, + events +}: Block) { + const { blockNumber, blockHash, timestamp } = header!; + + return (events ?? []).map(({ event, transaction }) => { + if (!event.data) return; + + const transactionHash = transaction.meta.hash; + + const [memecoin_address, quote_token, exchange_name] = event.data; + + const exchange_name_decoded = shortString.decodeShortString( + exchange_name.replace(/0x0+/, "0x") + ); + + return { + network: "starknet-mainnet", + block_hash: blockHash, + block_number: Number(blockNumber), + block_timestamp: timestamp, + transaction_hash: transactionHash, + memecoin_address: memecoin_address, + quote_token: quote_token, + exchange_name: exchange_name_decoded, + created_at: new Date().toISOString() + }; + }); +} diff --git a/apps/indexer/src/unruggableMemecoin-transfers.indexer.js b/apps/indexer/src/unruggableMemecoin-transfers.indexer.js deleted file mode 100644 index c5ab99fe..00000000 --- a/apps/indexer/src/unruggableMemecoin-transfers.indexer.js +++ /dev/null @@ -1,71 +0,0 @@ -import { Block, hash, uint256 } from './deps.js' -import { FACTORY_ADDRESS, STARTING_BLOCK } from './constants.js' - -export const config = { - filter: { - header: { weak: true }, - events: [ - { - fromAddress: FACTORY_ADDRESS, - keys: [hash.getSelectorFromName('MemecoinLaunched')], - includeReceipt: false, - }, - ], - }, - streamUrl: 'https://mainnet.starknet.a5a.ch', - startingBlock: STARTING_BLOCK, - network: 'starknet', - finality: 'DATA_STATUS_ACCEPTED', - sinkType: 'postgres', - sinkOptions: { - connectionString: '', - tableName: 'unrugmeme_transfers', - }, -} - -export function factory({ header, events }) { - const launchEvents = (events ?? []).map(({ event }) => { - const memecoin_address = event.data?.[0] - return { - fromAddress: memecoin_address, - keys: [hash.getSelectorFromName('Transfer')], - includeReceipt: false, - } - }) - - return { - filter: { - header: { weak: true }, - events: launchEvents, - }, - } -} - -export default function DecodeUnruggableMemecoinLaunch({ header, events }) { - const { blockNumber, blockHash, timestamp } = header - - return (events ?? []).map(({ event, transaction }) => { - if (!event.data || !event.keys) return - - const transactionHash = transaction.meta.hash - const transferId = `${transactionHash}_${event.index ?? 0}` - const fromAddress = event.keys[1] - const toAddress = event.keys[2] - const amount = uint256.uint256ToBN({ low: event.data[0], high: event.data[1] }) - const memecoin_address = event.fromAddress - - return { - network: 'starknet-mainnet', - block_hash: blockHash, - block_number: Number(blockNumber), - block_timestamp: timestamp, - transaction_hash: transactionHash, - transfer_id: transferId, - from_address: fromAddress, - to_address: toAddress, - memecoin_address: memecoin_address, - amount: amount.toString(10), - created_at: new Date().toISOString(), - } - }) -} diff --git a/apps/indexer/src/unruggableMemecoin-transfers.indexer.ts b/apps/indexer/src/unruggableMemecoin-transfers.indexer.ts new file mode 100644 index 00000000..73198cac --- /dev/null +++ b/apps/indexer/src/unruggableMemecoin-transfers.indexer.ts @@ -0,0 +1,77 @@ +import { Block, hash, uint256 } from "./deps.ts"; +import { FACTORY_ADDRESS, STARTING_BLOCK } from "./constants.ts"; + +export const config = { + filter: { + header: { weak: true }, + events: [ + { + fromAddress: FACTORY_ADDRESS, + keys: [hash.getSelectorFromName("MemecoinLaunched")], + includeReceipt: false + } + ] + }, + streamUrl: "https://mainnet.starknet.a5a.ch", + startingBlock: STARTING_BLOCK, + network: "starknet", + finality: "DATA_STATUS_ACCEPTED", + sinkType: "postgres", + sinkOptions: { + connectionString: Deno.env.get("POSTGRES_CONNECTION_STRING"), + tableName: "unrugmeme_transfers" + } +}; + +export function factory({ header, events }: Block) { + const launchEvents = (events ?? []).map(({ event }) => { + const memecoin_address = event.data?.[0]; + return { + fromAddress: memecoin_address, + keys: [hash.getSelectorFromName("Transfer")], + includeReceipt: false + }; + }); + + return { + filter: { + header: { weak: true }, + events: launchEvents + } + }; +} + +export default function DecodeUnruggableMemecoinLaunch({ + header, + events +}: Block) { + const { blockNumber, blockHash, timestamp } = header!; + + return (events ?? []).map(({ event, transaction }) => { + if (!event.data || !event.keys) return; + + const transactionHash = transaction.meta.hash; + const transferId = `${transactionHash}_${event.index ?? 0}`; + const fromAddress = event.keys[1]; + const toAddress = event.keys[2]; + const amount = uint256.uint256ToBN({ + low: event.data[0], + high: event.data[1] + }); + const memecoin_address = event.fromAddress; + + return { + network: "starknet-mainnet", + block_hash: blockHash, + block_number: Number(blockNumber), + block_timestamp: timestamp, + transaction_hash: transactionHash, + transfer_id: transferId, + from_address: fromAddress, + to_address: toAddress, + memecoin_address: memecoin_address, + amount: amount.toString(10), + created_at: new Date().toISOString() + }; + }); +} diff --git a/deno.lock b/deno.lock new file mode 100644 index 00000000..7d8ab2c0 --- /dev/null +++ b/deno.lock @@ -0,0 +1,80 @@ +{ + "version": "3", + "packages": { + "specifiers": { + "npm:@types/node": "npm:@types/node@18.16.19" + }, + "npm": { + "@types/node@18.16.19": { + "integrity": "sha512-IXl7o+R9iti9eBW4Wg2hx1xQDig183jj7YLn8F7udNceyfkbn1ZxmzZXuak20gR40D7pIkIY1kYGx5VIGbaHKA==", + "dependencies": {} + } + } + }, + "redirects": { + "https://esm.sh/starknet@5.14": "https://esm.sh/starknet@5.14.1", + "https://esm.sh/viem@1.4": "https://esm.sh/viem@1.4.2" + }, + "remote": { + "https://deno.land/std@0.150.0/media_types/_util.ts": "ce9b4fc4ba1c447dafab619055e20fd88236ca6bdd7834a21f98bd193c3fbfa1", + "https://deno.land/std@0.150.0/media_types/mod.ts": "2d4b6f32a087029272dc59e0a55ae3cc4d1b27b794ccf528e94b1925795b3118", + "https://deno.land/std@0.150.0/media_types/vendor/mime-db.v1.52.0.ts": "724cee25fa40f1a52d3937d6b4fbbfdd7791ff55e1b7ac08d9319d5632c7f5af", + "https://deno.land/x/xhr@0.3.0/mod.ts": "094aacd627fd9635cd942053bf8032b5223b909858fa9dc8ffa583752ff63b20", + "https://esm.sh/@apibara/indexer@0.3.1/starknet": "c5bc67974872c73e5da7afc8d9e2b9eb0b78b57f4207f3c6c5631269fb14147c", + "https://esm.sh/starknet@5.14.1": "28136a3b6937465d3d0d2b1eb6d8182c75652d5064e692ae458866836b28f203", + "https://esm.sh/v135/@apibara/indexer@0.3.1/denonext/starknet.js": "0bffde4519f613582e62143c1bdc63356f8bd043e309858d8795ee2363f2ffd1", + "https://esm.sh/v135/@noble/curves@1.0.0/denonext/_shortw_utils.js": "fafe045ca5a727e93221e9656f88a58253729fb0b7c3301c1238864f133488a6", + "https://esm.sh/v135/@noble/curves@1.0.0/denonext/abstract/curve.js": "8a113c300533a5b1dc0bd3d358a58a39ba20263ab537872d29881eacd0b76d45", + "https://esm.sh/v135/@noble/curves@1.0.0/denonext/abstract/hash-to-curve.js": "618017d3102aeb325f0d8b181a36878ec524b5059cf6cf537fb2c5aba37614d5", + "https://esm.sh/v135/@noble/curves@1.0.0/denonext/abstract/modular.js": "ae9c28dca5f0c1a57ed379a9b377bbca7b7432bd46ca5017a04609598dfd5625", + "https://esm.sh/v135/@noble/curves@1.0.0/denonext/abstract/poseidon.js": "44d8a3e0583da2ef1883c5270394845cb178c085bbf636215084643b59d241f2", + "https://esm.sh/v135/@noble/curves@1.0.0/denonext/abstract/utils.js": "e6bb1a3234f1a28b40866ab235d558a042d9764a693956efa0fc399b46753eac", + "https://esm.sh/v135/@noble/curves@1.0.0/denonext/abstract/weierstrass.js": "f7c1d4fb804251ccc2bd6db5aaa327f695fd591eccc0072a0345c4fdc0263454", + "https://esm.sh/v135/@noble/curves@1.0.0/denonext/secp256k1.js": "3967154ead515e56968b2b8aba1785c10e76c39577236b7751c915071c372b55", + "https://esm.sh/v135/@noble/curves@1.2.0/denonext/_shortw_utils.js": "47a889dd52d7b29e8bc0d641597239d0ae0b1f10a9ee3b114c3dbd273172e9af", + "https://esm.sh/v135/@noble/curves@1.2.0/denonext/abstract/curve.js": "d4ac165ea7e6b5e401112e5c91d38a258fc6fe1dc3afa1c391cc2e74141d2228", + "https://esm.sh/v135/@noble/curves@1.2.0/denonext/abstract/modular.js": "6d0fba13e486d0929f4ab81f7774d75b2254b934e0be7dd3fd96b959c0dd7600", + "https://esm.sh/v135/@noble/curves@1.2.0/denonext/abstract/poseidon.js": "ab1b97653828117af52678e8a62ef976b529fdc56359172639c1c8e9c1d5d895", + "https://esm.sh/v135/@noble/curves@1.2.0/denonext/abstract/utils.js": "33d6521fbb6756d058dff59616da1e55a55972b4848976c27e81c4b4bc36c0e4", + "https://esm.sh/v135/@noble/curves@1.2.0/denonext/abstract/weierstrass.js": "5cb85ed9ad826f7e623f0052a55a865ad957eab06c30697804157844e82416a9", + "https://esm.sh/v135/@noble/hashes@1.3.0/denonext/_assert.js": "71dd0f5dc02b25513b5626a31922758a28a33baa07a25c41632b98e5e0aae1b7", + "https://esm.sh/v135/@noble/hashes@1.3.0/denonext/_sha2.js": "4928b2144c1c82206cd7c6788b964d9cd28400e4900065077908ad66a09521b3", + "https://esm.sh/v135/@noble/hashes@1.3.0/denonext/crypto.js": "38ef199043a068b6b97d8f91f1e5991ff4843fe7cfed35588dd927defb3b1139", + "https://esm.sh/v135/@noble/hashes@1.3.0/denonext/hmac.js": "9d6daaea2ca7aaf07fce0a224a8e31b77951a57e81ffccdac31c451e28aebdbb", + "https://esm.sh/v135/@noble/hashes@1.3.0/denonext/sha256.js": "5483ef2fc7cddff45e92054a93a0790dac9d4df4ef12478684e20b11325a55f2", + "https://esm.sh/v135/@noble/hashes@1.3.0/denonext/sha3.js": "b8b819e832da73dd95711d014a6b5692a47c50098dbc37aad972fba025b9bb28", + "https://esm.sh/v135/@noble/hashes@1.3.0/denonext/utils.js": "c75dc36831fccde5833088b67254427dd99c526835804a7a9c7bf856e30a8330", + "https://esm.sh/v135/@noble/hashes@1.3.2/denonext/_assert.js": "8b3fcc3a8d18f25fded5ecb46250f2009f11e0586b0e1e33757d12b6d1b05591", + "https://esm.sh/v135/@noble/hashes@1.3.2/denonext/crypto.js": "3d09b6d143b1cb8ec95375586a7d9a30a02b60cb1de984ba374c779f8e6c877a", + "https://esm.sh/v135/@noble/hashes@1.3.2/denonext/hmac.js": "23f7c9bebfbb777754e776b3197005b866742ce752945bfca17bc3c3a59e0e21", + "https://esm.sh/v135/@noble/hashes@1.3.2/denonext/utils.js": "bbfe700df9ae51f477688035ec3dd96739f77fd2f50439a4c84bcbc1aa7c7d4a", + "https://esm.sh/v135/@noble/hashes@1.3.3/denonext/_assert.js": "f8882bd96e2a6d1834a445c5af97f927b1ba028f34963c8570568e33385c4419", + "https://esm.sh/v135/@noble/hashes@1.3.3/denonext/_sha2.js": "7b27807ccd3cf7c3b90ce23b17bc9c5d791a72e41dd2e01a4debd9727990bca9", + "https://esm.sh/v135/@noble/hashes@1.3.3/denonext/crypto.js": "cf6efbafcbb35e03bcb3a36cccd3d6d1f9bc4ba23f44a79551929a28c83e7901", + "https://esm.sh/v135/@noble/hashes@1.3.3/denonext/sha256.js": "762e0b0cbde1990fc905eb816d30cdc0cf7dd4c23d123408c6963294f124f97d", + "https://esm.sh/v135/@noble/hashes@1.3.3/denonext/sha3.js": "3765211a8eec7f75e4ad8f265c023ed372b16327f214133ce4fc64c3a1423404", + "https://esm.sh/v135/@noble/hashes@1.3.3/denonext/utils.js": "701831e12a7e656df467b62f929ac9536ababef1b9b7445c7f87512366ae3933", + "https://esm.sh/v135/@scure/base@1.1.5/denonext/base.mjs": "442a66c701330f27adff8b2fa6067308ff9a82b8e178c8482882ff4aa7dfee82", + "https://esm.sh/v135/@scure/starknet@0.3.0/denonext/starknet.mjs": "d50471d53849ef5de4018ca196ef69fb8f487016b83c36b4a9509291672abd6c", + "https://esm.sh/v135/abitype@0.9.3/denonext/abitype.mjs": "c34994f6b891b4dd14327365366fe144ff9dc1c4ad9e2f51f00fd1859ac08df2", + "https://esm.sh/v135/bufferutil@4.0.8/denonext/bufferutil.mjs": "60a4618cbd1a5cb24935c55590b793d4ecb33862357d32e1d4614a0bbb90947f", + "https://esm.sh/v135/isomorphic-fetch@3.0.0/denonext/isomorphic-fetch.mjs": "a791533fb7269baadd38e8e4a34a46a6cb70f5c89ea4e8f4b3e1e5ddd533d61f", + "https://esm.sh/v135/isomorphic-ws@5.0.0/denonext/isomorphic-ws.mjs": "9d8dcd29684101d1a7b9088ad6681da41967322755c6b4ac01a2b721314d2ac5", + "https://esm.sh/v135/lossless-json@2.0.11/denonext/lossless-json.mjs": "cb67043586fcaab9a862a403c35abc3c8485788ec59fd403565c7f550a932085", + "https://esm.sh/v135/micro-starknet@0.2.3/denonext/micro-starknet.mjs": "1d66a0f0a2ef5814082e7c00ee85ddc59d4fe2c7cb02c02f3272da2bd4689f0a", + "https://esm.sh/v135/node-gyp-build@4.6.1/denonext/node-gyp-build.mjs": "5d28b312f145a6cb2ec0dbdd80a7d34c0e0e6b5dcada65411d8bcff6c8991cc6", + "https://esm.sh/v135/pako@2.1.0/denonext/pako.mjs": "a96661a4528965146d092709c0566bbb9a6fbc04e21587adfae26d48b2b3d763", + "https://esm.sh/v135/starknet@5.14.1/denonext/starknet.mjs": "26128462d49e78d14adf881f1ad5fa6cd401d34cd5267cb551c94a084d2cd0dc", + "https://esm.sh/v135/starknet@5.24.3/denonext/starknet.mjs": "2728a4d3cefb2ae5e0292d590509eca79906286b8abf1523368224221fe38f2d", + "https://esm.sh/v135/url-join@4.0.1/denonext/url-join.mjs": "1d2b840f03b6a3aaaaaa56380ea7879740d376a1dd83511b5bcf8af6c4617e1e", + "https://esm.sh/v135/utf-8-validate@6.0.3/denonext/utf-8-validate.mjs": "410c48d66840e987e474a4849cd25829817415cedd25466280effb1287d05aa5", + "https://esm.sh/v135/viem@1.4.2/denonext/dist/esm/utils/ccip.js": "cd25f6c198cca8585152a88af07712ba5b384e7db7bf855dfcee061e8f730166", + "https://esm.sh/v135/viem@1.4.2/denonext/utils.js": "dc95864e31961e04e8d28ef982f0f88168f2e5d6366e95660649286b195ed266", + "https://esm.sh/v135/viem@1.4.2/denonext/viem.mjs": "1facf8ebb9e39a884abc3e0cb575e55c1e8d0805efe7560a295a21671adfa460", + "https://esm.sh/v135/whatwg-fetch@3.6.19/denonext/whatwg-fetch.mjs": "65c15a9d84dcbd90308975b351e180e43ed2849f0be2312e543202d4fbb8e335", + "https://esm.sh/v135/ws@8.14.2/denonext/ws.mjs": "e96033415d90efd20ce6bec551447fc2771a27e232d05689c5410582cf04ee17", + "https://esm.sh/v135/zod@3.22.4/denonext/zod.mjs": "660128af5d1e921745c4d452472d103d9f2fc5afa508bbf233b83d35a272ad67", + "https://esm.sh/v135/zod@3.23.5/denonext/zod.mjs": "f4e0c43e8ed12aac124a79022c6bb47db25c2a6acd1d83e00ee9caca1d512ca4", + "https://esm.sh/viem@1.4.2": "86d05b62a8b1b90980ac8e6c3f459b0bf0ebe8abc52763456998aa6cc65ee68f" + } +}