diff --git a/contract/contracts/hello-world/src/autoshare_logic.rs b/contract/contracts/hello-world/src/autoshare_logic.rs index 20e4dd7..ad96ba8 100644 --- a/contract/contracts/hello-world/src/autoshare_logic.rs +++ b/contract/contracts/hello-world/src/autoshare_logic.rs @@ -254,7 +254,7 @@ pub fn add_group_member( }); // Validate total percentage after adding - validate_members(&details.members)?; + validate_members(&env, &details.members)?; // Save updated details env.storage().persistent().set(&key, &details); @@ -901,7 +901,7 @@ pub fn withdraw( Ok(()) } -fn validate_members(members: &Vec) -> Result<(), Error> { +fn validate_members(env: &Env, members: &Vec) -> Result<(), Error> { if members.is_empty() { return Err(Error::EmptyMembers); } @@ -909,7 +909,6 @@ fn validate_members(members: &Vec) -> Result<(), Error> { if members.len() > MAX_MEMBERS { return Err(Error::TooManyMembers); } - let env = members.env(); let mut total_percentage: u32 = 0; let mut seen_addresses = Vec::new(env); diff --git a/listener/src/api/events-server.ts b/listener/src/api/events-server.ts index 13dfca1..aa89e0c 100644 --- a/listener/src/api/events-server.ts +++ b/listener/src/api/events-server.ts @@ -45,8 +45,8 @@ export interface EventsServerOptions { port: number; corsOrigin?: string; stellarRpcUrl: string; - stellarNetworkPassphrase: string; - contractAddresses: ContractConfig[]; + stellarNetworkPassphrase?: string; + contractAddresses?: ContractConfig[]; discordWebhookUrl?: string; webhookSecrets?: WebhookSecret[]; notificationAPI?: NotificationAPI | null; @@ -214,15 +214,17 @@ async function buildStatusResponse(options: EventsServerOptions): Promise<{ }>; timestamp: string; }> { - const contractStatuses = await Promise.all( - options.contractAddresses.map(async (contractConfig) => { - const status = await getContractPauseStatus(contractConfig.address, options.stellarRpcUrl); - return { - address: contractConfig.address, - ...status - }; - }) - ); + const contractStatuses = options.contractAddresses + ? await Promise.all( + options.contractAddresses.map(async (contractConfig) => { + const status = await getContractPauseStatus(contractConfig.address, options.stellarRpcUrl); + return { + address: contractConfig.address, + ...status + }; + }) + ) + : []; return { timestamp: new Date().toISOString(), diff --git a/listener/src/config.ts b/listener/src/config.ts index 44979bb..c999a01 100644 --- a/listener/src/config.ts +++ b/listener/src/config.ts @@ -1,3 +1,4 @@ +import { Config, ContractConfig, DiscordConfig, WebhookSecret, AppCleanupConfig, EventQueueConfig, RetrySchedulerOptions } from './types'; import { Config, ContractConfig, DiscordConfig, WebhookSecret, AppCleanupConfig, EventQueueConfig, RetrySchedulerOptions, AnalyticsConfig } from './types'; export class ConfigError extends Error { diff --git a/listener/src/database/schema.sql b/listener/src/database/schema.sql index 43584df..f0aac5a 100644 --- a/listener/src/database/schema.sql +++ b/listener/src/database/schema.sql @@ -50,6 +50,9 @@ CREATE INDEX IF NOT EXISTS idx_scheduled_notifications_lock_expires ON scheduled_notifications(lock_expires_at, status) WHERE status = 'PROCESSING'; +-- Migration: add next_retry_at for explicit retry scheduling +ALTER TABLE scheduled_notifications ADD COLUMN next_retry_at DATETIME; + CREATE INDEX IF NOT EXISTS idx_scheduled_notifications_next_retry_at ON scheduled_notifications(next_retry_at, status) WHERE status = 'PENDING';