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/database/schema.ts b/database/schema.ts index 847489b..a466894 100644 --- a/database/schema.ts +++ b/database/schema.ts @@ -2,7 +2,7 @@ import { env } from "../env"; 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", diff --git a/env.ts b/env.ts index dea86ee..7921426 100644 --- a/env.ts +++ b/env.ts @@ -18,6 +18,7 @@ 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(), diff --git a/handler.ts b/handler.ts new file mode 100644 index 0000000..4ec2a77 --- /dev/null +++ b/handler.ts @@ -0,0 +1,15 @@ +import { type Context, type Handler } from 'aws-lambda' + +import { main } from './migrationService' + +export const handler: Handler = async ( + event: void, + context: Context +): Promise => { + try { + await main(false) + } catch (error) { + console.error('Error With Migration Service:', error) + throw error + } +} 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 } diff --git a/index.ts b/migrationService.ts similarity index 62% rename from index.ts rename to migrationService.ts index 70cadb7..c9f360d 100644 --- a/index.ts +++ b/migrationService.ts @@ -20,7 +20,8 @@ import { initializeDatabaseConnection } from "./database"; 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(); @@ -48,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( @@ -145,5 +166,3 @@ async function addMigrationsToDatabase(migrations: MigrationRegisteredEvent[]) { console.error("Error adding migration to database", e); } } - -main(); diff --git a/package-lock.json b/package-lock.json index e948d12..990a9cf 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,21 @@ "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==", + "license": "MIT", + "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 +1925,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 +2190,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 +2455,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 +2474,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 +2767,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 +3171,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 +3517,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/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..da82a29 --- /dev/null +++ b/terraform/environments/main.tfvars @@ -0,0 +1,13 @@ +name = "migration-service" +project = "fractality" +environment = "main" +vpc_id = "" +subnet_ids = [] + +public_address = "" +token_address = "" +provider_url = "" +y2k_token_migration_address = "" +frct_r_migration_address = "" +block_start_number = "" +safety_cushion_number_of_blocks = "250" 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..f085268 --- /dev/null +++ b/terraform/environments/test.tfvars @@ -0,0 +1,16 @@ +name = "migration-service-test" +project = "fractality" +environment = "test" +vpc_id = "vpc-08ae44a5cd755d8b0" +subnet_ids = ["subnet-05fe54f7cba0f2fd5", "subnet-07452d48590bce532"] + + +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" + 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..ca8309c --- /dev/null +++ b/terraform/lambda.tf @@ -0,0 +1,87 @@ +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 = var.vpc_id + + 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.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 + 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 = var.subnet_ids + 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..d286401 --- /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_MIGRATION_${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..9a4fa30 --- /dev/null +++ b/terraform/var.tf @@ -0,0 +1,78 @@ +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 "testnet_provider_url" { + type = string +} + +variable "mainnet_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 +} + +variable "testnet" { + type = bool +}