diff --git a/backend/migrations/20240611000002-create-sponsorship-policies.cjs b/backend/migrations/20240611000002-create-sponsorship-policies.cjs index 6936475..f65ee33 100644 --- a/backend/migrations/20240611000002-create-sponsorship-policies.cjs +++ b/backend/migrations/20240611000002-create-sponsorship-policies.cjs @@ -65,6 +65,11 @@ async function up({ context: queryInterface }) { allowNull: true, field: 'END_DATE' }, + globalMaxApplicable: { + type: Sequelize.BOOLEAN, + defaultValue: false, + field: 'GLOBAL_MAX_APPLICABLE' + }, globalMaximumUsd: { type: Sequelize.DECIMAL(10, 4), // max 10 digits, 4 of which can be after the decimal point allowNull: true, @@ -80,6 +85,11 @@ async function up({ context: queryInterface }) { allowNull: true, field: 'GLOBAL_MAX_OP_COUNT' }, + perUserMaxApplicable: { + type: Sequelize.BOOLEAN, + defaultValue: false, + field: 'PER_USER_MAX_APPLICABLE' + }, perUserMaximumUsd: { type: Sequelize.DECIMAL(10, 4), // max 10 digits, 4 of which can be after the decimal point allowNull: true, @@ -95,6 +105,11 @@ async function up({ context: queryInterface }) { allowNull: true, field: 'PER_USER_MAX_OP_COUNT' }, + perOpMaxApplicable: { + type: Sequelize.BOOLEAN, + defaultValue: false, + field: 'PER_OP_MAX_APPLICABLE' + }, perOpMaximumUsd: { type: Sequelize.DECIMAL(10, 4), // max 10 digits, 4 of which can be after the decimal point allowNull: true, @@ -105,10 +120,15 @@ async function up({ context: queryInterface }) { allowNull: true, field: 'PER_OP_MAX_NATIVE' }, - contractRestrictions: { - type: Sequelize.TEXT, + addressAllowList: { + type: Sequelize.ARRAY(Sequelize.STRING), + allowNull: true, + field: 'ADDRESS_ALLOW_LIST' + }, + addressBlockList: { + type: Sequelize.ARRAY(Sequelize.STRING), allowNull: true, - field: 'CONTRACT_RESTRICTIONS' + field: 'ADDRESS_BLOCK_LIST' }, createdAt: { type: Sequelize.DATE, diff --git a/backend/src/models/sponsorship-policy.ts b/backend/src/models/sponsorship-policy.ts index ec2f1b0..bffc487 100644 --- a/backend/src/models/sponsorship-policy.ts +++ b/backend/src/models/sponsorship-policy.ts @@ -12,15 +12,19 @@ export class SponsorshipPolicy extends Model { public isPerpetual!: boolean; public startTime!: Date | null; public endTime!: Date | null; + public globalMaximumApplicable: boolean = false; public globalMaximumUsd!: number | null; public globalMaximumNative!: number | null; public globalMaximumOpCount!: number | null; + public perUserMaximumApplicable: boolean = false; public perUserMaximumUsd!: number | null; public perUserMaximumNative!: number | null; public perUserMaximumOpCount!: number | null; + public perOpMaximumApplicable: boolean = false; public perOpMaximumUsd!: number | null; public perOpMaximumNative!: number | null; - public contractRestrictions!: string | null; + public addressAllowList: string[] | null = null; + public addressBlockList: string[] | null = null; public readonly createdAt!: Date; public readonly updatedAt!: Date; @@ -108,6 +112,11 @@ export function initializeSponsorshipPolicyModel(sequelize: Sequelize, schema: s allowNull: true, field: 'END_DATE' }, + globalMaximumApplicable: { + type: DataTypes.BOOLEAN, + defaultValue: false, + field: 'GLOBAL_MAX_APPLICABLE' + }, globalMaximumUsd: { type: DataTypes.DECIMAL(10, 4), // max 10 digits, 4 of which can be after the decimal point allowNull: true, @@ -123,6 +132,11 @@ export function initializeSponsorshipPolicyModel(sequelize: Sequelize, schema: s allowNull: true, field: 'GLOBAL_MAX_OP_COUNT' }, + perUserMaximumApplicable: { + type: DataTypes.BOOLEAN, + defaultValue: false, + field: 'PER_USER_MAX_APPLICABLE' + }, perUserMaximumUsd: { type: DataTypes.DECIMAL(10, 4), // max 10 digits, 4 of which can be after the decimal point allowNull: true, @@ -138,6 +152,11 @@ export function initializeSponsorshipPolicyModel(sequelize: Sequelize, schema: s allowNull: true, field: 'PER_USER_MAX_OP_COUNT' }, + perOpMaximumApplicable: { + type: DataTypes.BOOLEAN, + defaultValue: false, + field: 'PER_OP_MAX_APPLICABLE' + }, perOpMaximumUsd: { type: DataTypes.DECIMAL(10, 4), // max 10 digits, 4 of which can be after the decimal point allowNull: true, @@ -148,10 +167,15 @@ export function initializeSponsorshipPolicyModel(sequelize: Sequelize, schema: s allowNull: true, field: 'PER_OP_MAX_NATIVE' }, - contractRestrictions: { - type: DataTypes.TEXT, + addressAllowList: { + type: DataTypes.ARRAY(DataTypes.STRING), + allowNull: true, + field: 'ADDRESS_ALLOW_LIST' + }, + addressBlockList: { + type: DataTypes.ARRAY(DataTypes.STRING), allowNull: true, - field: 'CONTRACT_RESTRICTIONS' + field: 'ADDRESS_BLOCK_LIST' }, createdAt: { type: DataTypes.DATE, diff --git a/backend/src/plugins/db.ts b/backend/src/plugins/db.ts index c02afa8..86647bb 100644 --- a/backend/src/plugins/db.ts +++ b/backend/src/plugins/db.ts @@ -9,7 +9,7 @@ import { Umzug, SequelizeStorage } from 'umzug'; const databasePlugin: FastifyPluginAsync = async (server) => { const sequelize = new Sequelize(server.config.DATABASE_URL, { - schema: 'arka', + schema: server.config.DATABASE_SCHEMA_NAME, }); const __filename = fileURLToPath(import.meta.url); diff --git a/backend/src/plugins/sequelizePlugin.ts b/backend/src/plugins/sequelizePlugin.ts index 6a6af30..0649525 100644 --- a/backend/src/plugins/sequelizePlugin.ts +++ b/backend/src/plugins/sequelizePlugin.ts @@ -28,7 +28,7 @@ const sequelizePlugin: FastifyPluginAsync = async (server) => { dialect: 'postgres', protocol: 'postgres', dialectOptions: { - searchPath: 'arka', + searchPath: server.config.DATABASE_SCHEMA_NAME, // ssl: { // require: false, // rejectUnauthorized: false diff --git a/backend/src/routes/index.ts b/backend/src/routes/index.ts index 87cd889..1c452c2 100644 --- a/backend/src/routes/index.ts +++ b/backend/src/routes/index.ts @@ -11,7 +11,6 @@ import ErrorMessage from "../constants/ErrorMessage.js"; import ReturnCode from "../constants/ReturnCode.js"; import { decode } from "../utils/crypto.js"; import { printRequest, getNetworkConfig } from "../utils/common.js"; -import { APIKeyRepository } from "repository/api-key-repository.js"; import { APIKey } from "models/api-key.js"; const SUPPORTED_ENTRYPOINTS = { @@ -127,7 +126,7 @@ const routes: FastifyPluginAsync = async (server) => { txnMode = secrets['TRANSACTION_LIMIT'] ?? 0; indexerEndpoint = secrets['INDEXER_ENDPOINT'] ?? process.env.DEFAULT_INDEXER_ENDPOINT; } else { - const apiKeyEntity = await new APIKeyRepository(server.sequelize).findOneByApiKey(api_key); + const apiKeyEntity = await server.apiKeyRepository.findOneByApiKey(api_key); if (!apiKeyEntity) { server.log.info("Invalid Api Key provided") @@ -373,7 +372,7 @@ const routes: FastifyPluginAsync = async (server) => { privateKey = secrets['PRIVATE_KEY']; supportedNetworks = secrets['SUPPORTED_NETWORKS']; } else { - const apiKeyEntity: APIKey | null = await new APIKeyRepository(server.sequelize).findOneByApiKey(api_key); + const apiKeyEntity: APIKey | null = await server.apiKeyRepository.findOneByApiKey(api_key); if (!apiKeyEntity) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }) privateKey = decode(apiKeyEntity.privateKey); supportedNetworks = apiKeyEntity.supportedNetworks; @@ -431,7 +430,7 @@ const routes: FastifyPluginAsync = async (server) => { privateKey = secrets['PRIVATE_KEY']; supportedNetworks = secrets['SUPPORTED_NETWORKS']; } else { - const apiKeyEntity: APIKey | null = await new APIKeyRepository(server.sequelize).findOneByApiKey(api_key); + const apiKeyEntity: APIKey | null = await server.apiKeyRepository.findOneByApiKey(api_key); if (!apiKeyEntity) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }) privateKey = decode(apiKeyEntity.apiKey); supportedNetworks = apiKeyEntity.supportedNetworks; @@ -489,7 +488,7 @@ const routes: FastifyPluginAsync = async (server) => { privateKey = secrets['PRIVATE_KEY']; supportedNetworks = secrets['SUPPORTED_NETWORKS']; } else { - const apiKeyEntity: APIKey | null = await new APIKeyRepository(server.sequelize).findOneByApiKey(api_key); + const apiKeyEntity: APIKey | null = await server.apiKeyRepository.findOneByApiKey(api_key); if (!apiKeyEntity) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }) privateKey = decode(apiKeyEntity.privateKey); supportedNetworks = apiKeyEntity.supportedNetworks; @@ -548,7 +547,7 @@ const routes: FastifyPluginAsync = async (server) => { privateKey = secrets['PRIVATE_KEY']; supportedNetworks = secrets['SUPPORTED_NETWORKS']; } else { - const apiKeyEntity: APIKey | null = await new APIKeyRepository(server.sequelize).findOneByApiKey(api_key); + const apiKeyEntity: APIKey | null = await server.apiKeyRepository.findOneByApiKey(api_key); if (!apiKeyEntity) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }) privateKey = decode(apiKeyEntity.apiKey); supportedNetworks = apiKeyEntity.supportedNetworks; @@ -601,7 +600,7 @@ const routes: FastifyPluginAsync = async (server) => { privateKey = secrets['PRIVATE_KEY']; supportedNetworks = secrets['SUPPORTED_NETWORKS']; } else { - const apiKeyEntity: APIKey | null = await new APIKeyRepository(server.sequelize).findOneByApiKey(api_key); + const apiKeyEntity: APIKey | null = await server.apiKeyRepository.findOneByApiKey(api_key); if (!apiKeyEntity) return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }) privateKey = decode(apiKeyEntity.privateKey); supportedNetworks = apiKeyEntity.supportedNetworks; diff --git a/backend/src/routes/metadata.ts b/backend/src/routes/metadata.ts index 11a2de6..9ee7aef 100644 --- a/backend/src/routes/metadata.ts +++ b/backend/src/routes/metadata.ts @@ -8,7 +8,6 @@ import ErrorMessage from "../constants/ErrorMessage.js"; import { decode } from "../utils/crypto.js"; import { PAYMASTER_ADDRESS } from "../constants/Pimlico.js"; import { APIKey } from "../models/api-key"; -import { APIKeyRepository } from "repository/api-key-repository"; import * as EtherspotAbi from "../abi/EtherspotAbi.js"; const metadataRoutes: FastifyPluginAsync = async (server) => { @@ -36,7 +35,6 @@ const metadataRoutes: FastifyPluginAsync = async (server) => { return reply.code(ReturnCode.FAILURE).send({error: ErrorMessage.INVALID_DATA}) let customPaymasters = []; let multiTokenPaymasters = []; - let multiTokenOracles = []; let privateKey = ''; let supportedNetworks; let sponsorName = '', sponsorImage = ''; @@ -64,7 +62,7 @@ const metadataRoutes: FastifyPluginAsync = async (server) => { privateKey = secrets['PRIVATE_KEY']; supportedNetworks = secrets['SUPPORTED_NETWORKS']; } else { - const apiKeyEntity: APIKey | null = await new APIKeyRepository(server.sequelize).findOneByApiKey(api_key); + const apiKeyEntity: APIKey | null = await server.apiKeyRepository.findOneByApiKey(api_key); if (!apiKeyEntity) { server.log.info("Invalid Api Key provided") return reply.code(ReturnCode.FAILURE).send({ error: ErrorMessage.INVALID_API_KEY }) diff --git a/backend/src/types/sponsorship-policy-dto.ts b/backend/src/types/sponsorship-policy-dto.ts index 52f8b39..3c3bc2f 100644 --- a/backend/src/types/sponsorship-policy-dto.ts +++ b/backend/src/types/sponsorship-policy-dto.ts @@ -1,46 +1,32 @@ // DTO for receiving data in the POST request to create a sponsorship policy export interface SponsorshipPolicyDto { - policyId: number; // ID of the policy + id: number; // ID of the policy walletAddress: string; // The wallet address associated with the API key name: string; // Name of the sponsorship policy description: string; // Description of the sponsorship policy - startDate?: string; // Optional start date for the policy - endDate?: string; // Optional end date for the policy - isPerpetual: boolean; // Flag to indicate if the policy is perpetual + isPublic: boolean; // Flag to indicate if the policy is public + isEnabled: boolean; // Flag to indicate if the policy is enabled isUniversal: boolean; // Flag to indicate if the policy is universal - contractRestrictions?: string; // JSON string containing any contract-specific restrictions enabledChains?: number[]; // Array of enabled chain IDs - limits: SponsorshipPolicyLimitDTO[]; // Array of limits associated with the policy - isEnabled: boolean; // Flag to indicate if the policy is enabled/disabled - isExpired: boolean; // Flag to indicate if the policy is expired - isCurrent: boolean; // Flag to indicate if the policy is current - isApplicable: boolean; // Flag to indicate if the policy is applicable -} - -export interface SponsorshipPolicyActionDto { - policyId: number; - action: ActionType; -} - -// DTO for sponsorship policy limits -export interface SponsorshipPolicyLimitDTO { - limitType: LimitType; // Type of limit (GLOBAL, PER_USER, PER_OPERATION) - maxUsd?: number; // Optional maximum USD limit - maxEth?: number; // Optional maximum ETH limit - maxOperations?: number; // Optional maximum number of operations -} - -// enum for LimitTypes -export enum LimitType { - GLOBAL = 'GLOBAL', - PER_USER = 'PER_USER', - PER_OPERATION = 'PER_OPERATION' + isPerpetual: boolean; // Flag to indicate if the policy is perpetual + startDate?: string; // Optional start date for the policy + endDate?: string; // Optional end date for the policy + globalMaximumApplicable: boolean; // Flag to indicate if the global maximum is applicable + globalMaximumUsd?: number; // Optional global maximum USD limit + globalMaximumNative?: number; // Optional global maximum native limit + globalMaximumOpCount?: number; // Optional global maximum operation count + perUserMaximumApplicable: boolean; // Flag to indicate if the per user maximum is applicable + perUserMaximumUsd?: number; // Optional per user maximum USD limit + perUserMaximumNative?: number; // Optional per user maximum native limit + perUserMaximumOpCount?: number; // Optional per user maximum operation count + perOpMaximumApplicable: boolean; // Flag to indicate if the per operation maximum is applicable + perOpMaximumUsd?: number; // Optional per operation maximum USD limit + perOpMaximumNative?: number; // Optional per operation maximum native limit + addressAllowList?: string[]; // Optional array of allowed addresses + addressBlockList?: string[]; // Optional array of blocked addresses + isExpired: boolean; // Flag to indicate if the policy is expired + isCurrent: boolean; // Flag to indicate if the policy is current + isApplicable: boolean; // Flag to indicate if the policy is applicable + createdAt: Date; // Date the policy was created + updatedAt: Date; // Date the policy was last updated } - -export enum ActionType { - CREATE = 'CREATE', - UPDATE = 'UPDATE', - DISABLE = 'DISABLE', - ENABLE = 'ENABLE', - DELETE = 'DELETE' -} \ No newline at end of file