diff --git a/backend/.eslintrc b/backend/.eslintrc index 1ec4e472..d7c19c01 100644 --- a/backend/.eslintrc +++ b/backend/.eslintrc @@ -2,11 +2,11 @@ "parser": "@typescript-eslint/parser", "parserOptions": { "ecmaVersion": 2020, - "sourceType": "script", + "sourceType": "script" }, "plugins": ["@typescript-eslint"], "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"], "rules": { - "no-undef": "off", - }, + "no-undef": "off" + } } diff --git a/backend/.prettierrc b/backend/.prettierrc index b2095be8..49955e2e 100644 --- a/backend/.prettierrc +++ b/backend/.prettierrc @@ -1,4 +1,5 @@ { "semi": false, - "singleQuote": true + "singleQuote": true, + "trailingComma": "none" } diff --git a/backend/src/handlers/discord-signed-digest.ts b/backend/src/handlers/discord-signed-digest.ts index 6992b6c5..06599715 100644 --- a/backend/src/handlers/discord-signed-digest.ts +++ b/backend/src/handlers/discord-signed-digest.ts @@ -9,7 +9,7 @@ interface DiscordSignedDigestRequest { } export const signDiscordMessage = async ( - event: APIGatewayProxyEvent, + event: APIGatewayProxyEvent ): Promise => { try { const requestBody = JSON.parse(event.body!) as DiscordSignedDigestRequest @@ -32,14 +32,14 @@ export const signDiscordMessage = async ( body: JSON.stringify({ signature: Buffer.from(signedDigest.signature).toString('hex'), publicKey: Buffer.from(signedDigest.publicKey).toString('hex'), // The dispenser guard's public key - fullMessage: Buffer.from(signedDigest.fullMessage).toString('hex'), - }), + fullMessage: Buffer.from(signedDigest.fullMessage).toString('hex') + }) } } catch (err) { console.error('Error generating signed discord digest', err) return { statusCode: 500, - body: JSON.stringify({ error: 'Internal server error' }), + body: JSON.stringify({ error: 'Internal server error' }) } } } @@ -47,12 +47,12 @@ export const signDiscordMessage = async ( async function loadDispenserGuard() { // TODO: Update secret name based on the secret you created in the AWS Secrets Manager const secretData = await getSecret( - process.env.DISPENSER_KEY_SECRET_NAME ?? 'xl-dispenser-guard-key', + process.env.DISPENSER_KEY_SECRET_NAME ?? 'xl-dispenser-guard-key' ) const dispenserGuardKey = secretData.key const dispenserGuard = Keypair.fromSecretKey( - Uint8Array.from(JSON.parse(dispenserGuardKey)), + Uint8Array.from(JSON.parse(dispenserGuardKey)) ) return dispenserGuard @@ -63,15 +63,15 @@ function validatePublicKey(publicKey?: string) { return { statusCode: 400, body: JSON.stringify({ - error: "Must provide the 'publicKey' query parameter", - }), + error: "Must provide the 'publicKey' query parameter" + }) } } if (typeof publicKey !== 'string') { return { statusCode: 400, - body: JSON.stringify({ error: "Invalid 'publicKey' query parameter" }), + body: JSON.stringify({ error: "Invalid 'publicKey' query parameter" }) } } @@ -80,26 +80,26 @@ function validatePublicKey(publicKey?: string) { } catch { return { statusCode: 400, - body: JSON.stringify({ error: "Invalid 'publicKey' query parameter" }), + body: JSON.stringify({ error: "Invalid 'publicKey' query parameter" }) } } } function validateAccessTokenAndDiscordId( AccessToken?: string, - discordId?: string, + discordId?: string ) { if (!AccessToken) { return { statusCode: 400, - body: JSON.stringify({ error: 'Must provide discord auth token' }), + body: JSON.stringify({ error: 'Must provide discord auth token' }) } } if (!discordId) { return { statusCode: 400, - body: JSON.stringify({ error: 'Must provide discord id' }), + body: JSON.stringify({ error: 'Must provide discord id' }) } } } diff --git a/backend/src/handlers/fund-transactions.ts b/backend/src/handlers/fund-transactions.ts index e7ebb9b5..db64ff5d 100644 --- a/backend/src/handlers/fund-transactions.ts +++ b/backend/src/handlers/fund-transactions.ts @@ -3,7 +3,7 @@ import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda' import { getSecret } from '../utils' import { checkTransactions, - deserializeTransactions, + deserializeTransactions } from '../utils/fundTransactions' import { Keypair } from '@solana/web3.js' @@ -12,7 +12,7 @@ interface FundTransactionRequest { } export const fundTransaction = async ( - event: APIGatewayProxyEvent, + event: APIGatewayProxyEvent ): Promise => { try { const requestBody = JSON.parse(event.body!) as FundTransactionRequest @@ -23,7 +23,7 @@ export const fundTransaction = async ( if (!isTransactionsValid) { return { statusCode: 403, - body: JSON.stringify({ error: 'Unauthorized transactions' }), + body: JSON.stringify({ error: 'Unauthorized transactions' }) } } @@ -33,14 +33,14 @@ export const fundTransaction = async ( return { statusCode: 200, body: JSON.stringify({ - signedTransactions: signedTransactions.map((tx) => tx.serialize()), - }), + signedTransactions: signedTransactions.map((tx) => tx.serialize()) + }) } } catch (err) { console.error('Error fully signing transactions', err) return { statusCode: 500, - body: JSON.stringify({ error: 'Internal server error' }), + body: JSON.stringify({ error: 'Internal server error' }) } } } @@ -49,22 +49,21 @@ function validateFundTransactions(transactions: unknown) { if (!Array.isArray(transactions) || transactions.length === 0) { return { statusCode: 400, - body: JSON.stringify({ error: 'Must provide transactions' }), + body: JSON.stringify({ error: 'Must provide transactions' }) } } if (transactions.length >= 10) { return { statusCode: 400, - body: JSON.stringify({ error: 'Too many transactions' }), + body: JSON.stringify({ error: 'Too many transactions' }) } } } async function loadFunderWallet(): Promise { const secretData = await getSecret( - process.env.FUNDER_WALLET_KEY_SECRET_NAME ?? - 'xli-test-secret-funder-wallet', + process.env.FUNDER_WALLET_KEY_SECRET_NAME ?? 'xli-test-secret-funder-wallet' ) const funderWalletKey = secretData.key diff --git a/backend/src/handlers/helloworld.ts b/backend/src/handlers/helloworld.ts index 1aad52d2..5526d262 100644 --- a/backend/src/handlers/helloworld.ts +++ b/backend/src/handlers/helloworld.ts @@ -4,7 +4,7 @@ export const handler = async () => { if (!process.env.SECRET_NAME) { return { statusCode: 500, - body: JSON.stringify({ error: 'SECRET_NAME is not set' }), + body: JSON.stringify({ error: 'SECRET_NAME is not set' }) } } @@ -14,6 +14,6 @@ export const handler = async () => { console.log(`Hello ${target}`) return { statusCode: 200, - body: JSON.stringify({ message: `Hello ${target}` }), + body: JSON.stringify({ message: `Hello ${target}` }) } } diff --git a/backend/src/utils/discord.ts b/backend/src/utils/discord.ts index 338d9076..cdfee875 100644 --- a/backend/src/utils/discord.ts +++ b/backend/src/utils/discord.ts @@ -8,13 +8,13 @@ const DISCORD_AUTH_ME_URL = 'https://discord.com/api/v10/users/@me' export async function isAccessTokenValid( discordId: string, - token: string, + token: string ): Promise { try { const response = await fetch(DISCORD_AUTH_ME_URL, { headers: { - Authorization: `Bearer ${token}`, - }, + Authorization: `Bearer ${token}` + } }) const userData = await response.json() @@ -31,26 +31,26 @@ const coder = new anchor.BorshCoder(IDL as any) function hardDriveSignDigest( fullMessage: Uint8Array, - keypair: Keypair, + keypair: Keypair ): SignedMessage { return { publicKey: keypair.publicKey.toBytes(), signature: nacl.sign.detached(fullMessage, keypair.secretKey), recoveryId: undefined, - fullMessage, + fullMessage } } export function signDiscordDigest( username: string, claimant: PublicKey, - dispenserGuard: Keypair, + dispenserGuard: Keypair ): SignedMessage { return hardDriveSignDigest( coder.types.encode('DiscordMessage', { username, - claimant, + claimant }), - dispenserGuard, + dispenserGuard ) } diff --git a/backend/src/utils/fundTransactions.ts b/backend/src/utils/fundTransactions.ts index dcc97080..2acc087e 100644 --- a/backend/src/utils/fundTransactions.ts +++ b/backend/src/utils/fundTransactions.ts @@ -3,18 +3,18 @@ import { Ed25519Program, PublicKey, Secp256k1Program, - VersionedTransaction, + VersionedTransaction } from '@solana/web3.js' import { getSecret } from './index' const SET_COMPUTE_UNIT_LIMIT_DISCRIMINANT = 2 export function deserializeTransactions( - transactions: unknown, + transactions: unknown ): VersionedTransaction[] { try { return (transactions as Uint8Array[]).map((serializedTx) => - VersionedTransaction.deserialize(Buffer.from(serializedTx)), + VersionedTransaction.deserialize(Buffer.from(serializedTx)) ) } catch (err) { console.error('Failed to deserialize transactions', err) @@ -25,7 +25,7 @@ export function deserializeTransactions( async function loadTokenDispenserProgramId(): Promise { const secretData = await getSecret( process.env.TOKEN_DISPENSER_PROGRAM_ID_SECRET_NAME ?? - 'xli-test-secret-token-dispenser-program-id', + 'xli-test-secret-token-dispenser-program-id' ) const programId = secretData.target @@ -38,20 +38,18 @@ async function loadWhitelistedProgramIds(): Promise { PROGRAM_ID, Secp256k1Program.programId, Ed25519Program.programId, - ComputeBudgetProgram.programId, + ComputeBudgetProgram.programId ] } export function checkAllProgramsWhitelisted( transaction: VersionedTransaction, - whitelist: PublicKey[], + whitelist: PublicKey[] ): boolean { for (const ix of transaction.message.compiledInstructions) { if ( !whitelist.some((program) => - transaction.message.staticAccountKeys[ix.programIdIndex].equals( - program, - ), + transaction.message.staticAccountKeys[ix.programIdIndex].equals(program) ) ) { return false @@ -65,12 +63,12 @@ export function checkV0(transaction: VersionedTransaction) { } export function checkSetComputeBudgetInstructionsAreSetComputeUnitLimit( - transaction: VersionedTransaction, + transaction: VersionedTransaction ) { for (const ix of transaction.message.compiledInstructions) { if ( transaction.message.staticAccountKeys[ix.programIdIndex].equals( - ComputeBudgetProgram.programId, + ComputeBudgetProgram.programId ) ) { if (ix.data[0] !== SET_COMPUTE_UNIT_LIMIT_DISCRIMINANT) { @@ -83,7 +81,7 @@ export function checkSetComputeBudgetInstructionsAreSetComputeUnitLimit( export function checkProgramAppears( transaction: VersionedTransaction, - program: PublicKey, + program: PublicKey ): boolean { for (const ix of transaction.message.compiledInstructions) { if ( @@ -96,7 +94,7 @@ export function checkProgramAppears( } export function countTotalSignatures( - transaction: VersionedTransaction, + transaction: VersionedTransaction ): number { return ( transaction.signatures.length + @@ -107,12 +105,12 @@ export function countTotalSignatures( export function countPrecompiledSignatures( transaction: VersionedTransaction, - program: PublicKey, + program: PublicKey ): number { return transaction.message.compiledInstructions .filter((ix) => { return transaction.message.staticAccountKeys[ix.programIdIndex].equals( - program, + program ) }) .reduce((acc, ix) => acc + ix.data[0], 0) @@ -120,7 +118,7 @@ export function countPrecompiledSignatures( // TODO: Verify if this is the expected behavior export function checkNumberOfSignatures( - transaction: VersionedTransaction, + transaction: VersionedTransaction ): boolean { return countTotalSignatures(transaction) <= 3 } @@ -128,7 +126,7 @@ export function checkNumberOfSignatures( export function checkTransaction( transaction: VersionedTransaction, tokenDispenser: PublicKey, - whitelist: PublicKey[], + whitelist: PublicKey[] ): boolean { // TODO: Also check if priority fee/compute unit price is set, also can use helius api here to verify with some diff percentage return ( @@ -141,11 +139,11 @@ export function checkTransaction( } export async function checkTransactions( - transactions: VersionedTransaction[], + transactions: VersionedTransaction[] ): Promise { const whitelist = await loadWhitelistedProgramIds() return transactions.every((tx) => - checkTransaction(tx, whitelist[0], whitelist), + checkTransaction(tx, whitelist[0], whitelist) ) } diff --git a/backend/src/utils/index.ts b/backend/src/utils/index.ts index c94081cc..e8b36f88 100644 --- a/backend/src/utils/index.ts +++ b/backend/src/utils/index.ts @@ -1,7 +1,7 @@ // Note: layers code that is shared across lambda functions import { SecretsManagerClient, - GetSecretValueCommand, + GetSecretValueCommand } from '@aws-sdk/client-secrets-manager' const client = new SecretsManagerClient({ region: 'us-east-2' }) // Ensure this matches the region of your secret