From 50c2e1ae7d9c06d9fa018aa3c417c7a47c16b524 Mon Sep 17 00:00:00 2001 From: Yusrah Mohammed Date: Sun, 21 Jun 2026 10:12:47 +0100 Subject: [PATCH 1/4] feat: enhance search bar with debounced autocomplete and term highlighting --- dashboard/src/components/EventFiltersBar.tsx | 10 +- .../src/components/SearchAutocomplete.tsx | 188 ++++++++++++++++++ dashboard/src/hooks/useDebounce.ts | 17 ++ 3 files changed, 209 insertions(+), 6 deletions(-) create mode 100644 dashboard/src/components/SearchAutocomplete.tsx create mode 100644 dashboard/src/hooks/useDebounce.ts diff --git a/dashboard/src/components/EventFiltersBar.tsx b/dashboard/src/components/EventFiltersBar.tsx index 222a48d1..a598cf6c 100644 --- a/dashboard/src/components/EventFiltersBar.tsx +++ b/dashboard/src/components/EventFiltersBar.tsx @@ -1,6 +1,7 @@ import { memo } from 'react'; import { useEventStore } from '../store/eventStore'; import { useEventCount, useEventFilters, useFilterOptions } from '../hooks/useEventSelectors'; +import { SearchAutocomplete } from './SearchAutocomplete'; export const EventFiltersBar = memo(function EventFiltersBar() { const filters = useEventFilters(); @@ -14,12 +15,9 @@ export const EventFiltersBar = memo(function EventFiltersBar() {
- setSearch(event.target.value)} + setSearch(value)} />
diff --git a/dashboard/src/components/SearchAutocomplete.tsx b/dashboard/src/components/SearchAutocomplete.tsx new file mode 100644 index 00000000..593de009 --- /dev/null +++ b/dashboard/src/components/SearchAutocomplete.tsx @@ -0,0 +1,188 @@ +import React, { useState, useEffect, useRef, memo } from 'react'; +import { useDebounce } from '../hooks/useDebounce'; +import { useEventStore } from '../store/eventStore'; +import { filterEvents } from '../utils/eventData'; +import type { BlockchainEvent } from '../types/event'; + +// Highlight matches +function HighlightMatch({ text, query }: { text: string; query: string }) { + if (!query) return <>{text}; + + const regex = new RegExp(`(${query})`, 'gi'); + const parts = text.split(regex); + + return ( + <> + {parts.map((part, index) => + part.toLowerCase() === query.toLowerCase() ? ( + + {part} + + ) : ( + {part} + ) + )} + + ); +} + +export const SearchAutocomplete = memo(function SearchAutocomplete({ + value, + onChange, +}: { + value: string; + onChange: (value: string) => void; +}) { + const [localValue, setLocalValue] = useState(value); + const debouncedSearchTerm = useDebounce(localValue, 300); + const [suggestions, setSuggestions] = useState([]); + const [isLoading, setIsLoading] = useState(false); + const [isOpen, setIsOpen] = useState(false); + const containerRef = useRef(null); + + // Sync internal state with external value changes (if any external changes) + useEffect(() => { + setLocalValue(value); + }, [value]); + + useEffect(() => { + // Close dropdown if search is empty + if (!debouncedSearchTerm.trim()) { + setSuggestions([]); + setIsOpen(false); + return; + } + + let isMounted = true; + const fetchSuggestions = async () => { + setIsLoading(true); + setIsOpen(true); + + // Simulate async fetching + await new Promise((resolve) => setTimeout(resolve, 300)); + + if (isMounted) { + const allEvents = useEventStore.getState().events; + // Get up to 5 matching suggestions based on query, disregarding other filters generally, + // or passing "all" for them. + const matches = filterEvents(allEvents, debouncedSearchTerm, 'all', 'all').slice(0, 5); + setSuggestions(matches); + setIsLoading(false); + } + }; + + fetchSuggestions(); + + return () => { + isMounted = false; + }; + }, [debouncedSearchTerm]); + + // Handle outside click to close suggestions + useEffect(() => { + const handleOutsideClick = (event: MouseEvent) => { + if (containerRef.current && !containerRef.current.contains(event.target as Node)) { + setIsOpen(false); + } + }; + document.addEventListener('mousedown', handleOutsideClick); + return () => document.removeEventListener('mousedown', handleOutsideClick); + }, []); + + const handleInputChange = (e: React.ChangeEvent) => { + const val = e.target.value; + setLocalValue(val); + onChange(val); // Immediately pass up the value to update store + if (!val.trim()) { + setIsOpen(false); + } + }; + + const handleSelect = (event: BlockchainEvent) => { + // Determine what to use for search field. We can use eventName or eventId + const targetValue = event.eventName || event.eventId; + setLocalValue(targetValue); + onChange(targetValue); + setIsOpen(false); + }; + + return ( +
+ { + if (debouncedSearchTerm.trim()) { + setIsOpen(true); + } + }} + autoComplete="off" + style={{ width: '100%' }} + /> + + {isOpen && ( +
+ {isLoading ? ( +
+ Loading suggestions... +
+ ) : suggestions.length > 0 ? ( +
    + {suggestions.map((event) => ( +
  • handleSelect(event)} + style={{ + padding: '8px 12px', + cursor: 'pointer', + borderBottom: '1px solid rgba(255,255,255,0.06)', + fontSize: '0.85rem' + }} + onMouseEnter={(e) => { + e.currentTarget.style.backgroundColor = 'rgba(255,255,255,0.06)'; + }} + onMouseLeave={(e) => { + e.currentTarget.style.backgroundColor = 'transparent'; + }} + > +
    + + + + +
    +
    + +
    +
  • + ))} +
+ ) : ( +
+ No suggestions found +
+ )} +
+ )} +
+ ); +}); diff --git a/dashboard/src/hooks/useDebounce.ts b/dashboard/src/hooks/useDebounce.ts new file mode 100644 index 00000000..614feab0 --- /dev/null +++ b/dashboard/src/hooks/useDebounce.ts @@ -0,0 +1,17 @@ +import { useState, useEffect } from "react"; + +export function useDebounce(value: T, delay: number): T { + const [debouncedValue, setDebouncedValue] = useState(value); + + useEffect(() => { + const timer = setTimeout(() => { + setDebouncedValue(value); + }, delay); + + return () => { + clearTimeout(timer); + }; + }, [value, delay]); + + return debouncedValue; +} From 410b25821f0be499cbd172f75411f657b14f1971 Mon Sep 17 00:00:00 2001 From: Yusrah Mohammed Date: Sun, 21 Jun 2026 10:19:11 +0100 Subject: [PATCH 2/4] fix: ci failure --- .github/workflows/ci.yml | 3 +- .../hello-world/src/tests/autoshare_test.rs | 90 ++++++++++++------- 2 files changed, 61 insertions(+), 32 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 73410dac..f19c9fc7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,8 @@ jobs: uses: actions/setup-node@v4 with: node-version: 18 - cache: 'npm' + cache: "npm" + cache-dependency-path: dashboard/package-lock.json - name: Install dependencies working-directory: dashboard run: npm ci diff --git a/contract/contracts/hello-world/src/tests/autoshare_test.rs b/contract/contracts/hello-world/src/tests/autoshare_test.rs index 4b5225c0..fbb42979 100644 --- a/contract/contracts/hello-world/src/tests/autoshare_test.rs +++ b/contract/contracts/hello-world/src/tests/autoshare_test.rs @@ -1486,10 +1486,10 @@ fn test_create_fails_name_too_long() { let creator = test_env.users.get(0).unwrap().clone(); let token = test_env.mock_tokens.get(0).unwrap().clone(); let id = BytesN::from_array(&test_env.env, &[1u8; 32]); - + // Create a very long name (over 100 characters) let long_name = String::from_str(&test_env.env, "a".repeat(101).as_str()); - + crate::test_utils::mint_tokens(&test_env.env, &token, &creator, 10000000); client.create(&id, &long_name, &creator, &10u32, &token); } @@ -1504,7 +1504,7 @@ fn test_create_fails_invalid_usage_count_zero() { let token = test_env.mock_tokens.get(0).unwrap().clone(); let id = BytesN::from_array(&test_env.env, &[1u8; 32]); let name = String::from_str(&test_env.env, "Test Group"); - + crate::test_utils::mint_tokens(&test_env.env, &token, &creator, 10000000); client.create(&id, &name, &creator, &0u32, &token); } @@ -1518,14 +1518,14 @@ fn test_create_fails_unsupported_token() { let creator = test_env.users.get(0).unwrap().clone(); let id = BytesN::from_array(&test_env.env, &[1u8; 32]); let name = String::from_str(&test_env.env, "Test Group"); - + // Create an unsupported token (not added to supported tokens) let unsupported_token = test_utils::deploy_mock_token( - &test_env.env, - &String::from_str(&test_env.env, "Unsupported"), - &String::from_str(&test_env.env, "UNSUP") + &test_env.env, + &String::from_str(&test_env.env, "Unsupported"), + &String::from_str(&test_env.env, "UNSUP"), ); - + crate::test_utils::mint_tokens(&test_env.env, &unsupported_token, &creator, 10000000); client.create(&id, &name, &creator, &10u32, &unsupported_token); } @@ -1539,10 +1539,17 @@ fn test_topup_fails_invalid_usage_count_zero() { let creator = test_env.users.get(0).unwrap().clone(); let token = test_env.mock_tokens.get(0).unwrap().clone(); let id = BytesN::from_array(&test_env.env, &[1u8; 32]); - + let members = Vec::new(&test_env.env); - create_test_group(&test_env.env, &test_env.autoshare_contract, &creator, &members, 10, &token); - + create_test_group( + &test_env.env, + &test_env.autoshare_contract, + &creator, + &members, + 10, + &token, + ); + client.topup_subscription(&id, &0u32, &token, &creator); } @@ -1555,17 +1562,24 @@ fn test_topup_fails_unsupported_token() { let creator = test_env.users.get(0).unwrap().clone(); let supported_token = test_env.mock_tokens.get(0).unwrap().clone(); let id = BytesN::from_array(&test_env.env, &[1u8; 32]); - + let members = Vec::new(&test_env.env); - create_test_group(&test_env.env, &test_env.autoshare_contract, &creator, &members, 10, &supported_token); - + create_test_group( + &test_env.env, + &test_env.autoshare_contract, + &creator, + &members, + 10, + &supported_token, + ); + // Create an unsupported token let unsupported_token = test_utils::deploy_mock_token( - &test_env.env, - &String::from_str(&test_env.env, "Unsupported"), - &String::from_str(&test_env.env, "UNSUP") + &test_env.env, + &String::from_str(&test_env.env, "Unsupported"), + &String::from_str(&test_env.env, "UNSUP"), ); - + crate::test_utils::mint_tokens(&test_env.env, &unsupported_token, &creator, 10000000); client.topup_subscription(&id, &10u32, &unsupported_token, &creator); } @@ -1579,13 +1593,20 @@ fn test_reduce_usage_fails_no_usages_remaining() { let creator = test_env.users.get(0).unwrap().clone(); let token = test_env.mock_tokens.get(0).unwrap().clone(); let id = BytesN::from_array(&test_env.env, &[1u8; 32]); - + let members = Vec::new(&test_env.env); - create_test_group(&test_env.env, &test_env.autoshare_contract, &creator, &members, 1, &token); - + create_test_group( + &test_env.env, + &test_env.autoshare_contract, + &creator, + &members, + 1, + &token, + ); + // Reduce once (should work) client.reduce_usage(&id); - + // Reduce again (should panic) client.reduce_usage(&id); } @@ -1600,7 +1621,7 @@ fn test_set_usage_fee_fails_zero() { let admin = Address::generate(&env); client.initialize_admin(&admin); - + client.set_usage_fee(&0u32, &admin); } @@ -1614,7 +1635,7 @@ fn test_add_supported_token_fails_already_exists() { let admin = Address::generate(&env); client.initialize_admin(&admin); - + let token_id = env.register(MockToken, ()); let token_client = MockTokenClient::new(&env, &token_id); token_client.initialize( @@ -1623,7 +1644,7 @@ fn test_add_supported_token_fails_already_exists() { &String::from_str(&env, "Test Token"), &String::from_str(&env, "TST"), ); - + // Add once client.add_supported_token(&token_id, &admin); // Add again (should panic) @@ -1640,7 +1661,7 @@ fn test_remove_supported_token_fails_not_found() { let admin = Address::generate(&env); client.initialize_admin(&admin); - + let token_id = env.register(MockToken, ()); let token_client = MockTokenClient::new(&env, &token_id); token_client.initialize( @@ -1649,7 +1670,7 @@ fn test_remove_supported_token_fails_not_found() { &String::from_str(&env, "Test Token"), &String::from_str(&env, "TST"), ); - + // Try to remove a token that was never added client.remove_supported_token(&token_id, &admin); } @@ -1663,11 +1684,18 @@ fn test_update_members_fails_too_many() { let creator = test_env.users.get(0).unwrap().clone(); let token = test_env.mock_tokens.get(0).unwrap().clone(); let id = BytesN::from_array(&test_env.env, &[1u8; 32]); - + // Create group first let initial_members = Vec::new(&test_env.env); - create_test_group(&test_env.env, &test_env.autoshare_contract, &creator, &initial_members, 10, &token); - + create_test_group( + &test_env.env, + &test_env.autoshare_contract, + &creator, + &initial_members, + 10, + &token, + ); + // Create 51 members (MAX_MEMBERS is 50) let mut too_many_members = Vec::new(&test_env.env); for _ in 0..51 { @@ -1676,7 +1704,7 @@ fn test_update_members_fails_too_many() { percentage: 1, // This will sum to 51, but first check is TooManyMembers }); } - + client.update_members(&id, &creator, &too_many_members); } From f892089c1d9fa73f03b088661a75e062b897f5f9 Mon Sep 17 00:00:00 2001 From: Yusrah Mohammed Date: Sun, 21 Jun 2026 10:33:38 +0100 Subject: [PATCH 3/4] feat: process automatic timeouts and cancellation for stalled webhook requests --- listener/src/api/events-server.test.ts | 17 +++++++- listener/src/api/events-server.ts | 7 +++- listener/src/api/rate-limiter.test.ts | 7 ++-- .../src/services/discord-notification.test.ts | 28 ++++++++++++- listener/src/services/discord-notification.ts | 41 +++++++++++++++---- listener/src/types/index.ts | 1 + 6 files changed, 86 insertions(+), 15 deletions(-) diff --git a/listener/src/api/events-server.test.ts b/listener/src/api/events-server.test.ts index d18e837a..ee4b6635 100644 --- a/listener/src/api/events-server.test.ts +++ b/listener/src/api/events-server.test.ts @@ -1,3 +1,4 @@ +import { jest, describe, it, expect, beforeEach, afterEach } from '@jest/globals'; import http from 'http'; import crypto from 'crypto'; import { createEventsServer, checkStellarRpc, checkDiscord } from './events-server'; @@ -12,7 +13,6 @@ jest.mock('@stellar/stellar-sdk', () => ({ })), }, })); -import { createEventsServer } from './events-server'; import { preferenceStore } from '../store/preference-store'; jest.mock('../store/preference-store', () => { @@ -65,7 +65,7 @@ describe('Preference API endpoints', () => { beforeEach((done) => { jest.clearAllMocks(); - server = createEventsServer({ port: 0 }); + server = createEventsServer({ port: 0, stellarRpcUrl: 'http://localhost' }); server.listen(0, '127.0.0.1', done); }); @@ -174,6 +174,19 @@ function makePostRequest( }); } +function startServer(options: any): Promise { + return new Promise((resolve) => { + const s = createEventsServer(options); + s.listen(0, '127.0.0.1', () => resolve(s)); + }); +} + +function closeServer(s: http.Server): Promise { + return new Promise((resolve) => s.close(() => resolve())); +} + +const BASE_OPTIONS = { port: 0, stellarRpcUrl: 'https://test' }; + describe('POST /api/webhooks', () => { let server: http.Server; const secrets = [ diff --git a/listener/src/api/events-server.ts b/listener/src/api/events-server.ts index 7266e258..ac61c4b5 100644 --- a/listener/src/api/events-server.ts +++ b/listener/src/api/events-server.ts @@ -132,7 +132,7 @@ export function createEventsServer(options: EventsServerOptions): http.Server { const corsOrigin = options.corsOrigin ?? 'http://localhost:5173'; const rateLimiter = options.rateLimit ? new RateLimiter(options.rateLimit) : undefined; - const server = http.createServer((req, res) => { + const server = http.createServer(async (req, res) => { const requestId = generateRequestId(); const correlationId = resolveCorrelationId(req.headers['x-correlation-id']); const startTime = Date.now(); @@ -143,6 +143,11 @@ export function createEventsServer(options: EventsServerOptions): http.Server { res.setHeader('X-Request-Id', requestId); res.setHeader('X-Correlation-Id', correlationId); + if (rateLimiter) { + const allowed = await rateLimiter.handle(req, res as any); + if (!allowed) return; + } + if (req.method === 'OPTIONS') { res.writeHead(204); res.end(); diff --git a/listener/src/api/rate-limiter.test.ts b/listener/src/api/rate-limiter.test.ts index d1d4fe91..cb039654 100644 --- a/listener/src/api/rate-limiter.test.ts +++ b/listener/src/api/rate-limiter.test.ts @@ -1,3 +1,4 @@ +import { jest, describe, it, expect, beforeEach, afterEach, beforeAll, afterAll } from '@jest/globals'; import http from 'http'; import * as fs from 'fs'; import * as path from 'path'; @@ -30,14 +31,14 @@ const mockResponse = () => { let statusCode = 200; let body = ''; return { - setHeader: jest.fn().mockImplementation((name, val) => headers.set(name.toLowerCase(), String(val))), - writeHead: jest.fn().mockImplementation((code, h) => { + setHeader: jest.fn().mockImplementation((name: any, val: any) => headers.set(name.toLowerCase(), String(val))), + writeHead: jest.fn().mockImplementation((code: any, h: any) => { statusCode = code; if (h) { Object.entries(h).forEach(([n, v]) => headers.set(n.toLowerCase(), String(v))); } }), - end: jest.fn().mockImplementation((val) => { + end: jest.fn().mockImplementation((val: any) => { body = val; }), _getHeaders: () => headers, diff --git a/listener/src/services/discord-notification.test.ts b/listener/src/services/discord-notification.test.ts index 2746792f..34467c18 100644 --- a/listener/src/services/discord-notification.test.ts +++ b/listener/src/services/discord-notification.test.ts @@ -1,9 +1,10 @@ +import { jest, describe, it, expect, beforeEach } from '@jest/globals'; import { xdr } from '@stellar/stellar-sdk'; import * as StellarSDK from '@stellar/stellar-sdk'; import { DiscordNotificationService } from './discord-notification'; import { NotificationDeduplicator } from './notification-deduplicator'; -const mockFetch = jest.fn(); +const mockFetch = jest.fn() as any; global.fetch = mockFetch; jest.mock('../utils/logger', () => ({ @@ -92,6 +93,29 @@ describe('DiscordNotificationService', () => { expect(result).toBe(false); }); + + it('should handle request timeout', async () => { + const abortError = new Error('The operation was aborted'); + abortError.name = 'AbortError'; + mockFetch.mockRejectedValueOnce(abortError); + + const mockLoggerModule = (jest.requireMock('../utils/logger') as any).default; + const service = new DiscordNotificationService({ ...mockConfig, timeoutMs: 100 }); + const mockEvent = createMockEvent(); + const mockContractConfig = { address: 'CA123', events: ['test'] }; + + const result = await service.sendEventNotification(mockEvent, mockContractConfig); + + expect(result).toBe(false); + expect(mockLoggerModule.error).toHaveBeenCalledWith( + 'Discord webhook request timed out', + expect.objectContaining({ + webhookId: mockConfig.webhookId, + timeoutMs: 100, + }) + ); + expect(service.getMetrics().timeoutCount).toBe(1); + }); }); describe('duplicate detection', () => { @@ -115,7 +139,7 @@ describe('DiscordNotificationService', () => { it('logs a duplicate detection event', async () => { mockFetch.mockResolvedValue({ ok: true }); - const mockLoggerModule = jest.requireMock('../utils/logger').default; + const mockLoggerModule = (jest.requireMock('../utils/logger') as any).default; const service = new DiscordNotificationService(mockConfig); const mockEvent = createMockEvent({ id: 'event-dup-log' }); const mockContractConfig = { address: 'CA123', events: ['test'] }; diff --git a/listener/src/services/discord-notification.ts b/listener/src/services/discord-notification.ts index 750b47f6..07158f9a 100644 --- a/listener/src/services/discord-notification.ts +++ b/listener/src/services/discord-notification.ts @@ -25,6 +25,7 @@ export function createDiscordService(config: DiscordConfig): DiscordNotification export class DiscordNotificationService { private config: DiscordConfig; private deduplicator: NotificationDeduplicator; + private timeoutCount: number = 0; constructor(config: DiscordConfig, deduplicator?: NotificationDeduplicator) { this.config = config; @@ -97,6 +98,13 @@ export class DiscordNotificationService { } } + getMetrics() { + return { + ...this.deduplicator.getMetrics(), + timeoutCount: this.timeoutCount, + }; + } + getDeduplicationMetrics() { return this.deduplicator.getMetrics(); } @@ -143,13 +151,32 @@ export class DiscordNotificationService { } private async sendWebhook(message: DiscordMessage): Promise { - return fetch(this.config.webhookUrl, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(message), - }); + const timeoutMs = this.config.timeoutMs ?? 5000; + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), timeoutMs); + + try { + const response = await fetch(this.config.webhookUrl, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(message), + signal: controller.signal as any, + }); + return response; + } catch (error: any) { + if (error.name === 'AbortError') { + this.timeoutCount++; + logger.error('Discord webhook request timed out', { + webhookId: this.config.webhookId, + timeoutMs, + }); + } + throw error; + } finally { + clearTimeout(timeoutId); + } } private formatEventMessage( diff --git a/listener/src/types/index.ts b/listener/src/types/index.ts index c4e7e1bf..2d10e7f1 100644 --- a/listener/src/types/index.ts +++ b/listener/src/types/index.ts @@ -10,6 +10,7 @@ export interface DiscordConfig { webhookId: string; deduplicationWindowMs?: number; deduplicationMaxSize?: number; + timeoutMs?: number; } export interface RetryQueueConfig { From 05b824341a90f6b3709bcc6c896a32b29313582f Mon Sep 17 00:00:00 2001 From: Yusrah Mohammed Date: Sun, 21 Jun 2026 10:44:02 +0100 Subject: [PATCH 4/4] fix: ci failure --- .../contracts/hello-world/src/tests/autoshare_test.rs | 8 ++++---- contract/contracts/hello-world/src/tests/version_test.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/contract/contracts/hello-world/src/tests/autoshare_test.rs b/contract/contracts/hello-world/src/tests/autoshare_test.rs index fbb42979..3e577ed1 100644 --- a/contract/contracts/hello-world/src/tests/autoshare_test.rs +++ b/contract/contracts/hello-world/src/tests/autoshare_test.rs @@ -1520,7 +1520,7 @@ fn test_create_fails_unsupported_token() { let name = String::from_str(&test_env.env, "Test Group"); // Create an unsupported token (not added to supported tokens) - let unsupported_token = test_utils::deploy_mock_token( + let unsupported_token = crate::test_utils::deploy_mock_token( &test_env.env, &String::from_str(&test_env.env, "Unsupported"), &String::from_str(&test_env.env, "UNSUP"), @@ -1574,7 +1574,7 @@ fn test_topup_fails_unsupported_token() { ); // Create an unsupported token - let unsupported_token = test_utils::deploy_mock_token( + let unsupported_token = crate::test_utils::deploy_mock_token( &test_env.env, &String::from_str(&test_env.env, "Unsupported"), &String::from_str(&test_env.env, "UNSUP"), @@ -1926,7 +1926,7 @@ fn test_too_many_members_rejected() { // Build > MAX_MEMBERS (51 members, limit is 50) let mut members = Vec::new(&test_env.env); - for i in 0..51u32 { + for _i in 0..51u32 { members.push_back(GroupMember { address: Address::generate(&test_env.env), percentage: 100 / 51, @@ -1951,7 +1951,7 @@ fn test_members_at_max_succeeds() { // Exactly MAX_MEMBERS (50 members, each 2%) let mut members = Vec::new(&test_env.env); - for i in 0..50u32 { + for _i in 0..50u32 { members.push_back(GroupMember { address: Address::generate(&test_env.env), percentage: 2, diff --git a/contract/contracts/hello-world/src/tests/version_test.rs b/contract/contracts/hello-world/src/tests/version_test.rs index 5d2495e5..c1194f9c 100644 --- a/contract/contracts/hello-world/src/tests/version_test.rs +++ b/contract/contracts/hello-world/src/tests/version_test.rs @@ -4,7 +4,7 @@ use soroban_sdk::Env; #[test] fn test_version() { let env = Env::default(); - let contract_id = env.register_contract(None, AutoShareContract); + let contract_id = env.register(AutoShareContract, ()); let client = AutoShareContractClient::new(&env, &contract_id); assert_eq!(client.version(), 1);