From 104dbb3e962994e44473324c58a687dd658e91a9 Mon Sep 17 00:00:00 2001 From: dylmanning Date: Mon, 10 Feb 2025 14:25:04 +1100 Subject: [PATCH 1/6] Initial scaffold --- database/schema.ts | 33 +++-- env.ts | 27 +++-- index.ts | 133 +++++++++------------ terraform/elasticache.tf | 48 ++++++++ terraform/environments/main.backend.tfvars | 3 + terraform/environments/main.tfvars | 13 ++ terraform/environments/test.backend.tfvars | 3 + terraform/environments/test.tfvars | 13 ++ terraform/eventbridge.tf | 24 ++++ terraform/iam.tf | 11 ++ terraform/lambda.tf | 86 +++++++++++++ terraform/main.tf | 25 ++++ terraform/rds.tf | 3 + terraform/secrets.tf | 15 +++ terraform/var.tf | 70 +++++++++++ 15 files changed, 398 insertions(+), 109 deletions(-) create mode 100644 terraform/elasticache.tf create mode 100644 terraform/environments/main.backend.tfvars create mode 100644 terraform/environments/main.tfvars create mode 100644 terraform/environments/test.backend.tfvars create mode 100644 terraform/environments/test.tfvars create mode 100644 terraform/eventbridge.tf create mode 100644 terraform/iam.tf create mode 100644 terraform/lambda.tf create mode 100644 terraform/main.tf create mode 100644 terraform/rds.tf create mode 100644 terraform/secrets.tf create mode 100644 terraform/var.tf diff --git a/database/schema.ts b/database/schema.ts index 847489b..edc8105 100644 --- a/database/schema.ts +++ b/database/schema.ts @@ -1,21 +1,18 @@ -import { env } from "../env"; +import { env } from '../env' -import { integer, text, boolean, pgSchema } from "drizzle-orm/pg-core"; +import { integer, text, boolean, pgSchema } from 'drizzle-orm/pg-core' -export const schema = pgSchema("test" as string); //TODO: change to env.DB_SCHEMA +export const schema = pgSchema(env.DB_SCHEMA || 'test') -export const fractalityTokenMigrations = schema.table( - "fractality_token_migrations", - { - transactionHash: text("transaction_hash").primaryKey(), - migrationContractAddress: text("migration_contract_address"), - eventName: text("event_name"), - caller: text("caller"), - migrationAddress: text("migration_address"), - amount: text("amount"), - foundAt: text("found_at"), - status: text("status"), - migratedAt: text("migrated_at"), - migratedAmount: text("migrated_amount"), - } -); +export const fractalityTokenMigrations = schema.table('fractality_token_migrations', { + transactionHash: text('transaction_hash').primaryKey(), + migrationContractAddress: text('migration_contract_address'), + eventName: text('event_name'), + caller: text('caller'), + migrationAddress: text('migration_address'), + amount: text('amount'), + foundAt: text('found_at'), + status: text('status'), + migratedAt: text('migrated_at'), + migratedAmount: text('migrated_amount') +}) diff --git a/env.ts b/env.ts index dea86ee..28318e9 100644 --- a/env.ts +++ b/env.ts @@ -1,6 +1,6 @@ -import { z } from "zod"; -import dotenv from "dotenv"; -dotenv.config(); +import { z } from 'zod' +import dotenv from 'dotenv' +dotenv.config() const envSchema = z.object({ PRIVATE_KEY: z.string(), @@ -18,25 +18,26 @@ const envSchema = z.object({ DB_PORT: z.coerce.number().optional(), DB_USER: z.string().optional(), DB_PASSWORD: z.string().optional(), + DB_SCHEMA: z.string().optional(), BLOCKCHAIN_ENVIRONMENT: z.string(), BLOCK_START_NUMBER: z.string(), SAFETY_CUSHION_NUMBER_OF_BLOCKS: z.coerce.number(), REDIS_CONNECTION_STRING: z.string(), - REDIS_USE_TLS: z.preprocess((str) => str === "true", z.boolean()), -}); + REDIS_USE_TLS: z.preprocess((str) => str === 'true', z.boolean()) +}) -const parsedEnv = envSchema.safeParse(process.env); +const parsedEnv = envSchema.safeParse(process.env) if (!parsedEnv.success) { const formattedErrors = parsedEnv.error.errors.map((err) => ({ - path: err.path.join("."), - message: err.message, - })); + path: err.path.join('.'), + message: err.message + })) - console.error("Environment variable validation failed:", formattedErrors); - throw new Error("Invalid environment variables."); + console.error('Environment variable validation failed:', formattedErrors) + throw new Error('Invalid environment variables.') } -export type BotEnv = z.infer; +export type BotEnv = z.infer -export const env = parsedEnv.data; +export const env = parsedEnv.data diff --git a/index.ts b/index.ts index 70cadb7..e0e9861 100644 --- a/index.ts +++ b/index.ts @@ -1,122 +1,104 @@ -import { PrivateKeyManager } from "./libs/PrivateKeyManager"; -import IORedis from "ioredis"; -const privateKeyManager = new PrivateKeyManager(); -import { env } from "./env"; -import { BlockchainConnectionProvider } from "./libs/BlockchainConnectionProvider"; -import { Address } from "viem"; +import { PrivateKeyManager } from './libs/PrivateKeyManager' +import IORedis from 'ioredis' +const privateKeyManager = new PrivateKeyManager() +import { env } from './env' +import { BlockchainConnectionProvider } from './libs/BlockchainConnectionProvider' +import { Address } from 'viem' import { addFractalityTokenMigrations, getUnmigratedFractalityTokenMigrations, finalizeHlMigrations, setHLMigrationStatus, - TokenMigration, -} from "./database"; -import { - HLMigration, - MigrationRegisteredEvent, - MigrationStatus, -} from "./interfaces"; -import { initializeDatabaseConnection } from "./database"; -import cron from "node-cron"; -import { PreviousBlockManager } from "./libs/PreviousBlockManager"; -import { HyperliquidManager } from "./libs/HyperliquidManager"; + TokenMigration +} from './database' +import { HLMigration, MigrationRegisteredEvent, MigrationStatus } from './interfaces' +import { initializeDatabaseConnection } from './database' +import cron from 'node-cron' +import { PreviousBlockManager } from './libs/PreviousBlockManager' +import { HyperliquidManager } from './libs/HyperliquidManager' + async function main() { - await privateKeyManager.init(); - await initializeDatabaseConnection(); + await privateKeyManager.init() + await initializeDatabaseConnection() - const redisConnection = await initRedisConnection(); + const redisConnection = await initRedisConnection() - const hlManager = new HyperliquidManager( - true, - true, - privateKeyManager.getPrivateKey() - ); + const hlManager = new HyperliquidManager(true, true, privateKeyManager.getPrivateKey()) const blockchainConnectionProvider = new BlockchainConnectionProvider({ providerUrl: env.PROVIDER_URL, y2kTokenMigrationAddress: env.Y2K_TOKEN_MIGRATION_ADDRESS as Address, - frctRTokenMigrationAddress: env.FRCT_R_MIGRATION_ADDRESS as Address, - }); + frctRTokenMigrationAddress: env.FRCT_R_MIGRATION_ADDRESS as Address + }) - await hlManager.init( - await blockchainConnectionProvider.getArbitrumTokenDecimals() - ); + await hlManager.init(await blockchainConnectionProvider.getArbitrumTokenDecimals()) const blockManager = new PreviousBlockManager( redisConnection, BigInt(env.SAFETY_CUSHION_NUMBER_OF_BLOCKS), () => blockchainConnectionProvider.getCurrentBlockNumber() - ); + ) - console.log("starting cron job for migrations, running every 5 minutes"); - cron.schedule("* * * * *", async () => { - const fromBlock = await blockManager.getFromBlockForScan(); - const toBlock = await blockManager.setFromBlockForScanToCurrentBlock(); - console.log( - `looking for migrations from block ${fromBlock} to block ${toBlock}` - ); + console.log('starting cron job for migrations, running every 5 minutes') + cron.schedule('* * * * *', async () => { + const fromBlock = await blockManager.getFromBlockForScan() + const toBlock = await blockManager.setFromBlockForScanToCurrentBlock() + console.log(`looking for migrations from block ${fromBlock} to block ${toBlock}`) const y2kMigrations = await blockchainConnectionProvider.scanMigrations( env.Y2K_TOKEN_MIGRATION_ADDRESS as Address, fromBlock, toBlock - ); + ) const frctRMigrations = await blockchainConnectionProvider.scanMigrations( env.FRCT_R_MIGRATION_ADDRESS as Address, fromBlock, toBlock - ); - await addMigrationsToDatabase([...y2kMigrations, ...frctRMigrations]); + ) + await addMigrationsToDatabase([...y2kMigrations, ...frctRMigrations]) //get migrations that still have not been sent to hyperliquid - const unmigratedMigrations: TokenMigration[] = - await getUnmigratedFractalityTokenMigrations(); + const unmigratedMigrations: TokenMigration[] = await getUnmigratedFractalityTokenMigrations() //calcualate the amount of tokens to send to hyperliquid - const hlMigrations = await prepForHLMigration( - hlManager, - unmigratedMigrations - ); - console.log("hlMigrations", hlMigrations); - - const { successes, failures } = await hlManager.sendHLMigrations( - hlMigrations - ); - console.log("successes", successes); - console.log("failures", failures); + const hlMigrations = await prepForHLMigration(hlManager, unmigratedMigrations) + console.log('hlMigrations', hlMigrations) + + const { successes, failures } = await hlManager.sendHLMigrations(hlMigrations) + console.log('successes', successes) + console.log('failures', failures) try { - await finalizeHlMigrations(successes); + await finalizeHlMigrations(successes) } catch (error) { - console.error("FATAL ERROR: Error finalizing HL migrations", error); + console.error('FATAL ERROR: Error finalizing HL migrations', error) } - console.log("done"); - }); + console.log('done') + }) } async function prepForHLMigration( hlManager: HyperliquidManager, unmigratedMigrations: TokenMigration[] ): Promise { - const hlMigrations: HLMigration[] = []; + const hlMigrations: HLMigration[] = [] for (const unmigratedMigration of unmigratedMigrations) { if (unmigratedMigration.amount && unmigratedMigration.migrationAddress) { - const arbitrumAmount = BigInt(unmigratedMigration.amount); - const hlAmount = - hlManager.decimalConversion!.convertToHlToken(arbitrumAmount); + const arbitrumAmount = BigInt(unmigratedMigration.amount) + const hlAmount = hlManager.decimalConversion!.convertToHlToken(arbitrumAmount) hlMigrations.push({ originalTransactionHash: unmigratedMigration.transactionHash, hlTokenAmount: hlAmount, - sendToAddress: unmigratedMigration.migrationAddress, - }); + sendToAddress: unmigratedMigration.migrationAddress + }) } else { console.error( `migration with hash ${unmigratedMigration.transactionHash} has no amount or no migration address` - ); + ) } } - return hlMigrations; + return hlMigrations } async function initRedisConnection() { @@ -125,25 +107,20 @@ async function initRedisConnection() { enableReadyCheck: false, tls: env.REDIS_USE_TLS ? { - rejectUnauthorized: false, + rejectUnauthorized: false } - : undefined, - }); + : undefined + }) } async function addMigrationsToDatabase(migrations: MigrationRegisteredEvent[]) { try { - const result = await addFractalityTokenMigrations(migrations); //TODO: make this batch + const result = await addFractalityTokenMigrations(migrations) //TODO: make this batch console.log( `Inserted ${result.newMigrations.length} new migrations and found ${result.existingTxs.length} existing migrations` - ); - console.info( - `existing migrations that already exist in the database`, - result.existingTxs - ); + ) + console.info(`existing migrations that already exist in the database`, result.existingTxs) } catch (e) { - console.error("Error adding migration to database", e); + console.error('Error adding migration to database', e) } } - -main(); diff --git a/terraform/elasticache.tf b/terraform/elasticache.tf new file mode 100644 index 0000000..7b6d6c2 --- /dev/null +++ b/terraform/elasticache.tf @@ -0,0 +1,48 @@ +resource "aws_elasticache_subnet_group" "redis_subnet" { + name = "${var.name}-redis-subnet-${var.environment}" + description = "Subnet group for Redis" + subnet_ids = var.subnet_ids +} + +resource "aws_security_group" "redis_sg" { + name = "${var.name}-redis-sg-${var.environment}" + description = "Security group for Redis" + vpc_id = var.vpc_id + + ingress { + description = "Allow Lambda to connect on Redis port" + from_port = 6379 + to_port = 6379 + protocol = "tcp" + security_groups = [aws_security_group.lambda_sg.id] + } + + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + + tags = { + Name = "${var.name}-redis-sg" + } +} + +resource "aws_elasticache_replication_group" "redis_cluster" { + replication_group_id = "${var.name}-redis-${var.environment}" + description = "{var.name} cluster for ${var.environment}" + engine = "redis" + engine_version = "6.x" + security_group_ids = [ + aws_security_group.redis_sg.id, + aws_security_group.lambda_sg.id + ] + subnet_group_name = aws_elasticache_subnet_group.redis_subnet.name + automatic_failover_enabled = true + + + tags = { + Name = "${var.name}-redis" + } +} diff --git a/terraform/environments/main.backend.tfvars b/terraform/environments/main.backend.tfvars new file mode 100644 index 0000000..0a204f2 --- /dev/null +++ b/terraform/environments/main.backend.tfvars @@ -0,0 +1,3 @@ +bucket = "fractality-backend-terraform" +key = "migration-service/mainnet.tfstate" +region = "ap-southeast-1" diff --git a/terraform/environments/main.tfvars b/terraform/environments/main.tfvars new file mode 100644 index 0000000..4b563ea --- /dev/null +++ b/terraform/environments/main.tfvars @@ -0,0 +1,13 @@ +name = "migration-service" +project = "fractality" +environment = "main" +vpc_id = "" +subnet_ids = [] + +provider_url = "" +public_address = "" +token_address = "" +y2k_token_migration_address = "" +frct_r_migration_address = "" +block_start_number = "" +safe_cushion_number_of_blocks = "" diff --git a/terraform/environments/test.backend.tfvars b/terraform/environments/test.backend.tfvars new file mode 100644 index 0000000..351ae09 --- /dev/null +++ b/terraform/environments/test.backend.tfvars @@ -0,0 +1,3 @@ +bucket = "fractality-backend-terraform" +key = "migration-service/testnet.tfstate" +region = "ap-southeast-1" diff --git a/terraform/environments/test.tfvars b/terraform/environments/test.tfvars new file mode 100644 index 0000000..f334cbe --- /dev/null +++ b/terraform/environments/test.tfvars @@ -0,0 +1,13 @@ +name = "migration-service-test" +project = "fractality" +environment = "test" +vpc_id = "" +subnet_ids = [] + +provider_url = "" +public_address = "" +token_address = "" +y2k_token_migration_address = "" +frct_r_migration_address = "" +block_start_number = "" +safe_cushion_number_of_blocks = "" diff --git a/terraform/eventbridge.tf b/terraform/eventbridge.tf new file mode 100644 index 0000000..fd1b8c7 --- /dev/null +++ b/terraform/eventbridge.tf @@ -0,0 +1,24 @@ +variable "schedule_expression" { + type = string + description = "Schedule expression for EventBridge trigger" + default = "rate(5 minutes)" +} + +resource "aws_cloudwatch_event_rule" "lambda_schedule_rule" { + name = "${var.name}-lambda-schedule-${var.environment}" + schedule_expression = var.schedule_expression +} + +resource "aws_cloudwatch_event_target" "lambda_schedule_target" { + rule = aws_cloudwatch_event_rule.lambda_schedule_rule.name + arn = aws_lambda_function.default.arn + target_id = "invoke-lambda" +} + +resource "aws_lambda_permission" "allow_cloudwatch" { + statement_id = "AllowExecutionFromCloudWatch" + action = "lambda:InvokeFunction" + function_name = aws_lambda_function.default.function_name + principal = "events.amazonaws.com" + source_arn = aws_cloudwatch_event_rule.lambda_schedule_rule.arn +} diff --git a/terraform/iam.tf b/terraform/iam.tf new file mode 100644 index 0000000..fe83e70 --- /dev/null +++ b/terraform/iam.tf @@ -0,0 +1,11 @@ +data "aws_iam_policy_document" "lambda_assume_role" { + statement { + effect = "Allow" + actions = ["sts:AssumeRole"] + principals { + type = "Service" + identifiers = ["lambda.amazonaws.com"] + } + } +} + diff --git a/terraform/lambda.tf b/terraform/lambda.tf new file mode 100644 index 0000000..36ab04c --- /dev/null +++ b/terraform/lambda.tf @@ -0,0 +1,86 @@ +locals { + secret_data = jsondecode(data.aws_secretsmanager_secret_version.db.secret_string) + db_username = local.secret_data["USERNAME"] + db_password = local.secret_data["PASSWORD"] + db_schema = var.environment == "main" ? "main" : "test" + db_name = var.db_name +} + +resource "aws_security_group" "lambda_sg" { + name = "${var.name}-lambda-sg-${var.environment}" + description = "Security group for Lambda functions" + vpc_id = "vpc-08ae44a5cd755d8b0" + + ingress { + description = "Allow Lambda to access RDS on port 5432" + from_port = 5432 + to_port = 5432 + protocol = "tcp" + security_groups = ["sg-03117204f06e38ba8"] + } + + egress { + description = "Allow all outbound traffic" + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + + tags = { + Name = "${var.name}-lambda-sg" + } +} + +resource "aws_lambda_function" "default" { + function_name = var.name + handler = "index.handler" + runtime = "nodejs18.x" + role = aws_iam_role.default.arn + filename = "${path.module}/../dist/bundle.zip" + source_code_hash = filebase64sha256("${path.module}/../dist/bundle.zip") + timeout = 300 + + environment { + variables = { + PROVIDER_URL = var.provider_url + BLOCKCHAIN_ENVIRONMENT = var.environment + PUBLIC_ADDRESS = var.public_address + TOKEN_ADDRESS = var.token_address + MNEMONIC_SECRET_ARN = data.aws_secretsmanager_secret.mnemonic.arn + DB_USER = local.db_username + DB_PASSWORD = local.db_password + DB_HOST = data.aws_db_instance.db.address + DB_NAME = local.db_name + DB_SCHEMA = local.db_schema + Y2K_TOKEN_MIGRATION_ADDRESS = var.y2k_token_migration_address + FRCT_R_MIGRATION_ADDRESS = var.frct_r_migration_address + BLOCK_START_NUMBER = var.block_start_number + SAFETY_CUSHION_NUMBER_OF_BLOCKS = var.safety_cushion_number_of_blocks + REDIS_CONNECTION_STRING = "${aws_elasticache_replication_group.redis_cluster.primary_endpoint_address}:${aws_elasticache_replication_group.redis_cluster.port}" + REDIS_USE_TLS = "true" + } + } + + vpc_config { + subnet_ids = ["subnet-05fe54f7cba0f2fd5", "subnet-07452d48590bce532"] + security_group_ids = [aws_security_group.lambda_sg.id] + } +} + + +resource "aws_iam_role" "default" { + name = "${var.name}-service-role" + assume_role_policy = data.aws_iam_policy_document.lambda_assume_role.json +} + +resource "aws_iam_role_policy_attachment" "lambda_vpc_access" { + role = aws_iam_role.default.name + policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole" +} + +resource "aws_iam_role_policy_attachment" "lambda_policy" { + role = aws_iam_role.default.name + policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" +} + diff --git a/terraform/main.tf b/terraform/main.tf new file mode 100644 index 0000000..86697ee --- /dev/null +++ b/terraform/main.tf @@ -0,0 +1,25 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "5.62.0" + } + } + backend "s3" { + encrypt = true + } +} + +provider "aws" { + region = var.region + default_tags { + tags = { + Name = var.name + Project = var.project + Environment = var.environment + Version = var.project_version + } + } +} + +data "aws_caller_identity" "current" {} diff --git a/terraform/rds.tf b/terraform/rds.tf new file mode 100644 index 0000000..1c044c3 --- /dev/null +++ b/terraform/rds.tf @@ -0,0 +1,3 @@ +data "aws_db_instance" "db" { + db_instance_identifier = var.db_instance_id +} diff --git a/terraform/secrets.tf b/terraform/secrets.tf new file mode 100644 index 0000000..6bd1498 --- /dev/null +++ b/terraform/secrets.tf @@ -0,0 +1,15 @@ +data "aws_secretsmanager_secret" "db" { + name = "FRACTALITY_DB" +} + +data "aws_secretsmanager_secret_version" "db" { + secret_id = data.aws_secretsmanager_secret.db.id +} + +data "aws_secretsmanager_secret" "mnemonic" { + name = "FRACTALITY_DB_${var.environment}" +} + +data "aws_secretsmanager_secret_version" "mnemonic" { + secret_id = data.aws_secretsmanager_secret.mnemonic.id +} diff --git a/terraform/var.tf b/terraform/var.tf new file mode 100644 index 0000000..d314dd4 --- /dev/null +++ b/terraform/var.tf @@ -0,0 +1,70 @@ +variable "account_id" { + type = string + description = "AWS account ID" +} + +variable "region" { + type = string + description = "AWS region" +} + +variable "environment" { + type = string +} + +variable "name" { + type = string +} + +variable "vpc_id" { + type = string +} + +variable "subnet_ids" { + type = list(string) + default = [] +} + +variable "project" { + type = string +} + +variable "project_version" { + type = string +} + +variable "db_name" { + type = string +} + +variable "db_instance_id" { + type = string +} + +variable "provider_url" { + type = string +} + +variable "public_address" { + type = string +} + +variable "token_address" { + type = string +} + +variable "y2k_token_migration_address" { + type = string +} + +variable "frct_r_migration_address" { + type = string +} + +variable "block_start_number" { + type = string +} + +variable "safety_cushion_number_of_blocks" { + type = string +} From 57e90cfdee01b83f0cc5041dcadb503c8f5a3116 Mon Sep 17 00:00:00 2001 From: dylmanning Date: Mon, 10 Feb 2025 14:29:45 +1100 Subject: [PATCH 2/6] Rename mnemonic secret --- terraform/secrets.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/terraform/secrets.tf b/terraform/secrets.tf index 6bd1498..d286401 100644 --- a/terraform/secrets.tf +++ b/terraform/secrets.tf @@ -7,7 +7,7 @@ data "aws_secretsmanager_secret_version" "db" { } data "aws_secretsmanager_secret" "mnemonic" { - name = "FRACTALITY_DB_${var.environment}" + name = "FRACTALITY_MIGRATION_${var.environment}" } data "aws_secretsmanager_secret_version" "mnemonic" { From 2d51164ae9b1233c4b06c836bc7ad6be659c40a5 Mon Sep 17 00:00:00 2001 From: Jose Herrera Date: Wed, 12 Feb 2025 18:10:09 -0500 Subject: [PATCH 3/6] format for easier reading (for jose), we need to get the same styling going. --- database/schema.ts | 33 ++++++------ env.ts | 26 ++++----- index.ts | 130 ++++++++++++++++++++++++++------------------- interfaces.ts | 7 ++- 4 files changed, 110 insertions(+), 86 deletions(-) diff --git a/database/schema.ts b/database/schema.ts index edc8105..a466894 100644 --- a/database/schema.ts +++ b/database/schema.ts @@ -1,18 +1,21 @@ -import { env } from '../env' +import { env } from "../env"; -import { integer, text, boolean, pgSchema } from 'drizzle-orm/pg-core' +import { integer, text, boolean, pgSchema } from "drizzle-orm/pg-core"; -export const schema = pgSchema(env.DB_SCHEMA || 'test') +export const schema = pgSchema(env.DB_SCHEMA || "test"); -export const fractalityTokenMigrations = schema.table('fractality_token_migrations', { - transactionHash: text('transaction_hash').primaryKey(), - migrationContractAddress: text('migration_contract_address'), - eventName: text('event_name'), - caller: text('caller'), - migrationAddress: text('migration_address'), - amount: text('amount'), - foundAt: text('found_at'), - status: text('status'), - migratedAt: text('migrated_at'), - migratedAmount: text('migrated_amount') -}) +export const fractalityTokenMigrations = schema.table( + "fractality_token_migrations", + { + transactionHash: text("transaction_hash").primaryKey(), + migrationContractAddress: text("migration_contract_address"), + eventName: text("event_name"), + caller: text("caller"), + migrationAddress: text("migration_address"), + amount: text("amount"), + foundAt: text("found_at"), + status: text("status"), + migratedAt: text("migrated_at"), + migratedAmount: text("migrated_amount"), + } +); diff --git a/env.ts b/env.ts index 28318e9..7921426 100644 --- a/env.ts +++ b/env.ts @@ -1,6 +1,6 @@ -import { z } from 'zod' -import dotenv from 'dotenv' -dotenv.config() +import { z } from "zod"; +import dotenv from "dotenv"; +dotenv.config(); const envSchema = z.object({ PRIVATE_KEY: z.string(), @@ -23,21 +23,21 @@ const envSchema = z.object({ BLOCK_START_NUMBER: z.string(), SAFETY_CUSHION_NUMBER_OF_BLOCKS: z.coerce.number(), REDIS_CONNECTION_STRING: z.string(), - REDIS_USE_TLS: z.preprocess((str) => str === 'true', z.boolean()) -}) + REDIS_USE_TLS: z.preprocess((str) => str === "true", z.boolean()), +}); -const parsedEnv = envSchema.safeParse(process.env) +const parsedEnv = envSchema.safeParse(process.env); if (!parsedEnv.success) { const formattedErrors = parsedEnv.error.errors.map((err) => ({ - path: err.path.join('.'), - message: err.message - })) + path: err.path.join("."), + message: err.message, + })); - console.error('Environment variable validation failed:', formattedErrors) - throw new Error('Invalid environment variables.') + console.error("Environment variable validation failed:", formattedErrors); + throw new Error("Invalid environment variables."); } -export type BotEnv = z.infer +export type BotEnv = z.infer; -export const env = parsedEnv.data +export const env = parsedEnv.data; diff --git a/index.ts b/index.ts index e0e9861..c54cd81 100644 --- a/index.ts +++ b/index.ts @@ -1,104 +1,123 @@ -import { PrivateKeyManager } from './libs/PrivateKeyManager' -import IORedis from 'ioredis' -const privateKeyManager = new PrivateKeyManager() -import { env } from './env' -import { BlockchainConnectionProvider } from './libs/BlockchainConnectionProvider' -import { Address } from 'viem' +import { PrivateKeyManager } from "./libs/PrivateKeyManager"; +import IORedis from "ioredis"; +const privateKeyManager = new PrivateKeyManager(); +import { env } from "./env"; +import { BlockchainConnectionProvider } from "./libs/BlockchainConnectionProvider"; +import { Address } from "viem"; import { addFractalityTokenMigrations, getUnmigratedFractalityTokenMigrations, finalizeHlMigrations, setHLMigrationStatus, - TokenMigration -} from './database' -import { HLMigration, MigrationRegisteredEvent, MigrationStatus } from './interfaces' -import { initializeDatabaseConnection } from './database' -import cron from 'node-cron' -import { PreviousBlockManager } from './libs/PreviousBlockManager' -import { HyperliquidManager } from './libs/HyperliquidManager' + TokenMigration, +} from "./database"; +import { + HLMigration, + MigrationRegisteredEvent, + MigrationStatus, +} from "./interfaces"; +import { initializeDatabaseConnection } from "./database"; +import cron from "node-cron"; +import { PreviousBlockManager } from "./libs/PreviousBlockManager"; +import { HyperliquidManager } from "./libs/HyperliquidManager"; async function main() { - await privateKeyManager.init() - await initializeDatabaseConnection() + await privateKeyManager.init(); + await initializeDatabaseConnection(); - const redisConnection = await initRedisConnection() + const redisConnection = await initRedisConnection(); - const hlManager = new HyperliquidManager(true, true, privateKeyManager.getPrivateKey()) + const hlManager = new HyperliquidManager( + true, + true, + privateKeyManager.getPrivateKey() + ); const blockchainConnectionProvider = new BlockchainConnectionProvider({ providerUrl: env.PROVIDER_URL, y2kTokenMigrationAddress: env.Y2K_TOKEN_MIGRATION_ADDRESS as Address, - frctRTokenMigrationAddress: env.FRCT_R_MIGRATION_ADDRESS as Address - }) + frctRTokenMigrationAddress: env.FRCT_R_MIGRATION_ADDRESS as Address, + }); - await hlManager.init(await blockchainConnectionProvider.getArbitrumTokenDecimals()) + await hlManager.init( + await blockchainConnectionProvider.getArbitrumTokenDecimals() + ); const blockManager = new PreviousBlockManager( redisConnection, BigInt(env.SAFETY_CUSHION_NUMBER_OF_BLOCKS), () => blockchainConnectionProvider.getCurrentBlockNumber() - ) + ); - console.log('starting cron job for migrations, running every 5 minutes') - cron.schedule('* * * * *', async () => { - const fromBlock = await blockManager.getFromBlockForScan() - const toBlock = await blockManager.setFromBlockForScanToCurrentBlock() - console.log(`looking for migrations from block ${fromBlock} to block ${toBlock}`) + console.log("starting cron job for migrations, running every 5 minutes"); + cron.schedule("* * * * *", async () => { + const fromBlock = await blockManager.getFromBlockForScan(); + const toBlock = await blockManager.setFromBlockForScanToCurrentBlock(); + console.log( + `looking for migrations from block ${fromBlock} to block ${toBlock}` + ); const y2kMigrations = await blockchainConnectionProvider.scanMigrations( env.Y2K_TOKEN_MIGRATION_ADDRESS as Address, fromBlock, toBlock - ) + ); const frctRMigrations = await blockchainConnectionProvider.scanMigrations( env.FRCT_R_MIGRATION_ADDRESS as Address, fromBlock, toBlock - ) - await addMigrationsToDatabase([...y2kMigrations, ...frctRMigrations]) + ); + await addMigrationsToDatabase([...y2kMigrations, ...frctRMigrations]); //get migrations that still have not been sent to hyperliquid - const unmigratedMigrations: TokenMigration[] = await getUnmigratedFractalityTokenMigrations() + const unmigratedMigrations: TokenMigration[] = + await getUnmigratedFractalityTokenMigrations(); //calcualate the amount of tokens to send to hyperliquid - const hlMigrations = await prepForHLMigration(hlManager, unmigratedMigrations) - console.log('hlMigrations', hlMigrations) - - const { successes, failures } = await hlManager.sendHLMigrations(hlMigrations) - console.log('successes', successes) - console.log('failures', failures) + const hlMigrations = await prepForHLMigration( + hlManager, + unmigratedMigrations + ); + console.log("hlMigrations", hlMigrations); + + const { successes, failures } = await hlManager.sendHLMigrations( + hlMigrations + ); + console.log("successes", successes); + console.log("failures", failures); try { - await finalizeHlMigrations(successes) + await finalizeHlMigrations(successes); } catch (error) { - console.error('FATAL ERROR: Error finalizing HL migrations', error) + console.error("FATAL ERROR: Error finalizing HL migrations", error); } - console.log('done') - }) + console.log("done"); + }); } async function prepForHLMigration( hlManager: HyperliquidManager, unmigratedMigrations: TokenMigration[] ): Promise { - const hlMigrations: HLMigration[] = [] + const hlMigrations: HLMigration[] = []; for (const unmigratedMigration of unmigratedMigrations) { if (unmigratedMigration.amount && unmigratedMigration.migrationAddress) { - const arbitrumAmount = BigInt(unmigratedMigration.amount) - const hlAmount = hlManager.decimalConversion!.convertToHlToken(arbitrumAmount) + const arbitrumAmount = BigInt(unmigratedMigration.amount); + const hlAmount = + hlManager.decimalConversion!.convertToHlToken(arbitrumAmount); hlMigrations.push({ originalTransactionHash: unmigratedMigration.transactionHash, hlTokenAmount: hlAmount, - sendToAddress: unmigratedMigration.migrationAddress - }) + sendToAddress: unmigratedMigration.migrationAddress, + }); } else { console.error( `migration with hash ${unmigratedMigration.transactionHash} has no amount or no migration address` - ) + ); } } - return hlMigrations + return hlMigrations; } async function initRedisConnection() { @@ -107,20 +126,23 @@ async function initRedisConnection() { enableReadyCheck: false, tls: env.REDIS_USE_TLS ? { - rejectUnauthorized: false + rejectUnauthorized: false, } - : undefined - }) + : undefined, + }); } async function addMigrationsToDatabase(migrations: MigrationRegisteredEvent[]) { try { - const result = await addFractalityTokenMigrations(migrations) //TODO: make this batch + const result = await addFractalityTokenMigrations(migrations); //TODO: make this batch console.log( `Inserted ${result.newMigrations.length} new migrations and found ${result.existingTxs.length} existing migrations` - ) - console.info(`existing migrations that already exist in the database`, result.existingTxs) + ); + console.info( + `existing migrations that already exist in the database`, + result.existingTxs + ); } catch (e) { - console.error('Error adding migration to database', e) + console.error("Error adding migration to database", e); } } diff --git a/interfaces.ts b/interfaces.ts index 684daed..68385a6 100644 --- a/interfaces.ts +++ b/interfaces.ts @@ -16,8 +16,7 @@ export interface HLMigration { } export enum MigrationStatus { - FOUND_ON_ARBITRUM = "FOUND_ON_ARBITRUM", - PREPPED_FOR_HL = "PREPPED_FOR_HL", - SENT_TO_HL = "SENT_TO_HL", - ERRORED_IN_SENDING_TO_HL = "ERRORED_IN_SENDING_TO_HL", + FOUND_ON_ARBITRUM = "FOUND_ON_ARBITRUM", //Just found on arbitrum, not filtered. + SENT_TO_HL = "SENT_TO_HL", //Sent to HL + ERRORED_IN_SENDING_TO_HL = "ERRORED_IN_SENDING_TO_HL", //Errored in sending to HL } From 9735e460b54a9e1a46aac83c3c836c6a0f32e70a Mon Sep 17 00:00:00 2001 From: Jose Herrera Date: Wed, 12 Feb 2025 19:00:27 -0500 Subject: [PATCH 4/6] - added variables into the terraform files - refactored so it can be run both manually with cron for testing and via lambda functions --- handler.ts | 19 ++++++ index.ts => migrationService.ts | 98 ++++++++++++++++++------------ package-lock.json | 83 ++++++++++++++++++++++++- package.json | 6 +- run.ts | 3 + terraform/environments/main.tfvars | 18 +++++- terraform/environments/test.tfvars | 18 +++++- 7 files changed, 198 insertions(+), 47 deletions(-) create mode 100644 handler.ts rename index.ts => migrationService.ts (62%) create mode 100644 run.ts diff --git a/handler.ts b/handler.ts new file mode 100644 index 0000000..57abd34 --- /dev/null +++ b/handler.ts @@ -0,0 +1,19 @@ +import { type Context, type Handler } from "aws-lambda"; + +import { main } from "./migrationService"; +interface ReportEvent { + DAGSTER_PIPES_CONTEXT: string; + DAGSTER_PIPES_MESSAGES: string; +} + +export const handler: Handler = async ( + event: ReportEvent, + context: Context +): Promise => { + try { + await main(false); + } catch (error) { + console.error("Error With Migration Service:", error); + throw error; + } +}; diff --git a/index.ts b/migrationService.ts similarity index 62% rename from index.ts rename to migrationService.ts index c54cd81..c9f360d 100644 --- a/index.ts +++ b/migrationService.ts @@ -21,7 +21,7 @@ import cron from "node-cron"; import { PreviousBlockManager } from "./libs/PreviousBlockManager"; import { HyperliquidManager } from "./libs/HyperliquidManager"; -async function main() { +export async function main(runWithCron: boolean) { await privateKeyManager.init(); await initializeDatabaseConnection(); @@ -49,51 +49,71 @@ async function main() { () => blockchainConnectionProvider.getCurrentBlockNumber() ); - console.log("starting cron job for migrations, running every 5 minutes"); - cron.schedule("* * * * *", async () => { - const fromBlock = await blockManager.getFromBlockForScan(); - const toBlock = await blockManager.setFromBlockForScanToCurrentBlock(); - console.log( - `looking for migrations from block ${fromBlock} to block ${toBlock}` + if (runWithCron) { + console.log("starting cron job for migrations, running every 5 minutes"); + cron.schedule("* * * * *", async () => { + await coreMigrationService( + blockManager, + blockchainConnectionProvider, + hlManager + ); + }); + } else { + await coreMigrationService( + blockManager, + blockchainConnectionProvider, + hlManager ); + } +} - const y2kMigrations = await blockchainConnectionProvider.scanMigrations( - env.Y2K_TOKEN_MIGRATION_ADDRESS as Address, - fromBlock, - toBlock - ); - const frctRMigrations = await blockchainConnectionProvider.scanMigrations( - env.FRCT_R_MIGRATION_ADDRESS as Address, - fromBlock, - toBlock - ); - await addMigrationsToDatabase([...y2kMigrations, ...frctRMigrations]); +export async function coreMigrationService( + blockManager: PreviousBlockManager, + blockchainConnectionProvider: BlockchainConnectionProvider, + hlManager: HyperliquidManager +) { + const fromBlock = await blockManager.getFromBlockForScan(); + const toBlock = await blockManager.setFromBlockForScanToCurrentBlock(); + console.log( + `looking for migrations from block ${fromBlock} to block ${toBlock}` + ); + + const y2kMigrations = await blockchainConnectionProvider.scanMigrations( + env.Y2K_TOKEN_MIGRATION_ADDRESS as Address, + fromBlock, + toBlock + ); + const frctRMigrations = await blockchainConnectionProvider.scanMigrations( + env.FRCT_R_MIGRATION_ADDRESS as Address, + fromBlock, + toBlock + ); + await addMigrationsToDatabase([...y2kMigrations, ...frctRMigrations]); - //get migrations that still have not been sent to hyperliquid - const unmigratedMigrations: TokenMigration[] = - await getUnmigratedFractalityTokenMigrations(); + //get migrations that still have not been sent to hyperliquid + const unmigratedMigrations: TokenMigration[] = + await getUnmigratedFractalityTokenMigrations(); - //calcualate the amount of tokens to send to hyperliquid - const hlMigrations = await prepForHLMigration( - hlManager, - unmigratedMigrations - ); - console.log("hlMigrations", hlMigrations); + //calcualate the amount of tokens to send to hyperliquid + const hlMigrations = await prepForHLMigration( + hlManager, + unmigratedMigrations + ); + console.log("hlMigrations", hlMigrations); - const { successes, failures } = await hlManager.sendHLMigrations( - hlMigrations - ); - console.log("successes", successes); - console.log("failures", failures); + const { successes, failures } = await hlManager.sendHLMigrations( + hlMigrations + ); + console.log("successes", successes); + console.log("failures", failures); - try { - await finalizeHlMigrations(successes); - } catch (error) { - console.error("FATAL ERROR: Error finalizing HL migrations", error); - } + try { + await finalizeHlMigrations(successes); + } catch (error) { + console.error("FATAL ERROR: Error finalizing HL migrations", error); + } - console.log("done"); - }); + console.log("done"); } async function prepForHLMigration( diff --git a/package-lock.json b/package-lock.json index e948d12..2f1bd65 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,8 @@ "dependencies": { "@aws-sdk/client-secrets-manager": "^3.692.0", "@aws-sdk/credential-providers": "^3.692.0", + "@types/aws-lambda": "^8.10.147", + "aws-lambda": "^1.0.7", "aws-sdk": "^2.1692.0", "axios": "^1.7.7", "dotenv": "^16.4.5", @@ -1410,6 +1412,11 @@ "typescript": ">=4.7.0" } }, + "node_modules/@types/aws-lambda": { + "version": "8.10.147", + "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.147.tgz", + "integrity": "sha512-nD0Z9fNIZcxYX5Mai2CTmFD7wX7UldCkW2ezCF8D1T5hdiLsnTWDGRpfRYntU6VjTdLQjOvyszru7I1c1oCQew==" + }, "node_modules/@types/node": { "version": "22.10.7", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.7.tgz", @@ -1523,6 +1530,14 @@ "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, "node_modules/array-back": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", @@ -1551,6 +1566,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/aws-lambda": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/aws-lambda/-/aws-lambda-1.0.7.tgz", + "integrity": "sha512-9GNFMRrEMG5y3Jvv+V4azWvc+qNWdWLTjDdhf/zgMlz8haaaLWv0xeAIWxz9PuWUBawsVxy0zZotjCdR3Xq+2w==", + "dependencies": { + "aws-sdk": "^2.814.0", + "commander": "^3.0.2", + "js-yaml": "^3.14.1", + "watchpack": "^2.0.0-beta.10" + }, + "bin": { + "lambda": "bin/lambda" + } + }, "node_modules/aws-sdk": { "version": "2.1692.0", "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1692.0.tgz", @@ -1895,6 +1924,11 @@ "node": ">=8" } }, + "node_modules/commander": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", + "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==" + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -2155,6 +2189,18 @@ "node": ">=0.8.0" } }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/ethers": { "version": "6.13.5", "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.13.5.tgz", @@ -2408,6 +2454,11 @@ "node": ">= 6" } }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" + }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -2422,8 +2473,7 @@ "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, "node_modules/has-flag": { "version": "3.0.0", @@ -2716,6 +2766,18 @@ "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", "dev": true }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", @@ -3108,6 +3170,11 @@ "node": ">=10" } }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" + }, "node_modules/standard-as-callback": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", @@ -3449,6 +3516,18 @@ } } }, + "node_modules/watchpack": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", + "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/which-typed-array": { "version": "1.1.18", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.18.tgz", diff --git a/package.json b/package.json index 2b21fbd..3245dca 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,8 @@ "description": "", "main": "index.js", "scripts": { - "start": "node dist/index.js", - "dev": "nodemon index.ts", + "start": "node dist/run.js", + "dev": "nodemon run.ts", "build": "tsc", "format": "prettier --write \"**/*.ts\"" }, @@ -14,6 +14,8 @@ "dependencies": { "@aws-sdk/client-secrets-manager": "^3.692.0", "@aws-sdk/credential-providers": "^3.692.0", + "@types/aws-lambda": "^8.10.147", + "aws-lambda": "^1.0.7", "aws-sdk": "^2.1692.0", "axios": "^1.7.7", "dotenv": "^16.4.5", diff --git a/run.ts b/run.ts new file mode 100644 index 0000000..08b47ed --- /dev/null +++ b/run.ts @@ -0,0 +1,3 @@ +import { main } from "./migrationService"; + +main(true); diff --git a/terraform/environments/main.tfvars b/terraform/environments/main.tfvars index 4b563ea..0e55aca 100644 --- a/terraform/environments/main.tfvars +++ b/terraform/environments/main.tfvars @@ -4,10 +4,24 @@ environment = "main" vpc_id = "" subnet_ids = [] -provider_url = "" +private_key = "" public_address = "" +mnemonic_secret_arn = "" +aws_region = "" +testnet = false token_address = "" +provider_url = "" y2k_token_migration_address = "" frct_r_migration_address = "" +node_env = "" +db_name = "" +db_host = "" +db_port = "" +db_user = "" +db_password = "" +db_schema = "" +blockchain_environment = "arbitrum" block_start_number = "" -safe_cushion_number_of_blocks = "" +safety_cushion_number_of_blocks = "250" +redis_connection_string = "" +redis_use_tls = "" \ No newline at end of file diff --git a/terraform/environments/test.tfvars b/terraform/environments/test.tfvars index f334cbe..7d052b0 100644 --- a/terraform/environments/test.tfvars +++ b/terraform/environments/test.tfvars @@ -4,10 +4,24 @@ environment = "test" vpc_id = "" subnet_ids = [] -provider_url = "" +private_key = "" public_address = "" +mnemonic_secret_arn = "" +aws_region = "" +testnet = true token_address = "" +provider_url = "" y2k_token_migration_address = "" frct_r_migration_address = "" +node_env = "" +db_name = "" +db_host = "" +db_port = "" +db_user = "" +db_password = "" +db_schema = "" +blockchain_environment = test block_start_number = "" -safe_cushion_number_of_blocks = "" +safety_cushion_number_of_blocks = "250" +redis_connection_string = "" +redis_use_tls = "" From 218ddf0622cfd48e102ba0cc1bd8399e91a00889 Mon Sep 17 00:00:00 2001 From: Jose Herrera Date: Wed, 12 Feb 2025 21:37:03 -0500 Subject: [PATCH 5/6] filled in more non secret env vars --- terraform/environments/test.tfvars | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/terraform/environments/test.tfvars b/terraform/environments/test.tfvars index 7d052b0..599d93a 100644 --- a/terraform/environments/test.tfvars +++ b/terraform/environments/test.tfvars @@ -5,14 +5,14 @@ vpc_id = "" subnet_ids = [] private_key = "" -public_address = "" +public_address = "0x5B5fe168C17A74Cd32B2A2b5dfB30aDA3edF94d6" mnemonic_secret_arn = "" aws_region = "" testnet = true -token_address = "" +token_address = "0xccbee9ae8e6666c53e55058c7b97ccee" provider_url = "" -y2k_token_migration_address = "" -frct_r_migration_address = "" +y2k_token_migration_address = "0x2839449acf90EDee7055FdA315875e9539359aA0" +frct_r_migration_address = "0xB78028Ca8246d5E8F08Fd656F9337C4E77Cd2389" node_env = "" db_name = "" db_host = "" @@ -21,7 +21,7 @@ db_user = "" db_password = "" db_schema = "" blockchain_environment = test -block_start_number = "" +block_start_number = "119867300" safety_cushion_number_of_blocks = "250" redis_connection_string = "" redis_use_tls = "" From b08537cdbbe4d9eb0cc26471969d8985c6612693 Mon Sep 17 00:00:00 2001 From: dylmanning Date: Mon, 17 Feb 2025 21:40:04 +1100 Subject: [PATCH 6/6] Prepare deployment --- .github/workflows/deploy.yaml | 61 ++++++++++++++++++++++++++++++ handler.ts | 20 ++++------ package-lock.json | 1 + terraform/environments/main.tfvars | 26 +++---------- terraform/environments/test.tfvars | 33 ++++++---------- terraform/lambda.tf | 7 ++-- terraform/var.tf | 10 ++++- 7 files changed, 100 insertions(+), 58 deletions(-) create mode 100644 .github/workflows/deploy.yaml diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml new file mode 100644 index 0000000..9c656c1 --- /dev/null +++ b/.github/workflows/deploy.yaml @@ -0,0 +1,61 @@ +name: Build/Deploy + +on: + push: + branches: + - main + - test + - '*' + pull_request: + branches: + - main + - test + +jobs: + build: + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write + + if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/test') + environment: ${{ github.event_name == 'pull_request' && github.base_ref || github.ref_name }} + + env: + DESTINATION_BRANCH: ${{ github.event_name == 'pull_request' && github.base_ref || github.ref_name }} + + steps: + - uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up Terraform + uses: hashicorp/setup-terraform@v1 + with: + terraform_wrapper: false + + - name: Terraform Init + run: terraform init -backend-config="environments/${{ env.DESTINATION_BRANCH }}.backend.tfvars" + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + working-directory: ./terraform + + - name: Set Version + if: github.ref == 'refs/heads/main' + run: echo "PROJECT_VERSION=$(git describe --tags `git rev-list --tags --max-count=1`)" >> $GITHUB_ENV + + - name: Terraform Deploy + run: | + terraform apply -auto-approve \ + -var-file="environments/${{ env.DESTINATION_BRANCH }}.tfvars" \ + -var="account_id=${{ vars.AWS_ACCOUNT_ID }}" \ + -var="region=${{ vars.AWS_REGION }}" \ + -var="project_version=${{ env.PROJECT_VERSION }}" \ + -var="tesnet_provider_url=${{ secrets.TESTNET_PROVIDER_URL }}" \ + -var="mainnet_provider_key=${{ secrets.MAINNET_PROVIDER_KEY }}" + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + PROJECT_VERSION: ${{ env.PROJECT_VERSION }} + working-directory: ./terraform diff --git a/handler.ts b/handler.ts index 57abd34..4ec2a77 100644 --- a/handler.ts +++ b/handler.ts @@ -1,19 +1,15 @@ -import { type Context, type Handler } from "aws-lambda"; +import { type Context, type Handler } from 'aws-lambda' -import { main } from "./migrationService"; -interface ReportEvent { - DAGSTER_PIPES_CONTEXT: string; - DAGSTER_PIPES_MESSAGES: string; -} +import { main } from './migrationService' -export const handler: Handler = async ( - event: ReportEvent, +export const handler: Handler = async ( + event: void, context: Context ): Promise => { try { - await main(false); + await main(false) } catch (error) { - console.error("Error With Migration Service:", error); - throw error; + console.error('Error With Migration Service:', error) + throw error } -}; +} diff --git a/package-lock.json b/package-lock.json index 2f1bd65..990a9cf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1570,6 +1570,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/aws-lambda/-/aws-lambda-1.0.7.tgz", "integrity": "sha512-9GNFMRrEMG5y3Jvv+V4azWvc+qNWdWLTjDdhf/zgMlz8haaaLWv0xeAIWxz9PuWUBawsVxy0zZotjCdR3Xq+2w==", + "license": "MIT", "dependencies": { "aws-sdk": "^2.814.0", "commander": "^3.0.2", diff --git a/terraform/environments/main.tfvars b/terraform/environments/main.tfvars index 0e55aca..da82a29 100644 --- a/terraform/environments/main.tfvars +++ b/terraform/environments/main.tfvars @@ -4,24 +4,10 @@ environment = "main" vpc_id = "" subnet_ids = [] -private_key = "" -public_address = "" -mnemonic_secret_arn = "" -aws_region = "" -testnet = false -token_address = "" -provider_url = "" -y2k_token_migration_address = "" -frct_r_migration_address = "" -node_env = "" -db_name = "" -db_host = "" -db_port = "" -db_user = "" -db_password = "" -db_schema = "" -blockchain_environment = "arbitrum" -block_start_number = "" +public_address = "" +token_address = "" +provider_url = "" +y2k_token_migration_address = "" +frct_r_migration_address = "" +block_start_number = "" safety_cushion_number_of_blocks = "250" -redis_connection_string = "" -redis_use_tls = "" \ No newline at end of file diff --git a/terraform/environments/test.tfvars b/terraform/environments/test.tfvars index 599d93a..f085268 100644 --- a/terraform/environments/test.tfvars +++ b/terraform/environments/test.tfvars @@ -1,27 +1,16 @@ name = "migration-service-test" project = "fractality" environment = "test" -vpc_id = "" -subnet_ids = [] +vpc_id = "vpc-08ae44a5cd755d8b0" +subnet_ids = ["subnet-05fe54f7cba0f2fd5", "subnet-07452d48590bce532"] -private_key = "" -public_address = "0x5B5fe168C17A74Cd32B2A2b5dfB30aDA3edF94d6" -mnemonic_secret_arn = "" -aws_region = "" -testnet = true -token_address = "0xccbee9ae8e6666c53e55058c7b97ccee" -provider_url = "" -y2k_token_migration_address = "0x2839449acf90EDee7055FdA315875e9539359aA0" -frct_r_migration_address = "0xB78028Ca8246d5E8F08Fd656F9337C4E77Cd2389" -node_env = "" -db_name = "" -db_host = "" -db_port = "" -db_user = "" -db_password = "" -db_schema = "" -blockchain_environment = test -block_start_number = "119867300" + +testnet = true +public_address = "0x5B5fe168C17A74Cd32B2A2b5dfB30aDA3edF94d6" +token_address = "0xccbee9ae8e6666c53e55058c7b97ccee" +provider_url = "https://arb-sepolia.g.alchemy.com/v2/SA1EqG4RW6GcciKBnPtu8n6OJqxy164t" +y2k_token_migration_address = "0x2839449acf90EDee7055FdA315875e9539359aA0" +frct_r_migration_address = "0xB78028Ca8246d5E8F08Fd656F9337C4E77Cd2389" +block_start_number = "119867300" safety_cushion_number_of_blocks = "250" -redis_connection_string = "" -redis_use_tls = "" + diff --git a/terraform/lambda.tf b/terraform/lambda.tf index 36ab04c..ca8309c 100644 --- a/terraform/lambda.tf +++ b/terraform/lambda.tf @@ -9,7 +9,7 @@ locals { resource "aws_security_group" "lambda_sg" { name = "${var.name}-lambda-sg-${var.environment}" description = "Security group for Lambda functions" - vpc_id = "vpc-08ae44a5cd755d8b0" + vpc_id = var.vpc_id ingress { description = "Allow Lambda to access RDS on port 5432" @@ -43,10 +43,11 @@ resource "aws_lambda_function" "default" { environment { variables = { - PROVIDER_URL = var.provider_url + PROVIDER_URL = var.environment == "main" ? var.mainnet_provider_url : var.testnet_provider_url BLOCKCHAIN_ENVIRONMENT = var.environment PUBLIC_ADDRESS = var.public_address TOKEN_ADDRESS = var.token_address + TESTNET = var.testnet MNEMONIC_SECRET_ARN = data.aws_secretsmanager_secret.mnemonic.arn DB_USER = local.db_username DB_PASSWORD = local.db_password @@ -63,7 +64,7 @@ resource "aws_lambda_function" "default" { } vpc_config { - subnet_ids = ["subnet-05fe54f7cba0f2fd5", "subnet-07452d48590bce532"] + subnet_ids = var.subnet_ids security_group_ids = [aws_security_group.lambda_sg.id] } } diff --git a/terraform/var.tf b/terraform/var.tf index d314dd4..9a4fa30 100644 --- a/terraform/var.tf +++ b/terraform/var.tf @@ -41,7 +41,11 @@ variable "db_instance_id" { type = string } -variable "provider_url" { +variable "testnet_provider_url" { + type = string +} + +variable "mainnet_provider_url" { type = string } @@ -68,3 +72,7 @@ variable "block_start_number" { variable "safety_cushion_number_of_blocks" { type = string } + +variable "testnet" { + type = bool +}