diff --git a/packages/api/index.ts b/packages/api/index.ts index 94c0ea826..242953c3b 100644 --- a/packages/api/index.ts +++ b/packages/api/index.ts @@ -1,5 +1,5 @@ export * from './src/modules/accounts/accounts.dto'; -export * from './src/modules/accounts/kyc.dto'; +export * from './src/modules/accounts/whiteList.dto'; export * from './src/modules/accounts/wallets.dto'; export * from './src/types/supabase'; export * from './src/types/responses'; diff --git a/packages/api/src/modules/accounts/accounts.controller.spec.ts b/packages/api/src/modules/accounts/accounts.controller.spec.ts index 34ac7f63b..072e16519 100644 --- a/packages/api/src/modules/accounts/accounts.controller.spec.ts +++ b/packages/api/src/modules/accounts/accounts.controller.spec.ts @@ -1,4 +1,4 @@ -import { CredbullKYCProvider } from '@credbull/contracts'; +import { CredbullWhiteListProvider } from '@credbull/contracts'; import { Test, TestingModule } from '@nestjs/testing'; import { SupabaseClient } from '@supabase/supabase-js'; import { beforeEach, describe, expect, it, vi } from 'vitest'; @@ -11,22 +11,22 @@ import { ConfigurationModule } from '../../utils/module'; import { AccountsController } from './accounts.controller'; import { AccountsModule } from './accounts.module'; -import { KYCStatus } from './kyc.dto'; -import { KycService } from './kyc.service'; +import { WhiteListStatus } from './whiteList.dto'; +import { WhiteListService } from './whiteList.service'; describe('AccountsController', () => { let controller: AccountsController; let client: DeepMockProxy; let admin: DeepMockProxy; - let kyc: DeepMockProxy; + let whiteList: DeepMockProxy; let ethers: DeepMockProxy; beforeEach(async () => { client = mockDeep(); admin = mockDeep(); - kyc = mockDeep(); + whiteList = mockDeep(); ethers = mockDeep(); - (KycService.prototype as any).getOnChainProvider = vi.fn().mockReturnValue(kyc); + (WhiteListService.prototype as any).getOnChainProvider = vi.fn().mockReturnValue(whiteList); const service = { client: () => client, admin: () => admin }; @@ -44,7 +44,7 @@ describe('AccountsController', () => { controller = await module.resolve(AccountsController); }); - it('should return pending status if there is no kyc event', async () => { + it('should return pending status if there is no white list event', async () => { const select = vi.fn(); const eq = vi.fn(); const single = vi.fn(); @@ -57,7 +57,7 @@ describe('AccountsController', () => { const { status } = await controller.status(); - expect(status).toBe(KYCStatus.PENDING); + expect(status).toBe(WhiteListStatus.PENDING); }); it('should whitelist an existing account', async () => { @@ -91,13 +91,13 @@ describe('AccountsController', () => { admin.from.mockReturnValue({ select, insert } as any); ethers.operator.mockResolvedValue({} as any); - kyc.status.mockResolvedValueOnce(false); - kyc.updateStatus.mockResolvedValueOnce({} as any); + whiteList.status.mockResolvedValueOnce(false); + whiteList.updateStatus.mockResolvedValueOnce({} as any); const { status } = await controller.whitelist({ user_id, address }); expect(insert.mock.calls[0][0]).toStrictEqual({ address, user_id, event_name: 'accepted' }); - expect(status).toBe(KYCStatus.ACTIVE); + expect(status).toBe(WhiteListStatus.ACTIVE); }); it('should verify the signature and link the wallet', async () => { diff --git a/packages/api/src/modules/accounts/accounts.controller.ts b/packages/api/src/modules/accounts/accounts.controller.ts index 8e7ac40f5..213ad2f44 100644 --- a/packages/api/src/modules/accounts/accounts.controller.ts +++ b/packages/api/src/modules/accounts/accounts.controller.ts @@ -15,10 +15,10 @@ import { UserWalletDto } from '../../types/db.dto'; import { isKnownError } from '../../utils/errors'; import { AccountStatusDto } from './accounts.dto'; -import { KYCStatus, WhitelistAccountDto } from './kyc.dto'; -import { KycService } from './kyc.service'; import { WalletDto } from './wallets.dto'; import { WalletsService } from './wallets.service'; +import { WhiteListAccountDto, WhiteListStatus } from './whiteList.dto'; +import { WhiteListService } from './whiteList.service'; @Controller('accounts') @ApiBearerAuth() @@ -26,7 +26,7 @@ import { WalletsService } from './wallets.service'; @ApiTags('Accounts') export class AccountsController { constructor( - private readonly kyc: KycService, + private readonly whiteList: WhiteListService, private readonly wallets: WalletsService, ) {} @@ -36,7 +36,7 @@ export class AccountsController { @ApiResponse({ status: 400, description: 'Bad Request' }) @ApiResponse({ status: 500, description: 'Internal Error' }) async status(): Promise { - const { data, error } = await this.kyc.status(); + const { data, error } = await this.whiteList.status(); if (isKnownError(error)) throw new BadRequestException(error); if (error) throw new InternalServerErrorException(error); @@ -51,14 +51,14 @@ export class AccountsController { @ApiResponse({ status: 200, description: 'Success', type: AccountStatusDto }) @ApiResponse({ status: 400, description: 'Bad Request' }) @ApiResponse({ status: 500, description: 'Internal Error' }) - async whitelist(@Body() dto: WhitelistAccountDto): Promise { - const { data, error } = await this.kyc.whitelist(dto); + async whitelist(@Body() dto: WhiteListAccountDto): Promise { + const { data, error } = await this.whiteList.whitelist(dto); if (isKnownError(error)) throw new BadRequestException(error); if (error) throw new InternalServerErrorException(error); if (!data) throw new NotFoundException(); - return new AccountStatusDto({ status: KYCStatus.ACTIVE }); + return new AccountStatusDto({ status: WhiteListStatus.ACTIVE }); } @Post('link-wallet') diff --git a/packages/api/src/modules/accounts/accounts.dto.ts b/packages/api/src/modules/accounts/accounts.dto.ts index 943a28a28..18366daef 100644 --- a/packages/api/src/modules/accounts/accounts.dto.ts +++ b/packages/api/src/modules/accounts/accounts.dto.ts @@ -1,17 +1,17 @@ import { ApiProperty } from '@nestjs/swagger'; import { IsEnum } from 'class-validator'; -import { KYCStatus } from './kyc.dto'; +import { WhiteListStatus } from './whiteList.dto'; export class AccountStatusDto { - @IsEnum(KYCStatus) + @IsEnum(WhiteListStatus) @ApiProperty({ example: 'active', - description: 'account kyc status', - enum: KYCStatus, - enumName: 'KYCStatus', + description: 'account white list status', + enum: WhiteListStatus, + enumName: 'WhiteListStatus', }) - status: KYCStatus; + status: WhiteListStatus; constructor(partial: Partial) { Object.assign(this, partial); diff --git a/packages/api/src/modules/accounts/accounts.module.ts b/packages/api/src/modules/accounts/accounts.module.ts index 21ca4efd5..7b362afe6 100644 --- a/packages/api/src/modules/accounts/accounts.module.ts +++ b/packages/api/src/modules/accounts/accounts.module.ts @@ -7,13 +7,13 @@ import { VaultsModule } from '../vaults/vaults.module'; import { VaultsService } from '../vaults/vaults.service'; import { AccountsController } from './accounts.controller'; -import { KycService } from './kyc.service'; import { WalletsService } from './wallets.service'; +import { WhiteListService } from './whiteList.service'; @Module({ imports: [ConfigurationModule, SupabaseModule, EthersModule, VaultsModule], - providers: [KycService, WalletsService, VaultsService], + providers: [WhiteListService, WalletsService, VaultsService], controllers: [AccountsController], - exports: [KycService, WalletsService], + exports: [WhiteListService, WalletsService], }) export class AccountsModule {} diff --git a/packages/api/src/modules/accounts/kyc.dto.ts b/packages/api/src/modules/accounts/whiteList.dto.ts similarity index 77% rename from packages/api/src/modules/accounts/kyc.dto.ts rename to packages/api/src/modules/accounts/whiteList.dto.ts index 74ccc0a50..2f32d5022 100644 --- a/packages/api/src/modules/accounts/kyc.dto.ts +++ b/packages/api/src/modules/accounts/whiteList.dto.ts @@ -1,13 +1,13 @@ import { ApiProperty } from '@nestjs/swagger'; import { IsString } from 'class-validator'; -export enum KYCStatus { +export enum WhiteListStatus { ACTIVE = 'active', PENDING = 'pending', REJECTED = 'rejected', } -export class WhitelistAccountDto { +export class WhiteListAccountDto { @IsString() @ApiProperty({ example: '0x0000000', @@ -21,7 +21,7 @@ export class WhitelistAccountDto { }) user_id: string; - constructor(partial: Partial) { + constructor(partial: Partial) { Object.assign(this, partial); } } diff --git a/packages/api/src/modules/accounts/kyc.service.ts b/packages/api/src/modules/accounts/whiteList.service.ts similarity index 66% rename from packages/api/src/modules/accounts/kyc.service.ts rename to packages/api/src/modules/accounts/whiteList.service.ts index 71d0d8487..1f609de4c 100644 --- a/packages/api/src/modules/accounts/kyc.service.ts +++ b/packages/api/src/modules/accounts/whiteList.service.ts @@ -1,4 +1,4 @@ -import { CredbullKYCProvider__factory } from '@credbull/contracts'; +import { CredbullWhiteListProvider__factory } from '@credbull/contracts'; import { Injectable } from '@nestjs/common'; import * as _ from 'lodash'; @@ -9,36 +9,36 @@ import { ServiceResponse } from '../../types/responses'; import { Tables } from '../../types/supabase'; import { responseFromRead, responseFromWrite } from '../../utils/contracts'; -import { KYCStatus, WhitelistAccountDto } from './kyc.dto'; +import { WhiteListAccountDto, WhiteListStatus } from './whiteList.dto'; @Injectable() -export class KycService { +export class WhiteListService { constructor( private readonly ethers: EthersService, private readonly supabase: SupabaseService, private readonly supabaseAdmin: SupabaseAdminService, ) {} - async status(): Promise> { + async status(): Promise> { const client = this.supabase.client(); - const events = await client.from('kyc_events').select().eq('event_name', 'accepted').single(); + const events = await client.from('whitelist_events').select().eq('event_name', 'accepted').single(); if (events.error) return events; - if (!events.data?.address) return { data: KYCStatus.PENDING }; + if (!events.data?.address) return { data: WhiteListStatus.PENDING }; - const kycProvider = await client.from('vault_entities').select('*').eq('type', 'kyc_provider'); - if (kycProvider.error) return kycProvider; + const whiteListProvider = await client.from('vault_entities').select('*').eq('type', 'whitelist_provider'); + if (whiteListProvider.error) return whiteListProvider; - const distinctProviders = _.uniqBy(kycProvider.data ?? [], 'address'); + const distinctProviders = _.uniqBy(whiteListProvider.data ?? [], 'address'); const check = await this.checkOnChain(distinctProviders, events.data?.address); if (check.error) return check; - return check.data ? { data: KYCStatus.ACTIVE } : { data: KYCStatus.REJECTED }; + return check.data ? { data: WhiteListStatus.ACTIVE } : { data: WhiteListStatus.REJECTED }; } - async whitelist(dto: WhitelistAccountDto): Promise[]>> { + async whitelist(dto: WhiteListAccountDto): Promise[]>> { const admin = this.supabaseAdmin.admin(); const wallet = await admin @@ -49,7 +49,7 @@ export class KycService { .single(); if (wallet.error) return wallet; - const query = admin.from('vault_entities').select('address').eq('type', 'kyc_provider'); + const query = admin.from('vault_entities').select('address').eq('type', 'whitelist_provider'); if (wallet.data.discriminator) { query.eq('tenant', dto.user_id); } else { @@ -78,7 +78,7 @@ export class KycService { if (errors.length) return { error: new AggregateError(errors) }; const existing = await admin - .from('kyc_events') + .from('whitelist_events') .select() .eq('address', dto.address) .eq('user_id', dto.user_id) @@ -89,33 +89,36 @@ export class KycService { if (existing.data) return { data: [existing.data] }; return admin - .from('kyc_events') + .from('whitelist_events') .insert({ ...dto, event_name: 'accepted' }) .select(); } private async checkOnChain( - kycProviders: Tables<'vault_entities'>[], + whiteListProviders: Tables<'vault_entities'>[], address: string, ): Promise> { const errors = []; let status = false; - for (const kyc of kycProviders) { - const provider = await this.getOnChainProvider(kyc.address); + for (const whiteListProvider of whiteListProviders) { + const provider = await this.getOnChainProvider(whiteListProvider.address); const { error, data } = await responseFromRead(provider, provider.status(address)); if (error) { errors.push(error); continue; } - status = status && data; - if (!status) break; + // If the address is white listed by ANY active WhiteListProvider, it is deemed white listed. + if (data) { + status = true; + break; + } } return errors.length > 0 ? { error: new AggregateError(errors) } : { data: status }; } private async getOnChainProvider(address: string) { - return CredbullKYCProvider__factory.connect(address, await this.ethers.operator()); + return CredbullWhiteListProvider__factory.connect(address, await this.ethers.operator()); } } diff --git a/packages/api/src/modules/vaults/sync-vaults.service.ts b/packages/api/src/modules/vaults/sync-vaults.service.ts index 40d07aca9..38362c9ca 100644 --- a/packages/api/src/modules/vaults/sync-vaults.service.ts +++ b/packages/api/src/modules/vaults/sync-vaults.service.ts @@ -146,15 +146,13 @@ export class SyncVaultsService { return { type: 'fixed_yield_upside', status: 'created' as const, - deposits_opened_at: toISOString(Number(params.fixedYieldVaultParams.windowVaultParams.depositWindow.opensAt)), - deposits_closed_at: toISOString(Number(params.fixedYieldVaultParams.windowVaultParams.depositWindow.closesAt)), - redemptions_opened_at: toISOString(Number(params.fixedYieldVaultParams.windowVaultParams.matureWindow.opensAt)), - redemptions_closed_at: toISOString( - Number(params.fixedYieldVaultParams.windowVaultParams.matureWindow.closesAt), - ), + deposits_opened_at: toISOString(Number(params.fixedYieldVault.windowPlugin.depositWindow.opensAt)), + deposits_closed_at: toISOString(Number(params.fixedYieldVault.windowPlugin.depositWindow.closesAt)), + redemptions_opened_at: toISOString(Number(params.fixedYieldVault.windowPlugin.redemptionWindow.opensAt)), + redemptions_closed_at: toISOString(Number(params.fixedYieldVault.windowPlugin.redemptionWindow.closesAt)), address: event.args.vault, strategy_address: event.args.vault, - asset_address: params.fixedYieldVaultParams.maturityVaultParams.baseVaultParams.asset, + asset_address: params.fixedYieldVault.maturityVault.vault.asset, tenant, } as Tables<'vaults'>; } @@ -163,13 +161,13 @@ export class SyncVaultsService { return { type: 'fixed_yield', status: 'created' as const, - deposits_opened_at: toISOString(Number(params.windowVaultParams.depositWindow.opensAt)), - deposits_closed_at: toISOString(Number(params.windowVaultParams.depositWindow.opensAt)), - redemptions_opened_at: toISOString(Number(params.windowVaultParams.matureWindow.opensAt)), - redemptions_closed_at: toISOString(Number(params.windowVaultParams.matureWindow.closesAt)), + deposits_opened_at: toISOString(Number(params.windowPlugin.depositWindow.opensAt)), + deposits_closed_at: toISOString(Number(params.windowPlugin.depositWindow.opensAt)), + redemptions_opened_at: toISOString(Number(params.windowPlugin.redemptionWindow.opensAt)), + redemptions_closed_at: toISOString(Number(params.windowPlugin.redemptionWindow.closesAt)), address: event.args.vault, strategy_address: event.args.vault, - asset_address: params.maturityVaultParams.baseVaultParams.asset, + asset_address: params.maturityVault.vault.asset, tenant, } as Tables<'vaults'>; } diff --git a/packages/api/src/modules/vaults/vaults.dto.ts b/packages/api/src/modules/vaults/vaults.dto.ts index 59fcd0771..75a2a155f 100644 --- a/packages/api/src/modules/vaults/vaults.dto.ts +++ b/packages/api/src/modules/vaults/vaults.dto.ts @@ -21,7 +21,7 @@ export class VaultsDto { export class EntitiesDto { @Expose() - type: 'treasury' | 'custodian' | 'activity_reward' | 'vault' | 'kyc_provider'; + type: 'treasury' | 'custodian' | 'activity_reward' | 'vault' | 'whitelist_provider'; @Expose() address: string; @@ -77,7 +77,7 @@ export class VaultParamsDto extends EntitiesDto { @ApiProperty({ type: String, example: '0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512' }) @IsString() - kycProvider: string; + whiteListProvider: string; @ApiProperty({ type: String, example: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8' }) @IsString() @@ -97,7 +97,7 @@ export class VaultParamsDto extends EntitiesDto { @ApiProperty({ type: String, example: '1000000000', description: 'Should be in wei with 6 decimals' }) @IsString() - depositThresholdForWhitelisting: string; + depositThresholdForWhiteListing: string; @ApiProperty({ type: EntitiesDto, diff --git a/packages/api/src/modules/vaults/vaults.service.ts b/packages/api/src/modules/vaults/vaults.service.ts index 4a3ad296d..5a4ac3684 100644 --- a/packages/api/src/modules/vaults/vaults.service.ts +++ b/packages/api/src/modules/vaults/vaults.service.ts @@ -115,7 +115,7 @@ export class VaultsService { upside: boolean = false, collateralPercentage?: number, ): FixedYieldVault.FixedYieldVaultParamsStruct | UpsideVault.UpsideVaultParamsStruct { - const baseVaultParams = { + const vaultParams = { asset: params.asset, shareName: params.shareName, shareSymbol: params.shareSymbol, @@ -133,36 +133,36 @@ export class VaultsService { closesAt: params.depositClosesAt, }; - const matureWindowParam = { + const redemptionWindowParam = { opensAt: params.redemptionOpensAt, closesAt: params.redemptionClosesAt, }; - const windowVaultParams = { + const windowPluginParams = { depositWindow: depositWindowParam, - matureWindow: matureWindowParam, + redemptionWindow: redemptionWindowParam, }; - const kycParams = { - kycProvider: params.kycProvider, - depositThresholdForWhitelisting: params.depositThresholdForWhitelisting, + const whiteListPluginParams = { + whiteListProvider: params.whiteListProvider, + depositThresholdForWhiteListing: params.depositThresholdForWhiteListing, }; - const maxCapParams = { + const maxCapPluginParams = { maxCap: params.maxCap, }; const maturityVaultParams: MaturityVault.MaturityVaultParamsStruct = { - baseVaultParams, - promisedYield: params.promisedYield, + vault: vaultParams, }; const fixedYieldVaultParams: FixedYieldVault.FixedYieldVaultParamsStruct = { - maturityVaultParams, - contractRoles, - windowVaultParams, - kycParams, - maxCapParams, + maturityVault: maturityVaultParams, + roles: contractRoles, + windowPlugin: windowPluginParams, + whiteListPlugin: whiteListPluginParams, + maxCapPlugin: maxCapPluginParams, + promisedYield: params.promisedYield, }; if (!upside) { @@ -170,7 +170,7 @@ export class VaultsService { } const upsideVaultParams: UpsideVault.UpsideVaultParamsStruct = { - fixedYieldVaultParams, + fixedYieldVault: fixedYieldVaultParams, cblToken: params.token, collateralPercentage: collateralPercentage as unknown as BigNumber, }; diff --git a/packages/api/src/types/supabase.ts b/packages/api/src/types/supabase.ts index 2b5f5412b..cee6390a8 100644 --- a/packages/api/src/types/supabase.ts +++ b/packages/api/src/types/supabase.ts @@ -30,31 +30,31 @@ export type Database = { }; Relationships: []; }; - kyc_events: { + whitelist_events: { Row: { address: string; created_at: string; - event_name: Database['public']['Enums']['kyc_event']; + event_name: Database['public']['Enums']['whitelist_event']; id: number; user_id: string; }; Insert: { address: string; created_at?: string; - event_name: Database['public']['Enums']['kyc_event']; + event_name: Database['public']['Enums']['whitelist_event']; id?: number; user_id: string; }; Update: { address?: string; created_at?: string; - event_name?: Database['public']['Enums']['kyc_event']; + event_name?: Database['public']['Enums']['whitelist_event']; id?: number; user_id?: string; }; Relationships: [ { - foreignKeyName: 'kyc_events_user_id_fkey'; + foreignKeyName: 'whitelist_events_user_id_fkey'; columns: ['user_id']; isOneToOne: false; referencedRelation: 'users'; @@ -239,8 +239,8 @@ export type Database = { [_ in never]: never; }; Enums: { - kyc_event: 'processing' | 'accepted' | 'rejected'; - vault_entity_types: 'activity_reward' | 'treasury' | 'vault' | 'custodian' | 'kyc_provider'; + whitelist_event: 'processing' | 'accepted' | 'rejected'; + vault_entity_types: 'activity_reward' | 'treasury' | 'vault' | 'custodian' | 'whitelist_provider'; vault_status: 'created' | 'ready' | 'matured'; vault_type: 'fixed_yield' | 'fixed_yield_upside'; }; diff --git a/packages/api/supabase/migrations/20240702110629_whiteList.sql b/packages/api/supabase/migrations/20240702110629_whiteList.sql new file mode 100644 index 000000000..00daa6964 --- /dev/null +++ b/packages/api/supabase/migrations/20240702110629_whiteList.sql @@ -0,0 +1,135 @@ +create type "public"."whitelist_event" as enum ('processing', 'accepted', 'rejected'); + +drop policy "Only users based on user_id" on "public"."kyc_events"; + +revoke delete on table "public"."kyc_events" from "anon"; + +revoke insert on table "public"."kyc_events" from "anon"; + +revoke references on table "public"."kyc_events" from "anon"; + +revoke select on table "public"."kyc_events" from "anon"; + +revoke trigger on table "public"."kyc_events" from "anon"; + +revoke truncate on table "public"."kyc_events" from "anon"; + +revoke update on table "public"."kyc_events" from "anon"; + +revoke delete on table "public"."kyc_events" from "authenticated"; + +revoke insert on table "public"."kyc_events" from "authenticated"; + +revoke references on table "public"."kyc_events" from "authenticated"; + +revoke select on table "public"."kyc_events" from "authenticated"; + +revoke trigger on table "public"."kyc_events" from "authenticated"; + +revoke truncate on table "public"."kyc_events" from "authenticated"; + +revoke update on table "public"."kyc_events" from "authenticated"; + +revoke delete on table "public"."kyc_events" from "service_role"; + +revoke insert on table "public"."kyc_events" from "service_role"; + +revoke references on table "public"."kyc_events" from "service_role"; + +revoke select on table "public"."kyc_events" from "service_role"; + +revoke trigger on table "public"."kyc_events" from "service_role"; + +revoke truncate on table "public"."kyc_events" from "service_role"; + +revoke update on table "public"."kyc_events" from "service_role"; + +alter table "public"."kyc_events" drop constraint "kyc_events_user_id_fkey"; + +alter table "public"."kyc_events" drop constraint "kyc_events_pkey"; + +drop index if exists "public"."kyc_events_pkey"; + +drop table "public"."kyc_events"; + +alter type "public"."vault_entity_types" rename to "vault_entity_types__old_version_to_be_dropped"; + +create type "public"."vault_entity_types" as enum ('activity_reward', 'treasury', 'vault', 'custodian', 'whitelist_provider'); + +create table "public"."whitelist_events" ( + "id" bigint generated by default as identity not null, + "user_id" uuid not null, + "address" text not null, + "event_name" whitelist_event not null, + "created_at" timestamp with time zone not null default now() +); + + +alter table "public"."whitelist_events" enable row level security; + +alter table "public"."vault_entities" alter column type type "public"."vault_entity_types" using type::text::"public"."vault_entity_types"; + +drop type "public"."vault_entity_types__old_version_to_be_dropped"; + +drop type "public"."kyc_event"; + +CREATE UNIQUE INDEX whitelist_events_pkey ON public.whitelist_events USING btree (id); + +alter table "public"."whitelist_events" add constraint "whitelist_events_pkey" PRIMARY KEY using index "whitelist_events_pkey"; + +alter table "public"."whitelist_events" add constraint "whitelist_events_user_id_fkey" FOREIGN KEY (user_id) REFERENCES auth.users(id) not valid; + +alter table "public"."whitelist_events" validate constraint "whitelist_events_user_id_fkey"; + +grant delete on table "public"."whitelist_events" to "anon"; + +grant insert on table "public"."whitelist_events" to "anon"; + +grant references on table "public"."whitelist_events" to "anon"; + +grant select on table "public"."whitelist_events" to "anon"; + +grant trigger on table "public"."whitelist_events" to "anon"; + +grant truncate on table "public"."whitelist_events" to "anon"; + +grant update on table "public"."whitelist_events" to "anon"; + +grant delete on table "public"."whitelist_events" to "authenticated"; + +grant insert on table "public"."whitelist_events" to "authenticated"; + +grant references on table "public"."whitelist_events" to "authenticated"; + +grant select on table "public"."whitelist_events" to "authenticated"; + +grant trigger on table "public"."whitelist_events" to "authenticated"; + +grant truncate on table "public"."whitelist_events" to "authenticated"; + +grant update on table "public"."whitelist_events" to "authenticated"; + +grant delete on table "public"."whitelist_events" to "service_role"; + +grant insert on table "public"."whitelist_events" to "service_role"; + +grant references on table "public"."whitelist_events" to "service_role"; + +grant select on table "public"."whitelist_events" to "service_role"; + +grant trigger on table "public"."whitelist_events" to "service_role"; + +grant truncate on table "public"."whitelist_events" to "service_role"; + +grant update on table "public"."whitelist_events" to "service_role"; + +create policy "Only users based on user_id" +on "public"."whitelist_events" +as permissive +for all +to public +using ((auth.uid() = user_id)) +with check ((auth.uid() = user_id)); + + + diff --git a/packages/app/next.config.mjs b/packages/app/next.config.mjs index 6c17ea4ba..f23f52d6d 100644 --- a/packages/app/next.config.mjs +++ b/packages/app/next.config.mjs @@ -2,9 +2,6 @@ * @type {import("next").NextConfig} */ const nextConfig = { - experimental: { - serverActions: true, - }, transpilePackages: ['@credbull/sdk'], webpack: (config) => { config.externals.push({ diff --git a/packages/app/src/app/(protected)/dashboard/actions.ts b/packages/app/src/app/(protected)/dashboard/actions.ts index aef4e0d5f..e2441d066 100644 --- a/packages/app/src/app/(protected)/dashboard/actions.ts +++ b/packages/app/src/app/(protected)/dashboard/actions.ts @@ -3,17 +3,17 @@ import { cookies } from 'next/headers'; import { createClient as createCredbull } from '@/clients/credbull-api.client'; -import { createClient as createSuabase, createClient as createSupabase } from '@/clients/supabase.server'; +import { createClient as createSupabase } from '@/clients/supabase.server'; export const accountStatus = async () => { - const supabase = createSuabase(cookies()); + const supabase = createSupabase(cookies()); const credbullApi = createCredbull(supabase); return credbullApi.accountStatus(); }; export const linkWallet = async (message: string, signature: string, discriminator?: string) => { - const supabase = createSuabase(cookies()); + const supabase = createSupabase(cookies()); const credbullApi = createCredbull(supabase); await credbullApi.linkWallet(message, signature, discriminator); @@ -21,7 +21,7 @@ export const linkWallet = async (message: string, signature: string, discriminat export const mockTokenAddress = async (): Promise => { const admin = createSupabase(cookies(), { admin: true }); - const { data } = await admin.from('contracts_addresses').select().eq('contract_name', 'MockToken').single(); + const { data } = await admin.from('contracts_addresses').select().eq('contract_name', 'SimpleToken').single(); return data?.address; }; diff --git a/packages/app/src/app/(protected)/dashboard/debug/debug-new.tsx b/packages/app/src/app/(protected)/dashboard/debug/debug-new.tsx index 5afaeb859..eb968d2b3 100644 --- a/packages/app/src/app/(protected)/dashboard/debug/debug-new.tsx +++ b/packages/app/src/app/(protected)/dashboard/debug/debug-new.tsx @@ -1,14 +1,8 @@ 'use client'; import { Tables } from '@credbull/api'; -import { - CredbullBaseVault__factory, - ERC4626__factory, - FixedYieldVault__factory, - MockStablecoin__factory, - MockToken__factory, -} from '@credbull/contracts'; -// import { CredbullSDK } from '@credbull/sdk'; +import { ERC4626__factory, SimpleToken__factory, SimpleUSDC__factory } from '@credbull/contracts'; +import { CredbullSDK } from '@credbull/sdk'; import { Button, Card, Flex, Group, NumberInput, SimpleGrid, Text, TextInput } from '@mantine/core'; import { zodResolver } from '@mantine/form'; import { useClipboard } from '@mantine/hooks'; @@ -16,9 +10,7 @@ import { OpenNotificationParams, useList, useNotification, useOne } from '@refin import { useForm } from '@refinedev/mantine'; import { IconCopy } from '@tabler/icons'; import { getPublicClient } from '@wagmi/core'; -import { utils } from 'ethers'; -import { ethers } from 'ethers'; -import { Signer } from 'ethers'; +import { Signer, utils } from 'ethers'; import { useEffect, useState } from 'react'; import { createWalletClient, http, parseEther } from 'viem'; import { waitForTransactionReceipt } from 'viem/actions'; @@ -28,9 +20,9 @@ import { z } from 'zod'; import { BalanceOf } from '@/components/contracts/balance-of'; -import { whitelistAddress } from '@/app/(protected)/dashboard/debug/actions'; +import { getEthersSigner } from '@/utils/ether-adapters'; -import { getEthersSigner } from '../../../../utils/ether-adapters'; +import { whitelistAddress } from '@/app/(protected)/dashboard/debug/actions'; declare global { interface Window { @@ -56,7 +48,7 @@ const MintUSDC = ({ erc20Address }: { erc20Address: string }) => { const { writeAsync } = useContractWrite({ address: erc20Address as Address, - abi: MockStablecoin__factory.abi, + abi: SimpleUSDC__factory.abi, functionName: 'mint', args: [form.values.address as Address, utils.parseUnits((form.values.amount ?? 0).toString(), 'mwei').toBigInt()], }); @@ -134,7 +126,7 @@ const MintCToken = ({ erc20Address }: { erc20Address: string }) => { const { writeAsync } = useContractWrite({ address: erc20Address as Address, - abi: MockToken__factory.abi, + abi: SimpleToken__factory.abi, functionName: 'mint', args: [form.values.address as Address, utils.parseUnits((form.values.amount ?? 0).toString(), 18).toBigInt()], }); @@ -360,25 +352,25 @@ const VaultDeposit = ({ erc20Address, mockTokenAddress }: { erc20Address: string }; // TODO: unexpected dependency on SDK here - is this required? -// const LinkWallet = () => { -// const { connector } = useAccount(); -// -// const link = async () => { -// const signer = await getEthersSigner({ chainId: await connector?.getChainId() }); -// const sdk = new CredbullSDK( -// process.env.API_BASE_URL || '', -// { accessToken: process.env.NEXT_PUBLIC_ACCESS_TOKEN as string }, -// signer as Signer, -// ); -// await sdk.linkWallet(); -// }; -// -// return ( -// <> -// -// -// ); -// }; +const LinkWallet = () => { + const { connector } = useAccount(); + + const link = async () => { + const signer = await getEthersSigner({ chainId: await connector?.getChainId() }); + const sdk = new CredbullSDK( + process.env.API_BASE_URL || '', + { accessToken: process.env.NEXT_PUBLIC_ACCESS_TOKEN as string }, + signer as Signer, + ); + await sdk.linkWallet(); + }; + + return ( + <> + + + ); +}; const WhitelistWalletAddress = () => { const { open } = useNotification(); @@ -445,7 +437,7 @@ export function Debug(props: { mockTokenAddress: string | undefined }) { - {/**/} + ); diff --git a/packages/app/src/app/(protected)/dashboard/debug/debug.tsx b/packages/app/src/app/(protected)/dashboard/debug/debug.tsx index f3ebbd7e3..448087584 100644 --- a/packages/app/src/app/(protected)/dashboard/debug/debug.tsx +++ b/packages/app/src/app/(protected)/dashboard/debug/debug.tsx @@ -1,13 +1,7 @@ 'use client'; import { Tables } from '@credbull/api'; -import { - CredbullBaseVault__factory, - ERC4626__factory, - FixedYieldVault__factory, - MockStablecoin__factory, - MockToken__factory, -} from '@credbull/contracts'; +import { ERC4626__factory, SimpleToken__factory, SimpleUSDC__factory } from '@credbull/contracts'; import { Button, Card, Flex, Group, NumberInput, SimpleGrid, Text, TextInput } from '@mantine/core'; import { zodResolver } from '@mantine/form'; import { useClipboard } from '@mantine/hooks'; @@ -53,7 +47,7 @@ const MintUSDC = ({ erc20Address }: { erc20Address: string }) => { const { writeAsync } = useContractWrite({ address: erc20Address as Address, - abi: MockStablecoin__factory.abi, + abi: SimpleUSDC__factory.abi, functionName: 'mint', args: [form.values.address as Address, utils.parseUnits((form.values.amount ?? 0).toString(), 'mwei').toBigInt()], }); @@ -131,7 +125,7 @@ const MintCToken = ({ erc20Address }: { erc20Address: string }) => { const { writeAsync } = useContractWrite({ address: erc20Address as Address, - abi: MockToken__factory.abi, + abi: SimpleToken__factory.abi, functionName: 'mint', args: [form.values.address as Address, utils.parseUnits((form.values.amount ?? 0).toString(), 18).toBigInt()], }); diff --git a/packages/app/src/app/(protected)/dashboard/lending.tsx b/packages/app/src/app/(protected)/dashboard/lending.tsx index b5321a792..8bab13d48 100644 --- a/packages/app/src/app/(protected)/dashboard/lending.tsx +++ b/packages/app/src/app/(protected)/dashboard/lending.tsx @@ -2,7 +2,7 @@ import { Tables } from '@credbull/api'; import { - CredbullKYCProvider__factory, + CredbullWhiteListProvider__factory, ERC20__factory, ERC4626__factory, FixedYieldVault__factory, @@ -43,7 +43,7 @@ function Vault(props: VaultProps) { const { data: client } = useWalletClient(); const isMatured = props.data.status === 'matured'; - const kycProvider = _.find(props.entities, { type: 'kyc_provider' }); + const whiteListProvider = _.find(props.entities, { type: 'whitelist_provider' }); const custodian = _.find(props.entities, { type: 'custodian' }); const reward = _.find(props.entities, { type: 'activity_reward' }); @@ -62,13 +62,13 @@ function Vault(props: VaultProps) { enabled: !!props.data.address && !!props.address, }); - const { data: kycStatus } = useContractRead({ - address: kycProvider?.address as Address, - abi: CredbullKYCProvider__factory.abi, + const { data: whiteListStatus } = useContractRead({ + address: whiteListProvider?.address as Address, + abi: CredbullWhiteListProvider__factory.abi, functionName: 'status', watch: true, args: [props.address as Address], - enabled: !!kycProvider?.address && !!props.address, + enabled: !!whiteListProvider?.address && !!props.address, }); const { data: vaultTotalAssets } = useContractRead({ @@ -299,10 +299,10 @@ function Vault(props: VaultProps) { - Your KYC Status + Your White List Status - {kycStatus ? 'Active' : 'Inactive'} + {whiteListStatus ? 'Active' : 'Inactive'} diff --git a/packages/app/src/app/(protected)/dashboard/upside/lending.tsx b/packages/app/src/app/(protected)/dashboard/upside/lending.tsx index ddbada048..cf1bcabfc 100644 --- a/packages/app/src/app/(protected)/dashboard/upside/lending.tsx +++ b/packages/app/src/app/(protected)/dashboard/upside/lending.tsx @@ -2,7 +2,7 @@ import { Tables } from '@credbull/api'; import { - CredbullKYCProvider__factory, + CredbullWhiteListProvider__factory, ERC20__factory, ERC4626__factory, FixedYieldVault__factory, @@ -41,7 +41,7 @@ function Vault(props: VaultProps) { const { open } = useNotification(); const isMatured = props.data[0].status === 'matured'; - const kycProvider = _.find(props.entities, { type: 'kyc_provider' }); + const whiteListProvider = _.find(props.entities, { type: 'whitelist_provider' }); const custodian = _.find(props.entities, { type: 'custodian' }); const reward = _.find(props.entities, { type: 'activity_reward' }); @@ -51,13 +51,13 @@ function Vault(props: VaultProps) { } }, [clipboard.copied, open]); - const { data: kycStatus } = useContractRead({ - address: kycProvider?.address as Address, - abi: CredbullKYCProvider__factory.abi, + const { data: whiteListStatus } = useContractRead({ + address: whiteListProvider?.address as Address, + abi: CredbullWhiteListProvider__factory.abi, functionName: 'status', watch: true, args: [props.address as Address], - enabled: !!kycProvider?.address && !!props.address, + enabled: !!whiteListProvider?.address && !!props.address, }); const { data: vaultTotalAssets0 } = useContractRead({ @@ -254,10 +254,10 @@ function Vault(props: VaultProps) { - Your KYC Status + Your White List Status - {kycStatus ? 'Active' : 'Inactive'} + {whiteListStatus ? 'Active' : 'Inactive'} diff --git a/packages/app/src/utils/rsc.ts b/packages/app/src/utils/rsc.ts index 7c1d7f7ea..803ac9467 100644 --- a/packages/app/src/utils/rsc.ts +++ b/packages/app/src/utils/rsc.ts @@ -1,3 +1,5 @@ export const getSegment = (props: any) => { - return props.children.props.childProp.segment; + console.log('SEGMENT=', props.children?.props?.childProp?.segment); + // FIX (JL,2024-07-05): This deref chain always results in `undefined`. How to fix? + return props.children?.props?.childProp?.segment; }; diff --git a/packages/contracts/.gitignore b/packages/contracts/.gitignore index 029746348..49cb88202 100644 --- a/packages/contracts/.gitignore +++ b/packages/contracts/.gitignore @@ -23,3 +23,4 @@ config.js # code coverage lcov.info +coverage/ diff --git a/packages/contracts/package.json b/packages/contracts/package.json index 01079e4cc..c32dbfdde 100755 --- a/packages/contracts/package.json +++ b/packages/contracts/package.json @@ -9,7 +9,7 @@ "build": "forge clean && forge build", "test": "forge test", "format": "forge fmt && prettier './script/**/*.js' --write", - "lint": "forge fmt && eslint --fix --ignore-path .gitignore && yarn solhint './*(test|src)/**/*.sol'", + "lint": "forge fmt && eslint --fix --ignore-path .gitignore && yarn solhint './*(test|src)/**/*.sol'", "db-check": "tsc && node ./script/utils/checkDb.js", "db-export": "tsc && node ./script/utils/exporter.js", "deploy": "make deploy-local", @@ -26,6 +26,7 @@ "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.1.3", "prettier": "^3.2.2", + "solhint": "^5.0.1", "typechain": "^8.3.2", "typescript": "^5.4.5" }, @@ -35,7 +36,6 @@ "@supabase/supabase-js": "^2.39.3", "dotenv": "^16.4.5", "ethers": "^5.7.2", - "js-toml": "^1.0.0", - "solhint": "^4.1.1" + "js-toml": "^1.0.0" } } diff --git a/packages/contracts/remappings.txt b/packages/contracts/remappings.txt index f8107635f..e8dce0e89 100755 --- a/packages/contracts/remappings.txt +++ b/packages/contracts/remappings.txt @@ -3,3 +3,6 @@ ds-test/=lib/forge-std/lib/ds-test/src/ erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/ forge-std/=lib/forge-std/src/ openzeppelin-contracts/=lib/openzeppelin-contracts/ +@credbull/=src/ +@script/=script/ +@test/=test/ diff --git a/packages/contracts/script/DeployMocks.s.sol b/packages/contracts/script/DeployMocks.s.sol index 0cd799006..fd6079363 100755 --- a/packages/contracts/script/DeployMocks.s.sol +++ b/packages/contracts/script/DeployMocks.s.sol @@ -3,13 +3,15 @@ pragma solidity ^0.8.19; import { Script } from "forge-std/Script.sol"; +import { console2 } from "forge-std/console2.sol"; -import { MockStablecoin } from "../test/mocks/MockStablecoin.sol"; -import { MockToken } from "../test/mocks/MockToken.sol"; +import { Vault } from "@credbull/vault/Vault.sol"; + +import { SimpleUSDC } from "@test/test/token/SimpleUSDC.t.sol"; +import { SimpleToken } from "@test/test/token/SimpleToken.t.sol"; +import { SimpleVault } from "@test/test/vault/SimpleVault.t.sol"; -import { console2 } from "forge-std/console2.sol"; import { DeployedContracts } from "./DeployedContracts.s.sol"; -import { CredbullBaseVaultMock } from "../test/mocks/vaults/CredbullBaseVaultMock.m.sol"; contract DeployMocks is Script { bool public isTestMode; @@ -18,42 +20,48 @@ contract DeployMocks is Script { uint128 public totalSupply = MAX_UINT128_SIZE; - CredbullBaseVaultMock internal credbullBaseVaultMock; + SimpleVault internal testVault; constructor(bool _isTestMode, address _custodian) { isTestMode = _isTestMode; custodian = _custodian; } - function run() public returns (MockToken, MockStablecoin) { + function run() public returns (SimpleToken, SimpleUSDC) { DeployedContracts deployChecker = new DeployedContracts(); - MockToken mockToken; - MockStablecoin mockStablecoin; + SimpleToken testToken; + SimpleUSDC testStablecoin; vm.startBroadcast(); - if (isTestMode || deployChecker.isDeployRequired("MockToken")) { - mockToken = new MockToken(totalSupply); - console2.log("!!!!! Deploying MockToken !!!!!"); + if (isTestMode || deployChecker.isDeployRequired("SimpleToken")) { + testToken = new SimpleToken(totalSupply); + console2.log("!!!!! Deploying SimpleToken !!!!!"); } else { - mockStablecoin = MockStablecoin(deployChecker.getContractAddress("MockStablecoin")); + testStablecoin = SimpleUSDC(deployChecker.getContractAddress("SimpleUSDC")); } - if (isTestMode || deployChecker.isDeployRequired("MockStablecoin")) { - mockStablecoin = new MockStablecoin(totalSupply); - console2.log("!!!!! Deploying MockStablecoin !!!!!"); + if (isTestMode || deployChecker.isDeployRequired("SimpleUSDC")) { + testStablecoin = new SimpleUSDC(totalSupply); + console2.log("!!!!! Deploying SimpleUSDC !!!!!"); } else { - mockToken = MockToken(deployChecker.getContractAddress("MockStablecoin")); + testToken = SimpleToken(deployChecker.getContractAddress("SimpleToken")); } - if (isTestMode || deployChecker.isDeployRequired("CredbullBaseVaultMock")) { - credbullBaseVaultMock = new CredbullBaseVaultMock(mockStablecoin, "Mock Vault", "mVault", custodian); - console2.log("!!!!! Deploying CredbullBaseVaultMock !!!!!"); + if (isTestMode || deployChecker.isDeployRequired("SimpleVault")) { + Vault.VaultParams memory params = Vault.VaultParams({ + asset: testStablecoin, + shareName: "Simple Vault", + shareSymbol: "smpVLT", + custodian: custodian + }); + testVault = new SimpleVault(params); + console2.log("!!!!! Deploying Simple Vault !!!!!"); } vm.stopBroadcast(); - return (mockToken, mockStablecoin); + return (testToken, testStablecoin); } } diff --git a/packages/contracts/script/DeployVaultFactory.s.sol b/packages/contracts/script/DeployVaultFactory.s.sol index 56f8deee7..556851c87 100644 --- a/packages/contracts/script/DeployVaultFactory.s.sol +++ b/packages/contracts/script/DeployVaultFactory.s.sol @@ -3,14 +3,17 @@ pragma solidity ^0.8.19; import { Script } from "forge-std/Script.sol"; -import { HelperConfig, NetworkConfig } from "../script/HelperConfig.s.sol"; -import { CredbullFixedYieldVaultFactory } from "../src/factories/CredbullFixedYieldVaultFactory.sol"; -import { CredbullUpsideVaultFactory } from "../src/factories/CredbullUpsideVaultFactory.sol"; -import { CredbullKYCProvider } from "../src/CredbullKYCProvider.sol"; -import { DeployedContracts } from "./DeployedContracts.s.sol"; -import { CredbullFixedYieldVault } from "../src/CredbullFixedYieldVault.sol"; import { console2 } from "forge-std/console2.sol"; +import { HelperConfig, NetworkConfig } from "@script/HelperConfig.s.sol"; + +import { CredbullFixedYieldVaultFactory } from "@credbull/CredbullFixedYieldVaultFactory.sol"; +import { CredbullUpsideVaultFactory } from "@credbull/CredbullUpsideVaultFactory.sol"; +import { CredbullWhiteListProvider } from "@credbull/CredbullWhiteListProvider.sol"; +import { CredbullFixedYieldVault } from "@credbull/CredbullFixedYieldVault.sol"; + +import { DeployedContracts } from "./DeployedContracts.s.sol"; + contract DeployVaultFactory is Script { bool private isTestMode; @@ -19,7 +22,7 @@ contract DeployVaultFactory is Script { returns ( CredbullFixedYieldVaultFactory factory, CredbullUpsideVaultFactory upsideFactory, - CredbullKYCProvider kycProvider, + CredbullWhiteListProvider whiteListProvider, HelperConfig helperConfig ) { @@ -32,7 +35,7 @@ contract DeployVaultFactory is Script { returns ( CredbullFixedYieldVaultFactory factory, CredbullUpsideVaultFactory upsideFactory, - CredbullKYCProvider kycProvider, + CredbullWhiteListProvider whiteListProvider, HelperConfig helperConfig ) { @@ -58,13 +61,13 @@ contract DeployVaultFactory is Script { console2.log("!!!!! Deploying CredbullVaultWithUpsideFactory !!!!!"); } - if (isTestMode || deployChecker.isDeployRequired("CredbullKYCProvider")) { - kycProvider = new CredbullKYCProvider(operator); - console2.log("!!!!! Deploying CredbullKYCProvider !!!!!"); + if (isTestMode || deployChecker.isDeployRequired("CredbullWhiteListProvider")) { + whiteListProvider = new CredbullWhiteListProvider(operator); + console2.log("!!!!! Deploying CredbullWhiteListProvider !!!!!"); } vm.stopBroadcast(); - return (factory, upsideFactory, kycProvider, helperConfig); + return (factory, upsideFactory, whiteListProvider, helperConfig); } } diff --git a/packages/contracts/script/DeployedContracts.s.sol b/packages/contracts/script/DeployedContracts.s.sol index 6ad0a6ecc..106f9909f 100755 --- a/packages/contracts/script/DeployedContracts.s.sol +++ b/packages/contracts/script/DeployedContracts.s.sol @@ -4,7 +4,6 @@ pragma solidity ^0.8.19; import { Script } from "forge-std/Script.sol"; import { stdJson } from "forge-std/StdJson.sol"; - import { console2 } from "forge-std/console2.sol"; /// @author ian lucas diff --git a/packages/contracts/script/HelperConfig.s.sol b/packages/contracts/script/HelperConfig.s.sol index 5c5cd487a..fc592b775 100755 --- a/packages/contracts/script/HelperConfig.s.sol +++ b/packages/contracts/script/HelperConfig.s.sol @@ -82,8 +82,8 @@ contract HelperConfig is Script { return networkConfig; } - /// Create the Factory Parameters instance from configuration. - /// @return The active Factory Parameters + /// Create the Factory Params instance from configuration. + /// @return The active Factory Params function createFactoryParamsFromConfig() internal view returns (FactoryParams memory) { FactoryParams memory factoryParams = FactoryParams({ owner: tomlConfig.readAddress(".evm.address.owner"), diff --git a/packages/contracts/src/CredbullFixedYieldVault.sol b/packages/contracts/src/CredbullFixedYieldVault.sol index 02b8349ca..b09968b79 100644 --- a/packages/contracts/src/CredbullFixedYieldVault.sol +++ b/packages/contracts/src/CredbullFixedYieldVault.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.19; -import { FixedYieldVault } from "./vaults/FixedYieldVault.sol"; +import { FixedYieldVault } from "./vault/FixedYieldVault.sol"; contract CredbullFixedYieldVault is FixedYieldVault { constructor(FixedYieldVaultParams memory params) FixedYieldVault(params) { } diff --git a/packages/contracts/src/factories/CredbullFixedYieldVaultFactory.sol b/packages/contracts/src/CredbullFixedYieldVaultFactory.sol similarity index 64% rename from packages/contracts/src/factories/CredbullFixedYieldVaultFactory.sol rename to packages/contracts/src/CredbullFixedYieldVaultFactory.sol index fe107245d..274bc2be6 100644 --- a/packages/contracts/src/factories/CredbullFixedYieldVaultFactory.sol +++ b/packages/contracts/src/CredbullFixedYieldVaultFactory.sol @@ -2,36 +2,36 @@ pragma solidity ^0.8.19; -import { CredbullFixedYieldVault } from "../CredbullFixedYieldVault.sol"; -import { CredbullVaultFactory } from "./CredbullVaultFactory.sol"; +import { CredbullFixedYieldVault } from "./CredbullFixedYieldVault.sol"; +import { VaultFactory } from "./factory/VaultFactory.sol"; -contract CredbullFixedYieldVaultFactory is CredbullVaultFactory { +contract CredbullFixedYieldVaultFactory is VaultFactory { /// @notice Event to emit when a new vault is created event VaultDeployed(address indexed vault, CredbullFixedYieldVault.FixedYieldVaultParams params, string options); + /** * @param owner - The owner of the factory contract * @param operator - The operator of the factory contract * @param custodians - The custodians allowable for the vaults */ - constructor(address owner, address operator, address[] memory custodians) - CredbullVaultFactory(owner, operator, custodians) + VaultFactory(owner, operator, custodians) { } /** * @notice - Function to create a new vault. Should be called only by the owner - * @param _params - The VaultParams + * @param params - The VaultParams */ - function createVault(CredbullFixedYieldVault.FixedYieldVaultParams memory _params, string memory options) + function createVault(CredbullFixedYieldVault.FixedYieldVaultParams memory params, string memory options) public virtual onlyRole(OPERATOR_ROLE) - onlyAllowedCustodians(_params.maturityVaultParams.baseVaultParams.custodian) + onlyAllowedCustodians(params.maturityVault.vault.custodian) returns (address) { - CredbullFixedYieldVault newVault = new CredbullFixedYieldVault(_params); + CredbullFixedYieldVault newVault = new CredbullFixedYieldVault(params); - emit VaultDeployed(address(newVault), _params, options); + emit VaultDeployed(address(newVault), params, options); _addVault(address(newVault)); diff --git a/packages/contracts/src/CredbullFixedYieldVaultWithUpside.sol b/packages/contracts/src/CredbullFixedYieldVaultWithUpside.sol index 7b9f7bb35..501279a30 100755 --- a/packages/contracts/src/CredbullFixedYieldVaultWithUpside.sol +++ b/packages/contracts/src/CredbullFixedYieldVaultWithUpside.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -import { UpsideVault } from "./vaults/UpsideVault.sol"; +import { UpsideVault } from "./vault/UpsideVault.sol"; contract CredbullFixedYieldVaultWithUpside is UpsideVault { - constructor(UpsideVault.UpsideVaultParams memory params) UpsideVault(params) { } + constructor(CredbullFixedYieldVaultWithUpside.UpsideVaultParams memory params) UpsideVault(params) { } } diff --git a/packages/contracts/src/factories/CredbullUpsideVaultFactory.sol b/packages/contracts/src/CredbullUpsideVaultFactory.sol similarity index 64% rename from packages/contracts/src/factories/CredbullUpsideVaultFactory.sol rename to packages/contracts/src/CredbullUpsideVaultFactory.sol index 0264b8211..854015864 100644 --- a/packages/contracts/src/factories/CredbullUpsideVaultFactory.sol +++ b/packages/contracts/src/CredbullUpsideVaultFactory.sol @@ -2,10 +2,10 @@ pragma solidity ^0.8.19; -import { CredbullFixedYieldVaultWithUpside } from "../CredbullFixedYieldVaultWithUpside.sol"; -import { CredbullVaultFactory } from "./CredbullVaultFactory.sol"; +import { CredbullFixedYieldVaultWithUpside } from "./CredbullFixedYieldVaultWithUpside.sol"; +import { VaultFactory } from "./factory/VaultFactory.sol"; -contract CredbullUpsideVaultFactory is CredbullVaultFactory { +contract CredbullUpsideVaultFactory is VaultFactory { /// @notice Event to emit when a new vault is created event VaultDeployed( address indexed vault, CredbullFixedYieldVaultWithUpside.UpsideVaultParams params, string options @@ -17,23 +17,23 @@ contract CredbullUpsideVaultFactory is CredbullVaultFactory { * @param custodians - The custodians allowable for the vaults */ constructor(address owner, address operator, address[] memory custodians) - CredbullVaultFactory(owner, operator, custodians) + VaultFactory(owner, operator, custodians) { } /** * @notice - Function to create a new upside vault. Should be called only by the owner - * @param _params - The VaultParams + * @param params - The VaultParams * @param options - A JSON string that contains additional info about vault (Off-chain use case) */ - function createVault(CredbullFixedYieldVaultWithUpside.UpsideVaultParams memory _params, string memory options) + function createVault(CredbullFixedYieldVaultWithUpside.UpsideVaultParams memory params, string memory options) public onlyRole(OPERATOR_ROLE) - onlyAllowedCustodians(_params.fixedYieldVaultParams.maturityVaultParams.baseVaultParams.custodian) + onlyAllowedCustodians(params.fixedYieldVault.maturityVault.vault.custodian) returns (address) { - CredbullFixedYieldVaultWithUpside newVault = new CredbullFixedYieldVaultWithUpside(_params); + CredbullFixedYieldVaultWithUpside newVault = new CredbullFixedYieldVaultWithUpside(params); - emit VaultDeployed(address(newVault), _params, options); + emit VaultDeployed(address(newVault), params, options); _addVault(address(newVault)); diff --git a/packages/contracts/src/CredbullWhiteListProvider.sol b/packages/contracts/src/CredbullWhiteListProvider.sol new file mode 100755 index 000000000..7323e867c --- /dev/null +++ b/packages/contracts/src/CredbullWhiteListProvider.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import { WhiteListProvider } from "./provider/whiteList/WhiteListProvider.sol"; + +/** + * @title Credbull White List Provider implementation. + * @author @pasviegas + * @notice The deployable white list provider contract. + */ +contract CredbullWhiteListProvider is WhiteListProvider { + constructor(address _owner) WhiteListProvider(_owner) { } +} diff --git a/packages/contracts/src/factories/CredbullVaultFactory.sol b/packages/contracts/src/factory/VaultFactory.sol similarity index 98% rename from packages/contracts/src/factories/CredbullVaultFactory.sol rename to packages/contracts/src/factory/VaultFactory.sol index f451fe5b2..8edf41800 100644 --- a/packages/contracts/src/factories/CredbullVaultFactory.sol +++ b/packages/contracts/src/factory/VaultFactory.sol @@ -8,7 +8,7 @@ import { AccessControl } from "@openzeppelin/contracts/access/AccessControl.sol" /** * @notice - A factory contract to create vault contract */ -abstract contract CredbullVaultFactory is AccessControl { +abstract contract VaultFactory is AccessControl { using EnumerableSet for EnumerableSet.AddressSet; /// @notice Error to revert if custodian is not allowed @@ -48,7 +48,6 @@ abstract contract CredbullVaultFactory is AccessControl { if (!allowedCustodians.contains(_custodian)) { revert CredbullVaultFactory__CustodianNotAllowed(); } - _; } diff --git a/packages/contracts/src/interface/IErrors.sol b/packages/contracts/src/interface/IErrors.sol deleted file mode 100644 index ea3ed8ef6..000000000 --- a/packages/contracts/src/interface/IErrors.sol +++ /dev/null @@ -1,7 +0,0 @@ -//SPDX-License-Identifier: MIT - -pragma solidity ^0.8.19; - -interface IErrors { - error ZeroAddress(); -} diff --git a/packages/contracts/src/plugins/MaxCapPlugIn.sol b/packages/contracts/src/plugin/MaxCapPlugin.sol similarity index 80% rename from packages/contracts/src/plugins/MaxCapPlugIn.sol rename to packages/contracts/src/plugin/MaxCapPlugin.sol index 3ec73f732..37820f48d 100644 --- a/packages/contracts/src/plugins/MaxCapPlugIn.sol +++ b/packages/contracts/src/plugin/MaxCapPlugin.sol @@ -2,12 +2,12 @@ pragma solidity ^0.8.19; -/// @notice - A PlugIn to handle MaxCap -abstract contract MaxCapPlugIn { +/// @notice - A Plugin to handle MaxCap +abstract contract MaxCapPlugin { error CredbullVault__MaxCapReached(); - /// @notice - Parameters for the MaxCap PlugIn - struct MaxCapParams { + /// @notice - Params for the MaxCap Plugin + struct MaxCapPluginParams { uint256 maxCap; } @@ -17,8 +17,8 @@ abstract contract MaxCapPlugIn { /// @notice Flag to check for max cap bool public checkMaxCap; - constructor(uint256 _maxCap) { - maxCap = _maxCap; + constructor(MaxCapPluginParams memory params) { + maxCap = params.maxCap; checkMaxCap = true; // Set the check to true by default } diff --git a/packages/contracts/src/plugin/WhiteListPlugin.sol b/packages/contracts/src/plugin/WhiteListPlugin.sol new file mode 100644 index 000000000..0aa9e88f5 --- /dev/null +++ b/packages/contracts/src/plugin/WhiteListPlugin.sol @@ -0,0 +1,50 @@ +//SPDX-License-Identifier: MIT + +pragma solidity ^0.8.19; + +import { IWhiteListProvider } from "../provider/whiteList/IWhiteListProvider.sol"; + +/// @notice - A Plugin to handle whiteListing +abstract contract WhiteListPlugin { + /// @notice If an invalid `IWhiteListProvider` Address is provided. + error CredbullVault__InvalidWhiteListProviderAddress(address); + /// @notice Error to revert if the address is not whiteListed + error CredbullVault__NotWhiteListed(address, uint256); + + /// @notice - Params for the WhiteList Plugin + struct WhiteListPluginParams { + address whiteListProvider; + uint256 depositThresholdForWhiteListing; + } + + /// @notice - Address of the White List Provider. + IWhiteListProvider public whiteListProvider; + + /// @notice - Flag to check for whiteList + bool public checkWhiteList; + + /// @notice - Deposit threshold amount to check for whiteListing + uint256 public depositThresholdForWhiteListing; + + constructor(WhiteListPluginParams memory params) { + if (params.whiteListProvider == address(0)) { + revert CredbullVault__InvalidWhiteListProviderAddress(params.whiteListProvider); + } + + whiteListProvider = IWhiteListProvider(params.whiteListProvider); + checkWhiteList = true; // Set the check to true by default + depositThresholdForWhiteListing = params.depositThresholdForWhiteListing; + } + + /// @notice - Function to check for whiteListed address + function _checkIsWhiteListed(address receiver, uint256 amount) internal view virtual { + if (checkWhiteList && amount >= depositThresholdForWhiteListing && !whiteListProvider.status(receiver)) { + revert CredbullVault__NotWhiteListed(receiver, amount); + } + } + + /// @notice - Function to toggle check for whiteListed address + function _toggleWhiteListCheck(bool status) internal virtual { + checkWhiteList = status; + } +} diff --git a/packages/contracts/src/plugin/WindowPlugin.sol b/packages/contracts/src/plugin/WindowPlugin.sol new file mode 100644 index 000000000..e10104043 --- /dev/null +++ b/packages/contracts/src/plugin/WindowPlugin.sol @@ -0,0 +1,82 @@ +//SPDX-License-Identifier: MIT + +pragma solidity ^0.8.19; + +/// @notice - A plugin to handle deposit and redemption windows +abstract contract WindowPlugin { + /// @notice Error to revert when operation is outside required window + error CredbullVault__OperationOutsideRequiredWindow( + uint256 windowOpensAt, uint256 windowClosesAt, uint256 timestamp + ); + + /// @notice A Window is essentially a Time Span, denoted by an Opening and Closing Time pair. + struct Window { + uint256 opensAt; + uint256 closesAt; + } + + /// @notice - Struct to hold window parameters + struct WindowPluginParams { + Window depositWindow; + Window redemptionWindow; + } + + /// @dev The timestamp when the vault opens for deposit. + uint256 public depositOpensAtTimestamp; + + /// @dev The timestamp when the vault closes for deposit. + uint256 public depositClosesAtTimestamp; + + /// @dev The timestamp when the vault opens for redemption. + uint256 public redemptionOpensAtTimestamp; + + /// @dev The timestamp when the vault closes for redemption. + uint256 public redemptionClosesAtTimestamp; + + /// @notice - Flag to check for window + bool public checkWindow; + + constructor(WindowPluginParams memory params) { + depositOpensAtTimestamp = params.depositWindow.opensAt; + depositClosesAtTimestamp = params.depositWindow.closesAt; + redemptionOpensAtTimestamp = params.redemptionWindow.opensAt; + redemptionClosesAtTimestamp = params.redemptionWindow.closesAt; + checkWindow = true; + } + + /// @notice Check if a given timestamp is with in a window + /// @dev NOTE (JL,2024-07-01): Could we call this '_assertWindow' instead? + function _checkIsWithinWindow(uint256 windowOpensAt, uint256 windowClosesAt) internal view { + if (checkWindow && (block.timestamp < windowOpensAt || block.timestamp > windowClosesAt)) { + revert CredbullVault__OperationOutsideRequiredWindow(windowOpensAt, windowClosesAt, block.timestamp); + } + } + + /// @notice Check for deposit window + function _checkIsDepositWithinWindow() internal view virtual { + _checkIsWithinWindow(depositOpensAtTimestamp, depositClosesAtTimestamp); + } + + /// @notice Check for redemption window + function _checkIsRedeemWithinWindow() internal view virtual { + _checkIsWithinWindow(redemptionOpensAtTimestamp, redemptionClosesAtTimestamp); + } + + /// @notice - Function to update all timestamps + /// @dev NOTE (JL,2024-07-01): Why does this not use 2x `Window` instances or a `WindowPluginParams`? + /// That is their purpose. + function _updateWindow(uint256 _depositOpen, uint256 _depositClose, uint256 _redeemOpen, uint256 _redeemClose) + internal + virtual + { + depositOpensAtTimestamp = _depositOpen; + depositClosesAtTimestamp = _depositClose; + redemptionOpensAtTimestamp = _redeemOpen; + redemptionClosesAtTimestamp = _redeemClose; + } + + /// @notice - Function to toggle check for window + function _toggleWindowCheck(bool status) internal { + checkWindow = status; + } +} diff --git a/packages/contracts/src/plugins/WhitelistPlugIn.sol b/packages/contracts/src/plugins/WhitelistPlugIn.sol deleted file mode 100644 index 222cdd144..000000000 --- a/packages/contracts/src/plugins/WhitelistPlugIn.sol +++ /dev/null @@ -1,53 +0,0 @@ -//SPDX-License-Identifier: MIT - -pragma solidity ^0.8.19; - -import { IKYCProvider } from "../interface/IKYCProvider.sol"; - -/// @notice - A PlugIn to handle whitelisting -abstract contract WhitelistPlugIn { - /// @notice If an invalid `IKYCProvider` Address is provided. - error CredbullVault__InvalidKYCProviderAddress(address); - /// @notice Error to revert if the address is not whitelisted - error CredbullVault__NotAWhitelistedAddress(address, uint256); - - /// @notice - Parameters for the Whitelist PlugIn - struct KycParams { - address kycProvider; - uint256 depositThresholdForWhitelisting; - } - - /// @notice - Address of the Kyc provider - IKYCProvider public kycProvider; - - /// @notice - Flag to check for whitelist - bool public checkWhitelist; - - /// @notice - Deposit threshold amount to check for whitelisting - uint256 public depositThresholdForWhitelisting; - - /** - * @param _kycProvider - Address of the Kyc Provider - */ - constructor(address _kycProvider, uint256 _depositThresholdForWhitelisting) { - if (_kycProvider == address(0)) { - revert CredbullVault__InvalidKYCProviderAddress(_kycProvider); - } - - kycProvider = IKYCProvider(_kycProvider); - checkWhitelist = true; // Set the check to true by default - depositThresholdForWhitelisting = _depositThresholdForWhitelisting; - } - - /// @notice - Function to check for whitelisted address - function _checkIsWhitelisted(address receiver, uint256 amount) internal view virtual { - if (checkWhitelist && amount >= depositThresholdForWhitelisting && !kycProvider.status(receiver)) { - revert CredbullVault__NotAWhitelistedAddress(receiver, amount); - } - } - - /// @notice - Function to toggle check for whitelisted address - function _toggleWhitelistCheck(bool status) internal virtual { - checkWhitelist = status; - } -} diff --git a/packages/contracts/src/plugins/WindowPlugIn.sol b/packages/contracts/src/plugins/WindowPlugIn.sol deleted file mode 100644 index 10211f95d..000000000 --- a/packages/contracts/src/plugins/WindowPlugIn.sol +++ /dev/null @@ -1,102 +0,0 @@ -//SPDX-License-Identifier: MIT - -pragma solidity ^0.8.19; - -/// @notice - A plugIn to handle deposit and withdraw window -abstract contract WindowPlugIn { - //Error to revert when operation is outside required window - error CredbullVault__OperationOutsideRequiredWindow( - uint256 windowOpensAt, uint256 windowClosesAt, uint256 timestamp - ); - - /// @notice - Struct for window parameters - struct WindowParams { - uint256 opensAt; - uint256 closesAt; - } - - /// @notice - Struct to hold window parameters - struct WindowVaultParams { - WindowParams depositWindow; - WindowParams matureWindow; - } - - /** - * @dev - * The timestamp when the vault opens for deposit. - */ - uint256 public depositOpensAtTimestamp; - - /** - * @dev - * The timestamp when the vault closes for deposit. - */ - uint256 public depositClosesAtTimestamp; - - /** - * @dev - * The timestamp when the vault opens for redemption. - */ - uint256 public redemptionOpensAtTimestamp; - - /** - * @dev - * The timestamp when the vault closes for redemption. - */ - uint256 public redemptionClosesAtTimestamp; - - /// @notice - Flag to check for window - bool public checkWindow; - - /** - * @param _depositOpensAt - Deposit open Unix timestamp - * @param _depositClosesAt - Deposit close Unix timestamp - * @param _redemptionOpensAt - Redemption open Unix timestamp - * @param _redemptionClosesAt - Redemption close Unix timestamp - */ - constructor( - uint256 _depositOpensAt, - uint256 _depositClosesAt, - uint256 _redemptionOpensAt, - uint256 _redemptionClosesAt - ) { - depositOpensAtTimestamp = _depositOpensAt; - depositClosesAtTimestamp = _depositClosesAt; - redemptionOpensAtTimestamp = _redemptionOpensAt; - redemptionClosesAtTimestamp = _redemptionClosesAt; - checkWindow = true; - } - - /// @notice - Check if a given timestamp is with in a window - function _checkIsWithinWindow(uint256 windowOpensAt, uint256 windowClosesAt) internal view { - if (checkWindow && (block.timestamp < windowOpensAt || block.timestamp > windowClosesAt)) { - revert CredbullVault__OperationOutsideRequiredWindow(windowOpensAt, windowClosesAt, block.timestamp); - } - } - - /// @notice - Check for deposit window - function _checkIsDepositWithinWindow() internal view virtual { - _checkIsWithinWindow(depositOpensAtTimestamp, depositClosesAtTimestamp); - } - - /// @notice Check for withdraw window - function _checkIsWithdrawWithinWindow() internal view virtual { - _checkIsWithinWindow(redemptionOpensAtTimestamp, redemptionClosesAtTimestamp); - } - - /// @notice - Function to update all timestamps - function _updateWindow(uint256 _depositOpen, uint256 _depositClose, uint256 _withdrawOpen, uint256 _withdrawClose) - internal - virtual - { - depositOpensAtTimestamp = _depositOpen; - depositClosesAtTimestamp = _depositClose; - redemptionOpensAtTimestamp = _withdrawOpen; - redemptionClosesAtTimestamp = _withdrawClose; - } - - /// @notice - Function to toggle check for window - function _toggleWindowCheck(bool status) internal { - checkWindow = status; - } -} diff --git a/packages/contracts/src/interface/IKYCProvider.sol b/packages/contracts/src/provider/whiteList/IWhiteListProvider.sol similarity index 87% rename from packages/contracts/src/interface/IKYCProvider.sol rename to packages/contracts/src/provider/whiteList/IWhiteListProvider.sol index 017bcabe9..64d505c7c 100644 --- a/packages/contracts/src/interface/IKYCProvider.sol +++ b/packages/contracts/src/provider/whiteList/IWhiteListProvider.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -interface IKYCProvider { +interface IWhiteListProvider { function status(address receiver) external view returns (bool); function updateStatus(address[] calldata _addresses, bool[] calldata _statuses) external; diff --git a/packages/contracts/src/CredbullKYCProvider.sol b/packages/contracts/src/provider/whiteList/WhiteListProvider.sol similarity index 68% rename from packages/contracts/src/CredbullKYCProvider.sol rename to packages/contracts/src/provider/whiteList/WhiteListProvider.sol index 48e08a721..702b1d791 100755 --- a/packages/contracts/src/CredbullKYCProvider.sol +++ b/packages/contracts/src/provider/whiteList/WhiteListProvider.sol @@ -2,24 +2,24 @@ pragma solidity ^0.8.19; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; -import { IKYCProvider } from "./interface/IKYCProvider.sol"; +import { IWhiteListProvider } from "./IWhiteListProvider.sol"; -contract CredbullKYCProvider is IKYCProvider, Ownable { +contract WhiteListProvider is IWhiteListProvider, Ownable { error LengthMismatch(); /** - * @notice - Track whitelisted addresses + * @notice - Track whiteListed addresses */ - mapping(address => bool) public isWhitelisted; + mapping(address => bool) public isWhiteListed; constructor(address _owner) Ownable(_owner) { } function status(address receiver) public view override returns (bool) { - return isWhitelisted[receiver]; + return isWhiteListed[receiver]; } /** - * @notice - Method to update the whitelist status of an address called only by the owner. + * @notice - Method to update the whiteList status of an address called only by the owner. * * @param _addresses - List of addresses value * @param _statuses - List of statuses to update @@ -30,7 +30,7 @@ contract CredbullKYCProvider is IKYCProvider, Ownable { uint256 length = _addresses.length; for (uint256 i; i < length;) { - isWhitelisted[_addresses[i]] = _statuses[i]; + isWhiteListed[_addresses[i]] = _statuses[i]; unchecked { ++i; diff --git a/packages/contracts/src/vaults/FixedYieldVault.sol b/packages/contracts/src/vault/FixedYieldVault.sol similarity index 54% rename from packages/contracts/src/vaults/FixedYieldVault.sol rename to packages/contracts/src/vault/FixedYieldVault.sol index 9af9640ef..b64b20add 100644 --- a/packages/contracts/src/vaults/FixedYieldVault.sol +++ b/packages/contracts/src/vault/FixedYieldVault.sol @@ -3,44 +3,55 @@ pragma solidity ^0.8.19; import { AccessControl } from "@openzeppelin/contracts/access/AccessControl.sol"; -import { MaturityVault } from "../extensions/MaturityVault.sol"; -import { WhitelistPlugIn } from "../plugins/WhitelistPlugIn.sol"; -import { WindowPlugIn } from "../plugins/WindowPlugIn.sol"; -import { MaxCapPlugIn } from "../plugins/MaxCapPlugIn.sol"; +import { Math } from "openzeppelin-contracts/contracts/utils/math/Math.sol"; + +import { MaturityVault } from "./MaturityVault.sol"; +import { WhiteListPlugin } from "../plugin/WhiteListPlugin.sol"; +import { WindowPlugin } from "../plugin/WindowPlugin.sol"; +import { MaxCapPlugin } from "../plugin/MaxCapPlugin.sol"; + +contract FixedYieldVault is MaturityVault, WhiteListPlugin, WindowPlugin, MaxCapPlugin, AccessControl { + using Math for uint256; -contract FixedYieldVault is MaturityVault, WhitelistPlugIn, WindowPlugIn, MaxCapPlugIn, AccessControl { /// @notice - Hash of operator role bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE"); + struct ContractRoles { + address owner; + address operator; + address custodian; + } + struct FixedYieldVaultParams { - MaturityVaultParams maturityVaultParams; - ContractRoles contractRoles; - WindowVaultParams windowVaultParams; - KycParams kycParams; - MaxCapParams maxCapParams; + MaturityVaultParams maturityVault; + ContractRoles roles; + WindowPluginParams windowPlugin; + WhiteListPluginParams whiteListPlugin; + MaxCapPluginParams maxCapPlugin; + uint256 promisedYield; } + /// @dev The fixed yield value in percentage(100) that's promised to the users on deposit. + uint256 private _fixedYield; + constructor(FixedYieldVaultParams memory params) - MaturityVault(params.maturityVaultParams) - WhitelistPlugIn(params.kycParams.kycProvider, params.kycParams.depositThresholdForWhitelisting) - MaxCapPlugIn(params.maxCapParams.maxCap) - WindowPlugIn( - params.windowVaultParams.depositWindow.opensAt, - params.windowVaultParams.depositWindow.closesAt, - params.windowVaultParams.matureWindow.opensAt, - params.windowVaultParams.matureWindow.closesAt - ) + MaturityVault(params.maturityVault) + WhiteListPlugin(params.whiteListPlugin) + WindowPlugin(params.windowPlugin) + MaxCapPlugin(params.maxCapPlugin) { - _grantRole(DEFAULT_ADMIN_ROLE, params.contractRoles.owner); - _grantRole(OPERATOR_ROLE, params.contractRoles.operator); + _grantRole(DEFAULT_ADMIN_ROLE, params.roles.owner); + _grantRole(OPERATOR_ROLE, params.roles.operator); + + _fixedYield = params.promisedYield; } /// @dev - Overridden deposit modifer - /// Should check for whitelisted address + /// Should check for whiteListed address /// Should check for deposit window /// Should check for max cap - modifier depositModifier(address caller, address receiver, uint256 assets, uint256 shares) override { - _checkIsWhitelisted(receiver, assets + convertToAssets(balanceOf(receiver))); + modifier onDepositOrMint(address caller, address receiver, uint256 assets, uint256 shares) override { + _checkIsWhiteListed(receiver, assets + convertToAssets(balanceOf(receiver))); _checkIsDepositWithinWindow(); _checkMaxCap(totalAssetDeposited + assets); _; @@ -49,14 +60,19 @@ contract FixedYieldVault is MaturityVault, WhitelistPlugIn, WindowPlugIn, MaxCap /// @dev - Overridden withdraw modifier /// Should check for withdraw window /// Should check for maturity - modifier withdrawModifier(address caller, address receiver, address owner, uint256 assets, uint256 shares) + modifier onWithdrawOrRedeem(address caller, address receiver, address owner, uint256 assets, uint256 shares) override { - _checkIsWithdrawWithinWindow(); + _checkIsRedeemWithinWindow(); _checkVaultMaturity(); _; } + // @notice - Returns expected assets on maturity + function expectedAssetsOnMaturity() public view override returns (uint256) { + return totalAssetDeposited.mulDiv(100 + _fixedYield, 100); + } + /// @notice Mature the vault function mature() public override onlyRole(OPERATOR_ROLE) { _mature(); @@ -67,9 +83,9 @@ contract FixedYieldVault is MaturityVault, WhitelistPlugIn, WindowPlugIn, MaxCap _toggleMaturityCheck(status); } - /// @notice Toggle check for whitelist - function toggleWhitelistCheck(bool status) public onlyRole(DEFAULT_ADMIN_ROLE) { - _toggleWhitelistCheck(status); + /// @notice Toggle check for whiteList + function toggleWhiteListCheck(bool status) public onlyRole(DEFAULT_ADMIN_ROLE) { + _toggleWhiteListCheck(status); } /// @notice Toggle check for window diff --git a/packages/contracts/src/extensions/MaturityVault.sol b/packages/contracts/src/vault/MaturityVault.sol similarity index 74% rename from packages/contracts/src/extensions/MaturityVault.sol rename to packages/contracts/src/vault/MaturityVault.sol index c90f30d50..ce4d8d5d4 100644 --- a/packages/contracts/src/extensions/MaturityVault.sol +++ b/packages/contracts/src/vault/MaturityVault.sol @@ -3,15 +3,18 @@ pragma solidity ^0.8.19; import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol"; -import { Math } from "openzeppelin-contracts/contracts/utils/math/Math.sol"; -import { CredbullBaseVault } from "../base/CredbullBaseVault.sol"; - -abstract contract MaturityVault is CredbullBaseVault { - using Math for uint256; - +import { Vault } from "./Vault.sol"; + +/** + * @title A Credbull Vault with Maturity properties. + * @author @pasviegas + * @notice Once matured, such a vault will not accept further deposits. + */ +abstract contract MaturityVault is Vault { + /// @notice The set of parameters for creating a [MaturityVault].abi + /// @dev Though unnecessary, we maintain the implementation pattern of a 'Params' per Vault. struct MaturityVaultParams { - BaseVaultParams baseVaultParams; - uint256 promisedYield; + VaultParams vault; } /// @notice Reverts on withdraw if vault is not matured. @@ -26,17 +29,8 @@ abstract contract MaturityVault is CredbullBaseVault { /// @notice Determine if Maturity Checking is enabled or disabled. bool public checkMaturity; - /// @dev The fixed yield value in percentage(100) that's promised to the users on deposit. - uint256 private _fixedYield; - - constructor(MaturityVaultParams memory params) CredbullBaseVault(params.baseVaultParams) { + constructor(MaturityVaultParams memory params) Vault(params.vault) { checkMaturity = true; - _fixedYield = params.promisedYield; - } - - /// @notice - Returns expected assets on maturity - function expectedAssetsOnMaturity() public view returns (uint256) { - return totalAssetDeposited.mulDiv(100 + _fixedYield, 100); } /** @@ -56,6 +50,11 @@ abstract contract MaturityVault is CredbullBaseVault { isMatured = true; } + /// @notice - Returns expected assets on maturity + function expectedAssetsOnMaturity() public view virtual returns (uint256) { + return totalAssetDeposited; + } + /// @dev - To be access controlled on inherited contract function mature() public virtual { _mature(); diff --git a/packages/contracts/src/vaults/UpsideVault.sol b/packages/contracts/src/vault/UpsideVault.sol similarity index 92% rename from packages/contracts/src/vaults/UpsideVault.sol rename to packages/contracts/src/vault/UpsideVault.sol index b0fa74edc..37b191146 100644 --- a/packages/contracts/src/vaults/UpsideVault.sol +++ b/packages/contracts/src/vault/UpsideVault.sol @@ -12,7 +12,7 @@ contract UpsideVault is FixedYieldVault { error CredbullVault__InsufficientShareBalance(); struct UpsideVaultParams { - FixedYieldVaultParams fixedYieldVaultParams; + FixedYieldVaultParams fixedYieldVault; IERC20 cblToken; uint256 collateralPercentage; } @@ -39,12 +39,11 @@ contract UpsideVault is FixedYieldVault { /// @notice Additional precision required for math uint256 private additionalPrecision; - constructor(UpsideVaultParams memory params) FixedYieldVault(params.fixedYieldVaultParams) { + constructor(UpsideVaultParams memory params) FixedYieldVault(params.fixedYieldVault) { collateralPercentage = params.collateralPercentage; token = params.cblToken; - uint8 assetDecimal = - _checkValidDecimalValue(address(params.fixedYieldVaultParams.maturityVaultParams.baseVaultParams.asset)); + uint8 assetDecimal = _checkValidDecimalValue(address(params.fixedYieldVault.maturityVault.vault.asset)); uint8 tokenDecimal = _checkValidDecimalValue(address(params.cblToken)); if (tokenDecimal >= assetDecimal) { @@ -58,7 +57,7 @@ contract UpsideVault is FixedYieldVault { function _deposit(address caller, address receiver, uint256 assets, uint256 shares) internal override - depositModifier(caller, receiver, assets, shares) + onDepositOrMint(caller, receiver, assets, shares) whenNotPaused { (, uint256 reminder) = assets.tryMod(10 ** VAULT_DECIMALS); @@ -87,7 +86,7 @@ contract UpsideVault is FixedYieldVault { function _withdraw(address caller, address receiver, address owner, uint256 assets, uint256 shares) internal override - withdrawModifier(caller, receiver, owner, assets, shares) + onWithdrawOrRedeem(caller, receiver, owner, assets, shares) whenNotPaused { if (caller != owner) { diff --git a/packages/contracts/src/base/CredbullBaseVault.sol b/packages/contracts/src/vault/Vault.sol similarity index 76% rename from packages/contracts/src/base/CredbullBaseVault.sol rename to packages/contracts/src/vault/Vault.sol index ca09ffce1..63af9622c 100644 --- a/packages/contracts/src/base/CredbullBaseVault.sol +++ b/packages/contracts/src/vault/Vault.sol @@ -9,30 +9,31 @@ import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.s import { Math } from "openzeppelin-contracts/contracts/utils/math/Math.sol"; import { Pausable } from "@openzeppelin/contracts/utils/Pausable.sol"; -abstract contract CredbullBaseVault is ERC4626, Pausable { +/** + * @title Credbull Vault + * @notice The family defining contract, based upon Open Zeppelin's ERC4626 implementation. + * @dev Uses a Custodian Account to accummulate the deposited Asset. + */ +abstract contract Vault is ERC4626, Pausable { using Math for uint256; + /// @notice Thrown when attempting to create a Credbull Vault with an invalid Custodian Address. error CredbullVault__InvalidCustodianAddress(address); + /// @notice Thrown when attempting to create a Credbull Vault with a non-addressable Asset IERC20. error CredbullVault__InvalidAsset(IERC20); error CredbullVault__TransferOutsideEcosystem(address); error CredbullVault__InvalidAssetAmount(uint256); error CredbullVault__UnsupportedDecimalValue(uint8); error CredbullVault__NativeTransferNotAllowed(); - /// @notice Struct for Parameters required to create a base vault - struct BaseVaultParams { + /// @notice The set of parameters required to create a Credbull Vault instance. + struct VaultParams { IERC20 asset; string shareName; string shareSymbol; address custodian; } - struct ContractRoles { - address owner; - address operator; - address custodian; - } - /// @notice Address of the CUSTODIAN to receive the assets on deposit and mint address public immutable CUSTODIAN; @@ -51,35 +52,29 @@ abstract contract CredbullBaseVault is ERC4626, Pausable { /// @notice Min decimal value supported by vault uint8 public constant MIN_DECIMAL = 6; - /// @notice Modifier to add additional checks on deposit - modifier depositModifier(address caller, address receiver, uint256 assets, uint256 shares) virtual { + /// @notice Modifier to add additional checks on _deposit, the deposit/mint common workflow function. + modifier onDepositOrMint(address caller, address receiver, uint256 assets, uint256 shares) virtual { _; } - /// @notice Modifier to add additional checks on withdraw - modifier withdrawModifier(address caller, address receiver, address owner, uint256 assets, uint256 shares) + /// @notice Modifier to add additional checks on _withdraw, the withdraw/redeem common workflow function. + modifier onWithdrawOrRedeem(address caller, address receiver, address owner, uint256 assets, uint256 shares) virtual { _; } - /** - * @param baseVaultParams - Base vault parameters - */ - constructor(BaseVaultParams memory baseVaultParams) - ERC4626(baseVaultParams.asset) - ERC20(baseVaultParams.shareName, baseVaultParams.shareSymbol) - { - if (baseVaultParams.custodian == address(0)) { - revert CredbullVault__InvalidCustodianAddress(baseVaultParams.custodian); + constructor(VaultParams memory params) ERC4626(params.asset) ERC20(params.shareName, params.shareSymbol) { + if (params.custodian == address(0)) { + revert CredbullVault__InvalidCustodianAddress(params.custodian); } - if (address(baseVaultParams.asset) == address(0)) { - revert CredbullVault__InvalidAsset(baseVaultParams.asset); + if (address(params.asset) == address(0)) { + revert CredbullVault__InvalidAsset(params.asset); } - CUSTODIAN = baseVaultParams.custodian; + CUSTODIAN = params.custodian; - VAULT_DECIMALS = _checkValidDecimalValue(address(baseVaultParams.asset)); + VAULT_DECIMALS = _checkValidDecimalValue(address(params.asset)); } /** @@ -90,7 +85,7 @@ abstract contract CredbullBaseVault is ERC4626, Pausable { internal virtual override - depositModifier(caller, receiver, assets, shares) + onDepositOrMint(caller, receiver, assets, shares) whenNotPaused { (, uint256 reminder) = assets.tryMod(10 ** VAULT_DECIMALS); @@ -113,7 +108,7 @@ abstract contract CredbullBaseVault is ERC4626, Pausable { internal virtual override - withdrawModifier(caller, receiver, owner, assets, shares) + onWithdrawOrRedeem(caller, receiver, owner, assets, shares) whenNotPaused { if (caller != owner) { @@ -170,12 +165,12 @@ abstract contract CredbullBaseVault is ERC4626, Pausable { /// @notice Revert any ETH transfer to contract receive() external payable { - revert("Native transfer not allowed"); + revert CredbullVault__NativeTransferNotAllowed(); } /// @notice Revert any ETH transfer to contract fallback() external payable { - revert("Native transfer not allowed"); + revert CredbullVault__NativeTransferNotAllowed(); } /// @notice Withdraw any ERC20 tokens sent directly to contract. diff --git a/packages/contracts/test/CredbullKYCProviderTest.sol b/packages/contracts/test/CredbullKYCProviderTest.sol deleted file mode 100644 index 04f1860f4..000000000 --- a/packages/contracts/test/CredbullKYCProviderTest.sol +++ /dev/null @@ -1,34 +0,0 @@ -//SPDX-License-Identifier: MIT - -pragma solidity ^0.8.19; - -import { Test } from "forge-std/Test.sol"; -import { CredbullKYCProvider } from "../src/CredbullKYCProvider.sol"; - -contract CredbullKYCProviderTest is Test { - CredbullKYCProvider private kycProvider; - address private owner = makeAddr("owner"); - address private alice = makeAddr("alice"); - - function setUp() public { - kycProvider = new CredbullKYCProvider(owner); - } - - function test__SuccessfullyDeployKYCProvider() public { - kycProvider = new CredbullKYCProvider(owner); - assertEq(kycProvider.owner(), owner); - } - - function test__UpsideVault__RevertKYCProviderUpdateStatusIfLengthMismatch() public { - address[] memory whitelistAddresses = new address[](1); - whitelistAddresses[0] = alice; - - bool[] memory statuses = new bool[](2); - statuses[0] = true; - statuses[1] = true; - - vm.prank(owner); - vm.expectRevert(abi.encodeWithSelector(CredbullKYCProvider.LengthMismatch.selector)); - kycProvider.updateStatus(whitelistAddresses, statuses); - } -} diff --git a/packages/contracts/test/base/HelperVaultTest.t.sol b/packages/contracts/test/base/HelperVaultTest.t.sol deleted file mode 100644 index 3438a3608..000000000 --- a/packages/contracts/test/base/HelperVaultTest.t.sol +++ /dev/null @@ -1,100 +0,0 @@ -//SPDX-License-Identifier: MIT - -pragma solidity ^0.8.19; - -import { Test } from "forge-std/Test.sol"; -import { NetworkConfig } from "../../script/HelperConfig.s.sol"; -import { CredbullBaseVault } from "../mocks/vaults/CredbullBaseVaultMock.m.sol"; -import { CredbullFixedYieldVaultWithUpside } from "../../src/CredbullFixedYieldVaultWithUpside.sol"; -import { CredbullFixedYieldVault } from "../../src/CredbullFixedYieldVault.sol"; -import { MaxCapPlugIn } from "../../src/plugins/MaxCapPlugIn.sol"; -import { WhitelistPlugIn } from "../../src/plugins/WhitelistPlugIn.sol"; -import { WindowPlugIn } from "../../src/plugins/WindowPlugIn.sol"; -import { UpsideVault } from "../../src/vaults/UpsideVault.sol"; -import { FixedYieldVault } from "../../src/vaults/FixedYieldVault.sol"; -import { MaturityVault } from "../../src/extensions/MaturityVault.sol"; - -/// Utility to help with testing vaults -contract HelperVaultTest is Test { - uint256 private constant PROMISED_FIXED_YIELD = 10; - NetworkConfig private networkConfig; - - constructor(NetworkConfig memory _networkConfig) { - networkConfig = _networkConfig; - } - - function createBaseVaultTestParams() public returns (CredbullBaseVault.BaseVaultParams memory params) { - address custodian = makeAddr("custodianAddress"); - - params = CredbullBaseVault.BaseVaultParams({ - asset: networkConfig.usdcToken, - shareName: "Share_sep", - shareSymbol: "SYM_sep", - custodian: custodian - }); - } - - function createFixedYieldWithUpsideVaultParams() - public - returns (CredbullFixedYieldVaultWithUpside.UpsideVaultParams memory params) - { - params = UpsideVault.UpsideVaultParams({ - fixedYieldVaultParams: createFixedYieldVaultParams(), - cblToken: networkConfig.cblToken, - collateralPercentage: 20_00 - }); - } - - function createFixedYieldVaultParams() - public - returns (CredbullFixedYieldVault.FixedYieldVaultParams memory params) - { - params = FixedYieldVault.FixedYieldVaultParams({ - maturityVaultParams: createMaturityVaultTestParams(), - contractRoles: createContractRoles(), - windowVaultParams: createWindowVaultParams(), - kycParams: createKycParams(), - maxCapParams: createMaxCapParams() - }); - } - - function createMaturityVaultTestParams() public returns (MaturityVault.MaturityVaultParams memory params) { - params = MaturityVault.MaturityVaultParams({ - baseVaultParams: createBaseVaultTestParams(), - promisedYield: PROMISED_FIXED_YIELD - }); - } - - function createMaxCapParams() public pure returns (MaxCapPlugIn.MaxCapParams memory params) { - params = MaxCapPlugIn.MaxCapParams({ maxCap: 1e6 * 1e6 }); - } - - function createKycParams() public returns (WhitelistPlugIn.KycParams memory params) { - params = WhitelistPlugIn.KycParams({ - kycProvider: makeAddr("kycProviderAddress"), - depositThresholdForWhitelisting: 1000e6 - }); - } - - function createWindowVaultParams() public view returns (WindowPlugIn.WindowVaultParams memory params) { - uint256 opensAt = block.timestamp; - uint256 closesAt = opensAt + 7 days; - uint256 year = 365 days; - - WindowPlugIn.WindowParams memory depositWindow = - WindowPlugIn.WindowParams({ opensAt: opensAt, closesAt: closesAt }); - - WindowPlugIn.WindowParams memory matureWindow = - WindowPlugIn.WindowParams({ opensAt: opensAt + year, closesAt: closesAt + year }); - - params = WindowPlugIn.WindowVaultParams({ depositWindow: depositWindow, matureWindow: matureWindow }); - } - - function createContractRoles() public returns (CredbullBaseVault.ContractRoles memory roles) { - roles = CredbullBaseVault.ContractRoles({ - owner: networkConfig.factoryParams.owner, - operator: networkConfig.factoryParams.operator, - custodian: makeAddr("custodianAddress") - }); - } -} diff --git a/packages/contracts/test/factories/CredbullUpsideVaultFactory.t.sol b/packages/contracts/test/factories/CredbullUpsideVaultFactory.t.sol deleted file mode 100644 index a15cc5aad..000000000 --- a/packages/contracts/test/factories/CredbullUpsideVaultFactory.t.sol +++ /dev/null @@ -1,56 +0,0 @@ -//SPDX-License-Identifier: MIT - -pragma solidity ^0.8.19; - -import { Test } from "forge-std/Test.sol"; - -import { HelperVaultTest } from "../base/HelperVaultTest.t.sol"; -import { CredbullUpsideVaultFactory } from "../../src/factories/CredbullUpsideVaultFactory.sol"; -import { DeployVaultFactory } from "../../script/DeployVaultFactory.s.sol"; -import { HelperConfig, NetworkConfig } from "../../script/HelperConfig.s.sol"; -import { CredbullFixedYieldVaultWithUpside } from "../../src/CredbullFixedYieldVaultWithUpside.sol"; -import { CredbullKYCProvider } from "../../src/CredbullKYCProvider.sol"; - -contract CredbullVaultWithUpsideFactoryTest is Test { - CredbullUpsideVaultFactory private factory; - DeployVaultFactory private deployer; - HelperConfig private helperConfig; - CredbullKYCProvider private kycProvider; - - string private OPTIONS = "{}"; - - function setUp() public { - deployer = new DeployVaultFactory(); - (, factory, kycProvider, helperConfig) = deployer.runTest(); - } - - function test__ShouldSuccefullyCreateFactoryUpside() public { - NetworkConfig memory config = helperConfig.getNetworkConfig(); - address[] memory custodians = new address[](1); - custodians[0] = config.factoryParams.custodian; - CredbullUpsideVaultFactory vaultFactory = - new CredbullUpsideVaultFactory(config.factoryParams.owner, config.factoryParams.operator, custodians); - vaultFactory.hasRole(vaultFactory.OPERATOR_ROLE(), config.factoryParams.operator); - } - - function test__CreateUpsideVaultFromFactory() public { - NetworkConfig memory config = helperConfig.getNetworkConfig(); - (CredbullFixedYieldVaultWithUpside.UpsideVaultParams memory params) = - new HelperVaultTest(config).createFixedYieldWithUpsideVaultParams(); - - params.fixedYieldVaultParams.kycParams.kycProvider = address(kycProvider); - - vm.prank(config.factoryParams.owner); - factory.allowCustodian(params.fixedYieldVaultParams.maturityVaultParams.baseVaultParams.custodian); - - vm.prank(config.factoryParams.operator); - CredbullFixedYieldVaultWithUpside vault = - CredbullFixedYieldVaultWithUpside(payable(factory.createVault(params, OPTIONS))); - - assertEq(vault.asset(), address(params.fixedYieldVaultParams.maturityVaultParams.baseVaultParams.asset)); - assertEq(vault.name(), params.fixedYieldVaultParams.maturityVaultParams.baseVaultParams.shareName); - assertEq(vault.symbol(), params.fixedYieldVaultParams.maturityVaultParams.baseVaultParams.shareSymbol); - assertEq(address(vault.kycProvider()), params.fixedYieldVaultParams.kycParams.kycProvider); - assertEq(vault.CUSTODIAN(), params.fixedYieldVaultParams.maturityVaultParams.baseVaultParams.custodian); - } -} diff --git a/packages/contracts/test/mocks/MockDecimalToken.sol b/packages/contracts/test/mocks/MockDecimalToken.sol deleted file mode 100644 index b1176295b..000000000 --- a/packages/contracts/test/mocks/MockDecimalToken.sol +++ /dev/null @@ -1,17 +0,0 @@ -// SDPX-License-Identifier: MIT - -pragma solidity ^0.8.19; - -import { MockToken } from "./MockToken.sol"; - -contract MockDecimalToken is MockToken { - uint8 private tokenDecimals; - - constructor(uint256 initialSupply, uint8 _decimals) MockToken(initialSupply) { - tokenDecimals = _decimals; - } - - function decimals() public view override returns (uint8) { - return tokenDecimals; - } -} diff --git a/packages/contracts/test/mocks/MockStablecoin.sol b/packages/contracts/test/mocks/MockStablecoin.sol deleted file mode 100755 index b75659dc6..000000000 --- a/packages/contracts/test/mocks/MockStablecoin.sol +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.19; - -import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; -import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; - -//Mock stablecoin -contract MockStablecoin is ERC20, Ownable { - constructor(uint256 initialSupply) ERC20("Mock USDC", "mUSDC") Ownable(msg.sender) { - _mint(msg.sender, initialSupply); - } - - function mint(address to, uint256 amount) public { - _mint(to, amount); - } - - function decimals() public pure override returns (uint8) { - return 6; - } -} diff --git a/packages/contracts/test/mocks/MockToken.sol b/packages/contracts/test/mocks/MockToken.sol deleted file mode 100755 index 37ad8ef28..000000000 --- a/packages/contracts/test/mocks/MockToken.sol +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.19; - -import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; -import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; - -contract MockToken is ERC20, Ownable { - constructor(uint256 initialSupply) ERC20("Mock Token", "mToken") Ownable(msg.sender) { - _mint(msg.sender, initialSupply); - } - - function mint(address to, uint256 amount) public { - _mint(to, amount); - } -} diff --git a/packages/contracts/test/mocks/vaults/CredbullBaseVaultMock.m.sol b/packages/contracts/test/mocks/vaults/CredbullBaseVaultMock.m.sol deleted file mode 100644 index 4e0f6a302..000000000 --- a/packages/contracts/test/mocks/vaults/CredbullBaseVaultMock.m.sol +++ /dev/null @@ -1,25 +0,0 @@ -//SPDX-License-Identifier: MIT - -pragma solidity ^0.8.19; - -import { CredbullBaseVault } from "../../../src/base/CredbullBaseVault.sol"; -import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol"; - -contract CredbullBaseVaultMock is CredbullBaseVault { - constructor(IERC20 asset, string memory shareName, string memory shareSymbol, address custodian) - CredbullBaseVault(createBaseVaultParams(asset, shareName, shareSymbol, custodian)) - { } - - function createBaseVaultParams(IERC20 asset, string memory shareName, string memory shareSymbol, address custodian) - internal - pure - returns (BaseVaultParams memory vaultParams) - { - vaultParams = - BaseVaultParams({ asset: asset, shareName: shareName, shareSymbol: shareSymbol, custodian: custodian }); - } - - function withdrawERC20(address[] calldata _tokens, address _to) external { - _withdrawERC20(_tokens, _to); - } -} diff --git a/packages/contracts/test/mocks/vaults/MaturityVaultMock.m.sol b/packages/contracts/test/mocks/vaults/MaturityVaultMock.m.sol deleted file mode 100644 index 41cd8a30a..000000000 --- a/packages/contracts/test/mocks/vaults/MaturityVaultMock.m.sol +++ /dev/null @@ -1,22 +0,0 @@ -//SPDX-License-Identifier: MIT - -pragma solidity ^0.8.19; - -import { MaturityVault } from "../../../src/extensions/MaturityVault.sol"; -import { FixedYieldVault } from "../../../src/vaults/FixedYieldVault.sol"; -import { MaturityVault } from "../../../src/extensions/MaturityVault.sol"; - -contract MaturityVaultMock is MaturityVault { - constructor(MaturityVault.MaturityVaultParams memory params) MaturityVault(params) { } - - modifier withdrawModifier(address caller, address receiver, address owner, uint256 assets, uint256 shares) - override - { - _checkVaultMaturity(); - _; - } - - function toogleMaturityCheck(bool status) public { - _toggleMaturityCheck(status); - } -} diff --git a/packages/contracts/test/mocks/vaults/MaxCapVaultMock.m.sol b/packages/contracts/test/mocks/vaults/MaxCapVaultMock.m.sol deleted file mode 100644 index b0e3cad2a..000000000 --- a/packages/contracts/test/mocks/vaults/MaxCapVaultMock.m.sol +++ /dev/null @@ -1,28 +0,0 @@ -//SPDX-License-Identifier: MIT - -pragma solidity ^0.8.19; - -import { CredbullBaseVault } from "../../../src/base/CredbullBaseVault.sol"; - -import { MaxCapPlugIn } from "../../../src/plugins/MaxCapPlugIn.sol"; -import { CredbullBaseVault } from "../../../src/base/CredbullBaseVault.sol"; - -contract MaxCapVaultMock is CredbullBaseVault, MaxCapPlugIn { - constructor(CredbullBaseVault.BaseVaultParams memory params, MaxCapPlugIn.MaxCapParams memory maxCapParams) - CredbullBaseVault(params) - MaxCapPlugIn(maxCapParams.maxCap) - { } - - modifier depositModifier(address caller, address receiver, uint256 assets, uint256 shares) override { - _checkMaxCap(totalAssetDeposited + assets); - _; - } - - function toggleMaxCapCheck(bool status) public { - _toggleMaxCapCheck(status); - } - - function updateMaxCap(uint256 _value) public { - _updateMaxCap(_value); - } -} diff --git a/packages/contracts/test/mocks/vaults/WhitelistVaultMock.m.sol b/packages/contracts/test/mocks/vaults/WhitelistVaultMock.m.sol deleted file mode 100644 index aa2fd1c59..000000000 --- a/packages/contracts/test/mocks/vaults/WhitelistVaultMock.m.sol +++ /dev/null @@ -1,22 +0,0 @@ -//SPDX-License-Identifier: MIT - -pragma solidity ^0.8.19; - -import { CredbullBaseVault } from "../../../src/base/CredbullBaseVault.sol"; -import { WhitelistPlugIn } from "../../../src/plugins/WhitelistPlugIn.sol"; - -contract WhitelistVaultMock is CredbullBaseVault, WhitelistPlugIn { - constructor(CredbullBaseVault.BaseVaultParams memory params, WhitelistPlugIn.KycParams memory kycParams) - CredbullBaseVault(params) - WhitelistPlugIn(kycParams.kycProvider, kycParams.depositThresholdForWhitelisting) - { } - - modifier depositModifier(address caller, address receiver, uint256 assets, uint256 shares) override { - _checkIsWhitelisted(receiver, assets); - _; - } - - function toggleWhitelistCheck(bool status) public { - _toggleWhitelistCheck(status); - } -} diff --git a/packages/contracts/test/mocks/vaults/WindowVaultMock.m.sol b/packages/contracts/test/mocks/vaults/WindowVaultMock.m.sol deleted file mode 100644 index a57796720..000000000 --- a/packages/contracts/test/mocks/vaults/WindowVaultMock.m.sol +++ /dev/null @@ -1,40 +0,0 @@ -//SPDX-License-Identifier: MIT - -pragma solidity ^0.8.19; - -import { CredbullBaseVault } from "../../../src/base/CredbullBaseVault.sol"; -import { WindowPlugIn } from "../../../src/plugins/WindowPlugIn.sol"; - -contract WindowVaultMock is CredbullBaseVault, WindowPlugIn { - constructor(CredbullBaseVault.BaseVaultParams memory params, WindowPlugIn.WindowVaultParams memory windowParams) - CredbullBaseVault(params) - WindowPlugIn( - windowParams.depositWindow.opensAt, - windowParams.depositWindow.closesAt, - windowParams.matureWindow.opensAt, - windowParams.matureWindow.closesAt - ) - { } - - modifier depositModifier(address caller, address receiver, uint256 assets, uint256 shares) override { - _checkIsDepositWithinWindow(); - _; - } - - modifier withdrawModifier(address caller, address receiver, address owner, uint256 assets, uint256 shares) - override - { - _checkIsWithdrawWithinWindow(); - _; - } - - function updateWindow(uint256 _depositOpen, uint256 _depositClose, uint256 _withdrawOpen, uint256 _withdrawClose) - public - { - _updateWindow(_depositOpen, _depositClose, _withdrawOpen, _withdrawClose); - } - - function toggleWindowCheck(bool status) public { - _toggleWindowCheck(status); - } -} diff --git a/packages/contracts/test/plugins/WhitelistPlugInTest.t.sol b/packages/contracts/test/plugins/WhitelistPlugInTest.t.sol deleted file mode 100644 index e3119253e..000000000 --- a/packages/contracts/test/plugins/WhitelistPlugInTest.t.sol +++ /dev/null @@ -1,139 +0,0 @@ -//SPDX-License-Identifier: MIT - -pragma solidity ^0.8.19; - -import { Test } from "forge-std/Test.sol"; -import { HelperVaultTest } from "../base/HelperVaultTest.t.sol"; -import { WhitelistVaultMock } from "../mocks/vaults/WhitelistVaultMock.m.sol"; -import { HelperConfig } from "../../script/HelperConfig.s.sol"; -import { MockStablecoin } from "../mocks/MockStablecoin.sol"; -import { WhitelistPlugIn } from "../../src/plugins/WhitelistPlugIn.sol"; -import { DeployVaultFactory } from "../../script/DeployVaultFactory.s.sol"; -import { CredbullKYCProvider } from "../../src/CredbullKYCProvider.sol"; -import { CredbullBaseVault } from "../../src/base/CredbullBaseVault.sol"; - -contract WhitelistPlugInTest is Test { - WhitelistVaultMock private vault; - DeployVaultFactory private deployer; - CredbullKYCProvider private kycProvider; - - CredbullBaseVault.BaseVaultParams private vaultParams; - WhitelistPlugIn.KycParams private kycParams; - HelperConfig private helperConfig; - - address private alice = makeAddr("alice"); - address private bob = makeAddr("bob"); - uint256 private precision; - - uint256 private constant INITIAL_BALANCE = 1e6; - - function setUp() public { - deployer = new DeployVaultFactory(); - (,, kycProvider, helperConfig) = deployer.runTest(); - vaultParams = new HelperVaultTest(helperConfig.getNetworkConfig()).createBaseVaultTestParams(); - kycParams = new HelperVaultTest(helperConfig.getNetworkConfig()).createKycParams(); - kycParams.kycProvider = address(kycProvider); - - vault = new WhitelistVaultMock(vaultParams, kycParams); - precision = 10 ** MockStablecoin(address(vaultParams.asset)).decimals(); - - address[] memory whitelistAddresses = new address[](2); - whitelistAddresses[0] = alice; - whitelistAddresses[1] = bob; - - bool[] memory statuses = new bool[](2); - statuses[0] = true; - statuses[1] = true; - - vm.startPrank(kycProvider.owner()); - vault.kycProvider().updateStatus(whitelistAddresses, statuses); - vm.stopPrank(); - - MockStablecoin(address(vaultParams.asset)).mint(alice, INITIAL_BALANCE * precision); - MockStablecoin(address(vaultParams.asset)).mint(bob, INITIAL_BALANCE * precision); - } - - function test__WhitelistVault__RevertDepositIfReceiverNotWhitelisted() public { - address[] memory whitelistAddresses = new address[](1); - whitelistAddresses[0] = alice; - - bool[] memory statuses = new bool[](1); - statuses[0] = false; - - vm.startPrank(kycProvider.owner()); - vault.kycProvider().updateStatus(whitelistAddresses, statuses); - vm.stopPrank(); - - uint256 depositAmount = 1000 * precision; - - vm.startPrank(alice); - vaultParams.asset.approve(address(vault), depositAmount); - - vm.expectRevert( - abi.encodeWithSelector(WhitelistPlugIn.CredbullVault__NotAWhitelistedAddress.selector, alice, depositAmount) - ); - vault.deposit(depositAmount, alice); - vm.stopPrank(); - } - - function test__WhitelistVault__ShouldSkipCheckIfDepositIsLessThanThreshold() public { - address[] memory whitelistAddresses = new address[](1); - whitelistAddresses[0] = alice; - - bool[] memory statuses = new bool[](1); - statuses[0] = false; - - uint256 depositAmount = 100 * precision; - vm.startPrank(alice); - vaultParams.asset.approve(address(vault), depositAmount); - - vault.deposit(depositAmount, alice); - vm.stopPrank(); - - assertEq(vault.balanceOf(alice), depositAmount); - } - - function test__WhitelistVault__SucessfulDepositOnWhitelistVault() public { - uint256 depositAmount = 1000 * precision; - vm.startPrank(alice); - vaultParams.asset.approve(address(vault), depositAmount); - - vault.deposit(depositAmount, alice); - vm.stopPrank(); - - assertEq(vault.balanceOf(alice), depositAmount); - } - - function test__WhitelistVault__ShouldNotRevertOnWhitelistModifier() public { - address[] memory whitelistAddresses = new address[](1); - whitelistAddresses[0] = alice; - - bool[] memory statuses = new bool[](1); - statuses[0] = false; - - vm.startPrank(kycProvider.owner()); - vault.kycProvider().updateStatus(whitelistAddresses, statuses); - vm.stopPrank(); - - vault.toggleWhitelistCheck(false); - - deposit(alice, 10 * precision); - assertEq(vault.balanceOf(alice), 10 * precision); - } - - function test__WhitelistVault__ShouldToggleWhitelist() public { - bool beforeToggle = vault.checkWhitelist(); - vault.toggleWhitelistCheck(!beforeToggle); - bool afterToggle = vault.checkWhitelist(); - assertEq(afterToggle, !beforeToggle); - } - - function deposit(address user, uint256 assets) internal returns (uint256 shares) { - // first, approve the deposit - vm.startPrank(user); - vaultParams.asset.approve(address(vault), assets); - - shares = vault.deposit(assets, user); - vm.stopPrank(); - } -} diff --git a/packages/contracts/test/script/DeployMocksTest.t.sol b/packages/contracts/test/script/DeployMocksTest.t.sol index c955d151a..efc2a31e6 100644 --- a/packages/contracts/test/script/DeployMocksTest.t.sol +++ b/packages/contracts/test/script/DeployMocksTest.t.sol @@ -4,21 +4,22 @@ pragma solidity ^0.8.19; import { Test } from "forge-std/Test.sol"; -import { DeployMocks } from "../../script/DeployMocks.s.sol"; -import { MockStablecoin } from "../mocks/MockStablecoin.sol"; -import { MockToken } from "../mocks/MockToken.sol"; +import { DeployMocks } from "@script/DeployMocks.s.sol"; + +import { SimpleUSDC } from "@test/test/token/SimpleUSDC.t.sol"; +import { SimpleToken } from "@test/test/token/SimpleToken.t.sol"; contract DeployMocksTest is Test, DeployMocks { constructor() DeployMocks(true, makeAddr("custodian")) { } function test__DeployMocksTest__DeployMocks() public { - (MockToken mockToken, MockStablecoin mockStablecoin) = run(); + (SimpleToken testToken, SimpleUSDC testStablecoin) = run(); - assertNotEq(address(0), address(mockToken)); - assertNotEq(address(0), address(mockStablecoin)); - assertNotEq(address(0), address(credbullBaseVaultMock)); + assertNotEq(address(0), address(testToken)); + assertNotEq(address(0), address(testStablecoin)); + assertNotEq(address(0), address(testVault)); - assertEq(totalSupply, mockToken.totalSupply()); - assertEq(totalSupply, mockStablecoin.totalSupply()); + assertEq(totalSupply, testToken.totalSupply()); + assertEq(totalSupply, testStablecoin.totalSupply()); } } diff --git a/packages/contracts/test/script/DeployedContractsTest.t.sol b/packages/contracts/test/script/DeployedContractsTest.t.sol index 4d6556795..9d5e98cb7 100644 --- a/packages/contracts/test/script/DeployedContractsTest.t.sol +++ b/packages/contracts/test/script/DeployedContractsTest.t.sol @@ -3,7 +3,8 @@ pragma solidity ^0.8.19; import { Test } from "forge-std/Test.sol"; -import { DeployedContracts } from "../../script/DeployedContracts.s.sol"; + +import { DeployedContracts } from "@script/DeployedContracts.s.sol"; contract DeployedContractsTest is Test { function test__DeployedContracts() public { diff --git a/packages/contracts/test/script/HelperConfigTest.t.sol b/packages/contracts/test/script/HelperConfigTest.t.sol index 4a0e16786..1fad694b9 100644 --- a/packages/contracts/test/script/HelperConfigTest.t.sol +++ b/packages/contracts/test/script/HelperConfigTest.t.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.19; import { Test } from "forge-std/Test.sol"; -import { HelperConfig, NetworkConfig, FactoryParams } from "../../script/HelperConfig.s.sol"; +import { HelperConfig, NetworkConfig, FactoryParams } from "@script/HelperConfig.s.sol"; contract HelperConfigTest is Test, HelperConfig { constructor() HelperConfig(true) { } diff --git a/packages/contracts/test/factories/CredbullFixedYieldVaultFactory.t.sol b/packages/contracts/test/src/CredbullFixedYieldVaultFactoryTest.t.sol similarity index 64% rename from packages/contracts/test/factories/CredbullFixedYieldVaultFactory.t.sol rename to packages/contracts/test/src/CredbullFixedYieldVaultFactoryTest.t.sol index 7224230a3..265385805 100644 --- a/packages/contracts/test/factories/CredbullFixedYieldVaultFactory.t.sol +++ b/packages/contracts/test/src/CredbullFixedYieldVaultFactoryTest.t.sol @@ -2,21 +2,25 @@ pragma solidity ^0.8.19; -import { Test } from "forge-std/Test.sol"; -import { HelperVaultTest } from "../base/HelperVaultTest.t.sol"; -import { CredbullFixedYieldVaultFactory } from "../../src/factories/CredbullFixedYieldVaultFactory.sol"; -import { DeployVaultFactory } from "../../script/DeployVaultFactory.s.sol"; -import { HelperConfig, NetworkConfig } from "../../script/HelperConfig.s.sol"; -import { CredbullFixedYieldVault } from "../../src/CredbullFixedYieldVault.sol"; import { IAccessControl } from "@openzeppelin/contracts/access/IAccessControl.sol"; -import { CredbullVaultFactory } from "../../src/factories/CredbullVaultFactory.sol"; -import { CredbullKYCProvider } from "../../src/CredbullKYCProvider.sol"; + +import { Test } from "forge-std/Test.sol"; + +import { HelperConfig, NetworkConfig } from "@script/HelperConfig.s.sol"; +import { DeployVaultFactory } from "@script/DeployVaultFactory.s.sol"; + +import { CredbullFixedYieldVaultFactory } from "@credbull/CredbullFixedYieldVaultFactory.sol"; +import { CredbullFixedYieldVault } from "@credbull/CredbullFixedYieldVault.sol"; +import { CredbullWhiteListProvider } from "@credbull/CredbullWhiteListProvider.sol"; +import { VaultFactory } from "@credbull/factory/VaultFactory.sol"; + +import { ParamsFactory } from "@test/test/vault/utils/ParamsFactory.t.sol"; contract CredbullFixedYieldVaultFactoryTest is Test { CredbullFixedYieldVaultFactory private factory; DeployVaultFactory private deployer; HelperConfig private helperConfig; - CredbullKYCProvider private kycProvider; + CredbullWhiteListProvider private whiteListProvider; NetworkConfig private config; CredbullFixedYieldVault.FixedYieldVaultParams private params; @@ -24,11 +28,11 @@ contract CredbullFixedYieldVaultFactoryTest is Test { function setUp() public { deployer = new DeployVaultFactory(); - (factory,, kycProvider, helperConfig) = deployer.runTest(); + (factory,, whiteListProvider, helperConfig) = deployer.runTest(); config = helperConfig.getNetworkConfig(); - params = new HelperVaultTest(config).createFixedYieldVaultParams(); + params = new ParamsFactory(config).createFixedYieldVaultParams(); - params.kycParams.kycProvider = address(kycProvider); + params.whiteListPlugin.whiteListProvider = address(whiteListProvider); } function test__ShouldSuccefullyCreateFactoryFixedYield() public { @@ -41,16 +45,16 @@ contract CredbullFixedYieldVaultFactoryTest is Test { function test__CreateVaultFromFactory() public { vm.prank(config.factoryParams.owner); - factory.allowCustodian(params.maturityVaultParams.baseVaultParams.custodian); + factory.allowCustodian(params.maturityVault.vault.custodian); vm.prank(config.factoryParams.operator); CredbullFixedYieldVault vault = CredbullFixedYieldVault(payable(factory.createVault(params, OPTIONS))); - assertEq(vault.asset(), address(params.maturityVaultParams.baseVaultParams.asset)); - assertEq(vault.name(), params.maturityVaultParams.baseVaultParams.shareName); - assertEq(vault.symbol(), params.maturityVaultParams.baseVaultParams.shareSymbol); - assertEq(address(vault.kycProvider()), params.kycParams.kycProvider); - assertEq(vault.CUSTODIAN(), params.maturityVaultParams.baseVaultParams.custodian); + assertEq(vault.asset(), address(params.maturityVault.vault.asset)); + assertEq(vault.name(), params.maturityVault.vault.shareName); + assertEq(vault.symbol(), params.maturityVault.vault.shareSymbol); + assertEq(address(vault.whiteListProvider()), params.whiteListPlugin.whiteListProvider); + assertEq(vault.CUSTODIAN(), params.maturityVault.vault.custodian); } function test__ShouldRevertCreateVaultOnUnAuthorizedUser() public { @@ -63,7 +67,7 @@ contract CredbullFixedYieldVaultFactoryTest is Test { address newOperator = makeAddr("new_operator"); vm.startPrank(config.factoryParams.owner); - factory.allowCustodian(params.maturityVaultParams.baseVaultParams.custodian); + factory.allowCustodian(params.maturityVault.vault.custodian); factory.revokeRole(factory.OPERATOR_ROLE(), config.factoryParams.operator); factory.grantRole(factory.OPERATOR_ROLE(), newOperator); vm.stopPrank(); @@ -100,41 +104,41 @@ contract CredbullFixedYieldVaultFactoryTest is Test { function test__ShouldRevertOnNotAllowedCustodians() public { vm.prank(config.factoryParams.owner); - factory.allowCustodian(params.maturityVaultParams.baseVaultParams.custodian); + factory.allowCustodian(params.maturityVault.vault.custodian); - params.maturityVaultParams.baseVaultParams.custodian = makeAddr("randomCustodian"); + params.maturityVault.vault.custodian = makeAddr("randomCustodian"); vm.prank(config.factoryParams.operator); - vm.expectRevert(CredbullVaultFactory.CredbullVaultFactory__CustodianNotAllowed.selector); + vm.expectRevert(VaultFactory.CredbullVaultFactory__CustodianNotAllowed.selector); factory.createVault(params, OPTIONS); } function test__ShouldAllowAdminToAddCustodians() public { vm.prank(config.factoryParams.owner); - factory.allowCustodian(params.maturityVaultParams.baseVaultParams.custodian); + factory.allowCustodian(params.maturityVault.vault.custodian); - assertTrue(factory.isCustodianAllowed(params.maturityVaultParams.baseVaultParams.custodian)); + assertTrue(factory.isCustodianAllowed(params.maturityVault.vault.custodian)); } function test__ShoulRemoveCustodianIfExist() public { vm.startPrank(config.factoryParams.owner); - factory.allowCustodian(params.maturityVaultParams.baseVaultParams.custodian); - assertTrue(factory.isCustodianAllowed(params.maturityVaultParams.baseVaultParams.custodian)); + factory.allowCustodian(params.maturityVault.vault.custodian); + assertTrue(factory.isCustodianAllowed(params.maturityVault.vault.custodian)); - factory.removeCustodian(params.maturityVaultParams.baseVaultParams.custodian); - assertTrue(!factory.isCustodianAllowed(params.maturityVaultParams.baseVaultParams.custodian)); + factory.removeCustodian(params.maturityVault.vault.custodian); + assertTrue(!factory.isCustodianAllowed(params.maturityVault.vault.custodian)); vm.stopPrank(); } function test__ShouldRevertAllowAdmingIfNotOwner() public { vm.prank(makeAddr("random_addr")); vm.expectRevert(); - factory.allowCustodian(params.maturityVaultParams.baseVaultParams.custodian); + factory.allowCustodian(params.maturityVault.vault.custodian); } function createVault() internal returns (CredbullFixedYieldVault vault) { vm.prank(config.factoryParams.owner); - factory.allowCustodian(params.maturityVaultParams.baseVaultParams.custodian); + factory.allowCustodian(params.maturityVault.vault.custodian); vm.prank(config.factoryParams.operator); vault = CredbullFixedYieldVault(payable(factory.createVault(params, OPTIONS))); diff --git a/packages/contracts/test/vaults/CredbullFixedYieldVaultTest.t.sol b/packages/contracts/test/src/CredbullFixedYieldVaultTest.t.sol similarity index 55% rename from packages/contracts/test/vaults/CredbullFixedYieldVaultTest.t.sol rename to packages/contracts/test/src/CredbullFixedYieldVaultTest.t.sol index a2966479a..ab8730fef 100644 --- a/packages/contracts/test/vaults/CredbullFixedYieldVaultTest.t.sol +++ b/packages/contracts/test/src/CredbullFixedYieldVaultTest.t.sol @@ -2,25 +2,29 @@ pragma solidity ^0.8.19; -import { Test } from "forge-std/Test.sol"; -import { HelperVaultTest } from "../base/HelperVaultTest.t.sol"; -import { HelperConfig } from "../../script/HelperConfig.s.sol"; -import { MockStablecoin } from "../mocks/MockStablecoin.sol"; -import { CredbullFixedYieldVault } from "../../src/CredbullFixedYieldVault.sol"; import { IAccessControl } from "@openzeppelin/contracts/access/IAccessControl.sol"; -import { WhitelistPlugIn } from "../../src/plugins/WhitelistPlugIn.sol"; -import { CredbullKYCProvider } from "../../src/CredbullKYCProvider.sol"; -import { DeployVaultFactory } from "../../script/DeployVaultFactory.s.sol"; -import { CredbullKYCProvider } from "../../src/CredbullKYCProvider.sol"; import { Pausable } from "@openzeppelin/contracts/utils/Pausable.sol"; +import { Test } from "forge-std/Test.sol"; + +import { HelperConfig } from "@script/HelperConfig.s.sol"; +import { DeployVaultFactory } from "@script/DeployVaultFactory.s.sol"; + +import { CredbullFixedYieldVault } from "@credbull/CredbullFixedYieldVault.sol"; +import { CredbullWhiteListProvider } from "@credbull/CredbullWhiteListProvider.sol"; +import { WhiteListProvider } from "@credbull/provider/whiteList/WhiteListProvider.sol"; +import { WhiteListPlugin } from "@credbull/plugin/WhiteListPlugin.sol"; + +import { ParamsFactory } from "@test/test/vault/utils/ParamsFactory.t.sol"; +import { SimpleUSDC } from "@test/test/token/SimpleUSDC.t.sol"; + contract CredbullFixedYieldVaultTest is Test { CredbullFixedYieldVault private vault; HelperConfig private helperConfig; DeployVaultFactory private deployer; - CredbullKYCProvider private kycProvider; + CredbullWhiteListProvider private whiteListProvider; - CredbullFixedYieldVault.FixedYieldVaultParams private vaultParams; + CredbullFixedYieldVault.FixedYieldVaultParams private params; address private alice = makeAddr("alice"); address private bob = makeAddr("bob"); @@ -31,48 +35,42 @@ contract CredbullFixedYieldVaultTest is Test { function setUp() public { deployer = new DeployVaultFactory(); - (,, kycProvider, helperConfig) = deployer.runTest(); - vaultParams = new HelperVaultTest(helperConfig.getNetworkConfig()).createFixedYieldVaultParams(); - vaultParams.kycParams.kycProvider = address(kycProvider); + (,, whiteListProvider, helperConfig) = deployer.runTest(); + params = new ParamsFactory(helperConfig.getNetworkConfig()).createFixedYieldVaultParams(); + params.whiteListPlugin.whiteListProvider = address(whiteListProvider); - vault = new CredbullFixedYieldVault(vaultParams); + vault = new CredbullFixedYieldVault(params); - precision = 10 ** MockStablecoin(address(vaultParams.maturityVaultParams.baseVaultParams.asset)).decimals(); + precision = 10 ** SimpleUSDC(address(params.maturityVault.vault.asset)).decimals(); - address[] memory whitelistAddresses = new address[](2); - whitelistAddresses[0] = alice; - whitelistAddresses[1] = bob; + address[] memory whiteListAddresses = new address[](2); + whiteListAddresses[0] = alice; + whiteListAddresses[1] = bob; bool[] memory statuses = new bool[](2); statuses[0] = true; statuses[1] = true; - vm.startPrank(vaultParams.contractRoles.operator); - vault.kycProvider().updateStatus(whitelistAddresses, statuses); + vm.startPrank(params.roles.operator); + vault.whiteListProvider().updateStatus(whiteListAddresses, statuses); vm.stopPrank(); - MockStablecoin(address(vaultParams.maturityVaultParams.baseVaultParams.asset)).mint( - alice, INITIAL_BALANCE * precision - ); - MockStablecoin(address(vaultParams.maturityVaultParams.baseVaultParams.asset)).mint( - bob, INITIAL_BALANCE * precision - ); + SimpleUSDC(address(params.maturityVault.vault.asset)).mint(alice, INITIAL_BALANCE * precision); + SimpleUSDC(address(params.maturityVault.vault.asset)).mint(bob, INITIAL_BALANCE * precision); } function test__FixedYieldVault__ShouldAllowOwnerToChangeOperator() public { address newOperator = makeAddr("new_operator"); - vm.startPrank(vaultParams.contractRoles.owner); - vault.revokeRole(vault.OPERATOR_ROLE(), vaultParams.contractRoles.operator); + vm.startPrank(params.roles.owner); + vault.revokeRole(vault.OPERATOR_ROLE(), params.roles.operator); vault.grantRole(vault.OPERATOR_ROLE(), newOperator); vm.stopPrank(); - vm.startPrank(vaultParams.contractRoles.operator); + vm.startPrank(params.roles.operator); vm.expectRevert( abi.encodeWithSelector( - IAccessControl.AccessControlUnauthorizedAccount.selector, - vaultParams.contractRoles.operator, - vault.OPERATOR_ROLE() + IAccessControl.AccessControlUnauthorizedAccount.selector, params.roles.operator, vault.OPERATOR_ROLE() ) ); vault.mature(); @@ -84,205 +82,213 @@ contract CredbullFixedYieldVaultTest is Test { } function test__FixedYieldVault__RevertMatureIfNotOperator() public { - vm.startPrank(vaultParams.contractRoles.owner); + vm.startPrank(params.roles.owner); vm.expectRevert( abi.encodeWithSelector( - IAccessControl.AccessControlUnauthorizedAccount.selector, - vaultParams.contractRoles.owner, - vault.OPERATOR_ROLE() + IAccessControl.AccessControlUnauthorizedAccount.selector, params.roles.owner, vault.OPERATOR_ROLE() ) ); vault.mature(); vm.stopPrank(); } + function test__FixedYieldVault__ExpectedAssetOnMaturity() public { + uint256 depositAmount = 10 * precision; + deposit(alice, depositAmount, false); + + uint256 expectedAssetValue = ((depositAmount * (100 + params.promisedYield)) / 100); + assertEq(vault.expectedAssetsOnMaturity(), expectedAssetValue); + } + function test__FixedYieldVault__RevertMaturityToggleIfNotAdmin() public { - vm.startPrank(vaultParams.contractRoles.operator); + vm.startPrank(params.roles.operator); vm.expectRevert( abi.encodeWithSelector( IAccessControl.AccessControlUnauthorizedAccount.selector, - vaultParams.contractRoles.operator, + params.roles.operator, vault.DEFAULT_ADMIN_ROLE() ) ); vault.toggleMaturityCheck(false); vm.stopPrank(); - vm.prank(vaultParams.contractRoles.owner); + vm.prank(params.roles.owner); vault.toggleMaturityCheck(false); } - function test__FixedYieldVault__RevertWhitelistToggleIfNotAdmin() public { - vm.startPrank(vaultParams.contractRoles.operator); + function test__FixedYieldVault__RevertWhiteListToggleIfNotAdmin() public { + vm.startPrank(params.roles.operator); vm.expectRevert( abi.encodeWithSelector( IAccessControl.AccessControlUnauthorizedAccount.selector, - vaultParams.contractRoles.operator, + params.roles.operator, vault.DEFAULT_ADMIN_ROLE() ) ); - vault.toggleWhitelistCheck(false); + vault.toggleWhiteListCheck(false); vm.stopPrank(); - vm.prank(vaultParams.contractRoles.owner); - vault.toggleWhitelistCheck(false); + vm.prank(params.roles.owner); + vault.toggleWhiteListCheck(false); } function test__FixedYieldVault__RevertWindowToggleIfNotAdmin() public { - vm.startPrank(vaultParams.contractRoles.operator); + vm.startPrank(params.roles.operator); vm.expectRevert( abi.encodeWithSelector( IAccessControl.AccessControlUnauthorizedAccount.selector, - vaultParams.contractRoles.operator, + params.roles.operator, vault.DEFAULT_ADMIN_ROLE() ) ); vault.toggleWindowCheck(false); vm.stopPrank(); - vm.prank(vaultParams.contractRoles.owner); + vm.prank(params.roles.owner); vault.toggleWindowCheck(false); } - function test__FixedYieldVault__ShouldCheckForWhitelsitedAddresses() public { - address[] memory whitelistAddresses = new address[](1); - whitelistAddresses[0] = alice; + function test__FixedYieldVault__ShouldCheckForWhiteListedAddresses() public { + address[] memory whiteListAddresses = new address[](1); + whiteListAddresses[0] = alice; bool[] memory statuses = new bool[](1); statuses[0] = false; - vm.startPrank(vaultParams.contractRoles.operator); - vault.kycProvider().updateStatus(whitelistAddresses, statuses); + vm.startPrank(params.roles.operator); + vault.whiteListProvider().updateStatus(whiteListAddresses, statuses); vm.stopPrank(); uint256 depositAmount = 1000 * precision; vm.expectRevert( - abi.encodeWithSelector(WhitelistPlugIn.CredbullVault__NotAWhitelistedAddress.selector, alice, depositAmount) + abi.encodeWithSelector(WhiteListPlugin.CredbullVault__NotWhiteListed.selector, alice, depositAmount) ); vault.deposit(depositAmount, alice); } - function test__FixedYieldVault__ExpectACallToWhitelistPlugin() public { - address[] memory whitelistAddresses = new address[](1); - whitelistAddresses[0] = alice; + function test__FixedYieldVault__ExpectACallToWhiteListPlugin() public { + address[] memory whiteListAddresses = new address[](1); + whiteListAddresses[0] = alice; bool[] memory statuses = new bool[](1); statuses[0] = false; - vm.startPrank(vaultParams.contractRoles.operator); - vault.kycProvider().updateStatus(whitelistAddresses, statuses); + vm.startPrank(params.roles.operator); + vault.whiteListProvider().updateStatus(whiteListAddresses, statuses); vm.stopPrank(); uint256 depositAmount = 1000 * precision; vm.expectRevert( - abi.encodeWithSelector(WhitelistPlugIn.CredbullVault__NotAWhitelistedAddress.selector, alice, depositAmount) + abi.encodeWithSelector(WhiteListPlugin.CredbullVault__NotWhiteListed.selector, alice, depositAmount) + ); + vm.expectCall( + address(params.whiteListPlugin.whiteListProvider), abi.encodeCall(WhiteListProvider.status, alice) ); - vm.expectCall(address(vaultParams.kycParams.kycProvider), abi.encodeCall(CredbullKYCProvider.status, alice)); vault.deposit(depositAmount, alice); } function test__FixedYieldVault__RevertMaxCapToggleIfNotAdmin() public { - vm.startPrank(vaultParams.contractRoles.operator); + vm.startPrank(params.roles.operator); vm.expectRevert( abi.encodeWithSelector( IAccessControl.AccessControlUnauthorizedAccount.selector, - vaultParams.contractRoles.operator, + params.roles.operator, vault.DEFAULT_ADMIN_ROLE() ) ); vault.toggleMaxCapCheck(false); vm.stopPrank(); - vm.prank(vaultParams.contractRoles.owner); + vm.prank(params.roles.owner); vault.toggleMaxCapCheck(false); } function test__FixedYieldVault__RevertUdpateMaxCapIfNotAdmin() public { - vm.startPrank(vaultParams.contractRoles.operator); + vm.startPrank(params.roles.operator); vm.expectRevert( abi.encodeWithSelector( IAccessControl.AccessControlUnauthorizedAccount.selector, - vaultParams.contractRoles.operator, + params.roles.operator, vault.DEFAULT_ADMIN_ROLE() ) ); vault.updateMaxCap(100 * precision); vm.stopPrank(); - vm.prank(vaultParams.contractRoles.owner); + vm.prank(params.roles.owner); vault.updateMaxCap(100 * precision); } function test__FixedYieldVault__RevertOpsIfVaultIsPaused() public { - vm.startPrank(vaultParams.contractRoles.owner); + vm.startPrank(params.roles.owner); vault.toggleWindowCheck(false); vault.pauseVault(); vm.expectRevert(abi.encodeWithSelector(Pausable.EnforcedPause.selector)); vault.deposit(1000 * precision, alice); vm.stopPrank(); - vm.startPrank(vaultParams.contractRoles.owner); + vm.startPrank(params.roles.owner); vault.unpauseVault(); vm.stopPrank(); } function test__FixedYieldVault__ShouldAllowAdminToUnpauseVault() public { - vm.startPrank(vaultParams.contractRoles.owner); + vm.startPrank(params.roles.owner); vault.toggleWindowCheck(false); vault.pauseVault(); vm.expectRevert(abi.encodeWithSelector(Pausable.EnforcedPause.selector)); vault.deposit(1000 * precision, alice); vm.stopPrank(); - vm.startPrank(vaultParams.contractRoles.owner); + vm.startPrank(params.roles.owner); vault.unpauseVault(); deposit(alice, 1000 * precision, true); vm.stopPrank(); } function test__FixedYieldVault__ShouldAllowOnlyAdminToPauseVault() public { - vm.startPrank(vaultParams.contractRoles.operator); + vm.startPrank(params.roles.operator); vm.expectRevert( abi.encodeWithSelector( IAccessControl.AccessControlUnauthorizedAccount.selector, - vaultParams.contractRoles.operator, + params.roles.operator, vault.DEFAULT_ADMIN_ROLE() ) ); vault.pauseVault(); vm.stopPrank(); - vm.startPrank(vaultParams.contractRoles.owner); + vm.startPrank(params.roles.owner); vault.pauseVault(); vm.stopPrank(); } function test__FixedYieldVault__RevertWindowUpdateIfNotAdmin() public { - vm.startPrank(vaultParams.contractRoles.operator); + vm.startPrank(params.roles.operator); vm.expectRevert( abi.encodeWithSelector( IAccessControl.AccessControlUnauthorizedAccount.selector, - vaultParams.contractRoles.operator, + params.roles.operator, vault.DEFAULT_ADMIN_ROLE() ) ); vault.updateWindow(100, 200, 300, 400); vm.stopPrank(); - vm.prank(vaultParams.contractRoles.owner); + vm.prank(params.roles.owner); vault.updateWindow(100, 200, 300, 400); } function test__FixedYieldVault__ShouldAllowAdminToWithdrawERC20Tokens() public { - MockStablecoin token = MockStablecoin(address(vaultParams.maturityVaultParams.baseVaultParams.asset)); + SimpleUSDC token = SimpleUSDC(address(params.maturityVault.vault.asset)); vm.prank(alice); token.transfer(address(vault), 100 * precision); assertEq(token.balanceOf(address(vault)), 100 * precision); - vm.prank(vaultParams.contractRoles.owner); + vm.prank(params.roles.owner); address[] memory addresses = new address[](1); - addresses[0] = address(vaultParams.maturityVaultParams.baseVaultParams.asset); + addresses[0] = address(params.maturityVault.vault.asset); vault.withdrawERC20(addresses); assertEq(token.balanceOf(address(vault)), 0); @@ -291,12 +297,11 @@ contract CredbullFixedYieldVaultTest is Test { function deposit(address user, uint256 assets, bool warp) internal returns (uint256 shares) { // first, approve the deposit vm.startPrank(user); - vaultParams.maturityVaultParams.baseVaultParams.asset.approve(address(vault), assets); - // vaultParams.token.approve(address(vault), assets * ADDITIONAL_PRECISION); + params.maturityVault.vault.asset.approve(address(vault), assets); // wrap if set to true if (warp) { - vm.warp(vaultParams.windowVaultParams.depositWindow.opensAt); + vm.warp(params.windowPlugin.depositWindow.opensAt); } shares = vault.deposit(assets, user); diff --git a/packages/contracts/test/vaults/CredbullFixedYieldVaultWithUpsideTest.t.sol b/packages/contracts/test/src/CredbullFixedYieldVaultWithUpsideTest.t.sol similarity index 61% rename from packages/contracts/test/vaults/CredbullFixedYieldVaultWithUpsideTest.t.sol rename to packages/contracts/test/src/CredbullFixedYieldVaultWithUpsideTest.t.sol index 83b8cb160..315dca411 100644 --- a/packages/contracts/test/vaults/CredbullFixedYieldVaultWithUpsideTest.t.sol +++ b/packages/contracts/test/src/CredbullFixedYieldVaultWithUpsideTest.t.sol @@ -2,24 +2,28 @@ pragma solidity ^0.8.19; -import { Math } from "openzeppelin-contracts/contracts/utils/math/Math.sol"; -import { Test } from "forge-std/Test.sol"; -import { HelperVaultTest } from "../base/HelperVaultTest.t.sol"; -import { HelperConfig } from "../../script/HelperConfig.s.sol"; -import { CredbullFixedYieldVaultWithUpside } from "../../src/CredbullFixedYieldVaultWithUpside.sol"; -import { MockStablecoin } from "../mocks/MockStablecoin.sol"; -import { MockToken } from "../mocks/MockToken.sol"; -import { DeployVaultFactory } from "../../script/DeployVaultFactory.s.sol"; -import { CredbullKYCProvider } from "../../src/CredbullKYCProvider.sol"; -import { console2 } from "forge-std/console2.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import { FixedYieldVault } from "../../src/vaults/FixedYieldVault.sol"; -import { CredbullBaseVault } from "../mocks/vaults/CredbullBaseVaultMock.m.sol"; -import { MaxCapPlugIn } from "../../src/plugins/MaxCapPlugIn.sol"; import { IAccessControl } from "@openzeppelin/contracts/access/IAccessControl.sol"; -import { UpsideVault } from "../../src/vaults/UpsideVault.sol"; -import { WhitelistPlugIn } from "../../src/plugins/WhitelistPlugIn.sol"; -import { MockDecimalToken } from "../mocks/MockDecimalToken.sol"; +import { Math } from "@openzeppelin/contracts/utils/math/Math.sol"; + +import { Test } from "forge-std/Test.sol"; +import { console2 } from "forge-std/console2.sol"; + +import { DeployVaultFactory } from "@script/DeployVaultFactory.s.sol"; +import { HelperConfig } from "@script/HelperConfig.s.sol"; + +import { CredbullFixedYieldVaultWithUpside } from "@credbull/CredbullFixedYieldVaultWithUpside.sol"; +import { CredbullWhiteListProvider } from "@credbull/CredbullWhiteListProvider.sol"; +import { WhiteListPlugin } from "@credbull/plugin/WhiteListPlugin.sol"; +import { MaxCapPlugin } from "@credbull/plugin/MaxCapPlugin.sol"; +import { FixedYieldVault } from "@credbull/vault/FixedYieldVault.sol"; +import { UpsideVault } from "@credbull/vault/UpsideVault.sol"; +import { Vault } from "@credbull/vault/Vault.sol"; + +import { DecimalToken } from "@test/test/token/DecimalToken.t.sol"; +import { SimpleUSDC } from "@test/test/token/SimpleUSDC.t.sol"; +import { SimpleToken } from "@test/test/token/SimpleToken.t.sol"; +import { ParamsFactory } from "@test/test/vault/utils/ParamsFactory.t.sol"; contract CredbullFixedYieldVaultWithUpsideTest is Test { using Math for uint256; @@ -27,7 +31,7 @@ contract CredbullFixedYieldVaultWithUpsideTest is Test { CredbullFixedYieldVaultWithUpside private vault; HelperConfig private helperConfig; DeployVaultFactory private deployer; - CredbullKYCProvider private kycProvider; + CredbullWhiteListProvider private whiteListProvider; FixedYieldVault.FixedYieldVaultParams private vaultParams; CredbullFixedYieldVaultWithUpside.UpsideVaultParams private upsideVaultParams; @@ -44,62 +48,56 @@ contract CredbullFixedYieldVaultWithUpsideTest is Test { function setUp() public { deployer = new DeployVaultFactory(); - (,, kycProvider, helperConfig) = deployer.runTest(); - (upsideVaultParams) = - new HelperVaultTest(helperConfig.getNetworkConfig()).createFixedYieldWithUpsideVaultParams(); - vaultParams = upsideVaultParams.fixedYieldVaultParams; - upsideVaultParams.fixedYieldVaultParams.kycParams.kycProvider = address(kycProvider); + (,, whiteListProvider, helperConfig) = deployer.runTest(); + (upsideVaultParams) = new ParamsFactory(helperConfig.getNetworkConfig()).createUpsideVaultParams(); + vaultParams = upsideVaultParams.fixedYieldVault; + upsideVaultParams.fixedYieldVault.whiteListPlugin.whiteListProvider = address(whiteListProvider); cblToken = upsideVaultParams.cblToken; vault = new CredbullFixedYieldVaultWithUpside(upsideVaultParams); - precision = 10 ** MockStablecoin(address(vaultParams.maturityVaultParams.baseVaultParams.asset)).decimals(); + precision = 10 ** SimpleUSDC(address(vaultParams.maturityVault.vault.asset)).decimals(); - address[] memory whitelistAddresses = new address[](1); - whitelistAddresses[0] = alice; + address[] memory whiteListAddresses = new address[](1); + whiteListAddresses[0] = alice; bool[] memory statuses = new bool[](1); statuses[0] = true; - vm.startPrank(vaultParams.contractRoles.operator); - vault.kycProvider().updateStatus(whitelistAddresses, statuses); + vm.startPrank(vaultParams.roles.operator); + vault.whiteListProvider().updateStatus(whiteListAddresses, statuses); vm.stopPrank(); - MockStablecoin(address(vaultParams.maturityVaultParams.baseVaultParams.asset)).mint( - alice, INITIAL_BALANCE * precision - ); - MockToken(address(cblToken)).mint(alice, 200 ether); + SimpleUSDC(address(vaultParams.maturityVault.vault.asset)).mint(alice, INITIAL_BALANCE * precision); + SimpleToken(address(cblToken)).mint(alice, 200 ether); } function test__UpsideVault__VaultCreationShouldRevertOnUnsupportedDecimalValue() public { - UpsideVault.UpsideVaultParams memory params = upsideVaultParams; - params.cblToken = new MockDecimalToken(1e6, 19); - vm.expectRevert(abi.encodeWithSelector(CredbullBaseVault.CredbullVault__UnsupportedDecimalValue.selector, 19)); + CredbullFixedYieldVaultWithUpside.UpsideVaultParams memory params = upsideVaultParams; + params.cblToken = new DecimalToken(1e6, 19); + vm.expectRevert(abi.encodeWithSelector(Vault.CredbullVault__UnsupportedDecimalValue.selector, 19)); new CredbullFixedYieldVaultWithUpside(params); } function test__UpsideVault__ShouldSuccessfullyCreateUpsideVault() public { vault = new CredbullFixedYieldVaultWithUpside(upsideVaultParams); - assertEq(vault.asset(), address(vaultParams.maturityVaultParams.baseVaultParams.asset)); + assertEq(vault.asset(), address(vaultParams.maturityVault.vault.asset)); } function test__UpsideVault__VaultCreationShouldRevertOnTokenDecimalLessThanAssetDeciaml() public { - UpsideVault.UpsideVaultParams memory params = upsideVaultParams; - params.cblToken = new MockDecimalToken(1e6, 6); - params.fixedYieldVaultParams.maturityVaultParams.baseVaultParams.asset = new MockDecimalToken(1e6, 8); - vm.expectRevert(abi.encodeWithSelector(CredbullBaseVault.CredbullVault__UnsupportedDecimalValue.selector, 8)); + CredbullFixedYieldVaultWithUpside.UpsideVaultParams memory params = upsideVaultParams; + params.cblToken = new DecimalToken(1e6, 6); + params.fixedYieldVault.maturityVault.vault.asset = new DecimalToken(1e6, 8); + vm.expectRevert(abi.encodeWithSelector(Vault.CredbullVault__UnsupportedDecimalValue.selector, 8)); new CredbullFixedYieldVaultWithUpside(params); } function test__UpsideVault__DepositAssetsAndGetShares() public { - uint256 custodiansBalance = vaultParams.maturityVaultParams.baseVaultParams.asset.balanceOf( - vaultParams.maturityVaultParams.baseVaultParams.custodian - ); + uint256 custodiansBalance = + vaultParams.maturityVault.vault.asset.balanceOf(vaultParams.maturityVault.vault.custodian); // ---- Setup Part 1, Check balance before deposit ---- assertEq( - vaultParams.maturityVaultParams.baseVaultParams.asset.balanceOf(address(vault)), - 0, - "Vault should start with no assets" + vaultParams.maturityVault.vault.asset.balanceOf(address(vault)), 0, "Vault should start with no assets" ); assertEq(vault.totalAssets(), 0, "Vault should start with no assets"); assertEq(vault.balanceOf(alice), 0, "User should start with no Shares"); @@ -114,9 +112,7 @@ contract CredbullFixedYieldVaultWithUpsideTest is Test { // Vault should have the assets assertEq(vault.totalAssets(), depositAmount, "Vault should now have the assets"); assertEq( - vaultParams.maturityVaultParams.baseVaultParams.asset.balanceOf( - vaultParams.maturityVaultParams.baseVaultParams.custodian - ), + vaultParams.maturityVault.vault.asset.balanceOf(vaultParams.maturityVault.vault.custodian), depositAmount + custodiansBalance, "Custodian should have received the assets" ); @@ -164,7 +160,7 @@ contract CredbullFixedYieldVaultWithUpsideTest is Test { function test__UpsideVault__SetTWAP() public { uint256 twap = 1000; - vm.prank(vaultParams.contractRoles.operator); + vm.prank(vaultParams.roles.operator); vault.setTWAP(twap); assertEq(vault.twap(), twap, "TWAP should be set to 1000"); } @@ -184,23 +180,18 @@ contract CredbullFixedYieldVaultWithUpsideTest is Test { function test__UpsideVault__RevertDepositIfNotWhitelisted() public { uint256 depositAmount = 1000 * precision; vm.expectRevert( - abi.encodeWithSelector( - WhitelistPlugIn.CredbullVault__NotAWhitelistedAddress.selector, address(this), depositAmount - ) + abi.encodeWithSelector(WhiteListPlugin.CredbullVault__NotWhiteListed.selector, address(this), depositAmount) ); vault.deposit(depositAmount, address(this)); } function test__UpsideVault__MintAssetsAndGetShares() public { - uint256 custodiansBalance = vaultParams.maturityVaultParams.baseVaultParams.asset.balanceOf( - vaultParams.maturityVaultParams.baseVaultParams.custodian - ); + uint256 custodiansBalance = + vaultParams.maturityVault.vault.asset.balanceOf(vaultParams.maturityVault.vault.custodian); // ---- Setup Part 1, Check balance before deposit ---- assertEq( - vaultParams.maturityVaultParams.baseVaultParams.asset.balanceOf(address(vault)), - 0, - "Vault should start with no assets" + vaultParams.maturityVault.vault.asset.balanceOf(address(vault)), 0, "Vault should start with no assets" ); assertEq(vault.totalAssets(), 0, "Vault should start with no assets"); assertEq(vault.balanceOf(alice), 0, "User should start with no Shares"); @@ -215,9 +206,7 @@ contract CredbullFixedYieldVaultWithUpsideTest is Test { // Vault should have the assets assertEq(vault.totalAssets(), sharesAmount, "Vault should now have the assets"); assertEq( - vaultParams.maturityVaultParams.baseVaultParams.asset.balanceOf( - vaultParams.maturityVaultParams.baseVaultParams.custodian - ), + vaultParams.maturityVault.vault.asset.balanceOf(vaultParams.maturityVault.vault.custodian), sharesAmount + custodiansBalance, "Custodian should have received the assets" ); @@ -240,15 +229,15 @@ contract CredbullFixedYieldVaultWithUpsideTest is Test { uint256 depositAmount = 1e6 * 1e6; vm.prank(alice); - vm.expectRevert(abi.encodeWithSelector(MaxCapPlugIn.CredbullVault__MaxCapReached.selector)); + vm.expectRevert(abi.encodeWithSelector(MaxCapPlugin.CredbullVault__MaxCapReached.selector)); vault.deposit(depositAmount + 1, alice); } function depositWithRevert(address user, uint256 assets) internal returns (uint256 shares) { vm.startPrank(user); - vaultParams.maturityVaultParams.baseVaultParams.asset.approve(address(vault), assets); + vaultParams.maturityVault.vault.asset.approve(address(vault), assets); cblToken.approve(address(vault), assets * ADDITIONAL_PRECISION); - vm.expectRevert(abi.encodeWithSelector(CredbullBaseVault.CredbullVault__InvalidAssetAmount.selector, assets)); + vm.expectRevert(abi.encodeWithSelector(Vault.CredbullVault__InvalidAssetAmount.selector, assets)); shares = vault.deposit(assets, user); vm.stopPrank(); } @@ -260,15 +249,15 @@ contract CredbullFixedYieldVaultWithUpsideTest is Test { uint256 shares = deposit(alice, depositAmount, true); // ----- Setup Part 2 - Deposit asset from custodian vault with 10% addition yeild ---- // - MockStablecoin(address(vaultParams.maturityVaultParams.baseVaultParams.asset)).mint( - vaultParams.maturityVaultParams.baseVaultParams.custodian, (100 * precision) + 1 + SimpleUSDC(address(vaultParams.maturityVault.vault.asset)).mint( + vaultParams.maturityVault.vault.custodian, (100 * precision) + 1 ); - uint256 finalBalance = MockStablecoin(address(vaultParams.maturityVaultParams.baseVaultParams.asset)).balanceOf( - vaultParams.maturityVaultParams.baseVaultParams.custodian + uint256 finalBalance = SimpleUSDC(address(vaultParams.maturityVault.vault.asset)).balanceOf( + vaultParams.maturityVault.vault.custodian ); - vm.prank(vaultParams.maturityVaultParams.baseVaultParams.custodian); - vaultParams.maturityVaultParams.baseVaultParams.asset.transfer(address(vault), finalBalance); + vm.prank(vaultParams.maturityVault.vault.custodian); + vaultParams.maturityVault.vault.asset.transfer(address(vault), finalBalance); // ---- Assert Vault burns shares vm.startPrank(alice); @@ -276,9 +265,9 @@ contract CredbullFixedYieldVaultWithUpsideTest is Test { vault.approve(address(this), shares); vm.stopPrank(); - vm.startPrank(vaultParams.contractRoles.operator); + vm.startPrank(vaultParams.roles.operator); vault.mature(); - vm.warp(vaultParams.windowVaultParams.matureWindow.opensAt + 1); + vm.warp(vaultParams.windowPlugin.redemptionWindow.opensAt + 1); vm.stopPrank(); vault.redeem(shares, alice, alice); @@ -291,24 +280,24 @@ contract CredbullFixedYieldVaultWithUpsideTest is Test { uint256 shares = deposit(alice, depositAmount, true); // ----- Setup Part 2 - Deposit asset from custodian vault with 10% addition yeild ---- // - MockStablecoin(address(vaultParams.maturityVaultParams.baseVaultParams.asset)).mint( - vaultParams.maturityVaultParams.baseVaultParams.custodian, (100 * precision) + 1 + SimpleUSDC(address(vaultParams.maturityVault.vault.asset)).mint( + vaultParams.maturityVault.vault.custodian, (100 * precision) + 1 ); - uint256 finalBalance = MockStablecoin(address(vaultParams.maturityVaultParams.baseVaultParams.asset)).balanceOf( - vaultParams.maturityVaultParams.baseVaultParams.custodian + uint256 finalBalance = SimpleUSDC(address(vaultParams.maturityVault.vault.asset)).balanceOf( + vaultParams.maturityVault.vault.custodian ); - vm.prank(vaultParams.maturityVaultParams.baseVaultParams.custodian); - vaultParams.maturityVaultParams.baseVaultParams.asset.transfer(address(vault), finalBalance); + vm.prank(vaultParams.maturityVault.vault.custodian); + vaultParams.maturityVault.vault.asset.transfer(address(vault), finalBalance); // ---- Assert Vault burns shares and Alice receive asset with additional 10% --- - uint256 balanceBeforeRedeem = vaultParams.maturityVaultParams.baseVaultParams.asset.balanceOf(alice); + uint256 balanceBeforeRedeem = vaultParams.maturityVault.vault.asset.balanceOf(alice); vm.prank(alice); vault.approve(address(vault), shares); - vm.startPrank(vaultParams.contractRoles.operator); + vm.startPrank(vaultParams.roles.operator); vault.mature(); - vm.warp(vaultParams.windowVaultParams.matureWindow.opensAt + 1); + vm.warp(vaultParams.windowPlugin.redemptionWindow.opensAt + 1); vm.stopPrank(); uint256 collateralToRedeem = vault.calculateTokenRedemption(shares, alice); @@ -322,7 +311,7 @@ contract CredbullFixedYieldVaultWithUpsideTest is Test { assertEq(cblToken.balanceOf(alice), collateralToRedeem, "Alice should now have the Tokens"); assertEq( - vaultParams.maturityVaultParams.baseVaultParams.asset.balanceOf(alice), + vaultParams.maturityVault.vault.asset.balanceOf(alice), balanceBeforeRedeem + assets, "Alice should receive finalBalance with 10% yeild" ); @@ -335,27 +324,27 @@ contract CredbullFixedYieldVaultWithUpsideTest is Test { uint256 shares = deposit(alice, depositAmount, true); // ----- Setup Part 2 - Deposit asset from custodian vault with 10% addition yeild ---- // - MockStablecoin(address(vaultParams.maturityVaultParams.baseVaultParams.asset)).mint( - vaultParams.maturityVaultParams.baseVaultParams.custodian, 100 * precision + SimpleUSDC(address(vaultParams.maturityVault.vault.asset)).mint( + vaultParams.maturityVault.vault.custodian, 100 * precision ); - uint256 finalBalance = MockStablecoin(address(vaultParams.maturityVaultParams.baseVaultParams.asset)).balanceOf( - vaultParams.maturityVaultParams.baseVaultParams.custodian + uint256 finalBalance = SimpleUSDC(address(vaultParams.maturityVault.vault.asset)).balanceOf( + vaultParams.maturityVault.vault.custodian ); - vm.prank(vaultParams.maturityVaultParams.baseVaultParams.custodian); - vaultParams.maturityVaultParams.baseVaultParams.asset.transfer(address(vault), finalBalance); + vm.prank(vaultParams.maturityVault.vault.custodian); + vaultParams.maturityVault.vault.asset.transfer(address(vault), finalBalance); vm.stopPrank(); // ---- Assert Vault burns shares and Alice receive asset with additional 10% --- vm.prank(alice); vault.approve(address(vault), shares); - vm.startPrank(vaultParams.contractRoles.operator); + vm.startPrank(vaultParams.roles.operator); vault.mature(); - vm.warp(vaultParams.windowVaultParams.matureWindow.opensAt + 1); + vm.warp(vaultParams.windowPlugin.redemptionWindow.opensAt + 1); vm.stopPrank(); - uint256 assetBalanceBeforeWithdraw = vaultParams.maturityVaultParams.baseVaultParams.asset.balanceOf(alice); + uint256 assetBalanceBeforeWithdraw = vaultParams.maturityVault.vault.asset.balanceOf(alice); uint256 assetToReceive = vault.convertToAssets(shares); @@ -364,7 +353,7 @@ contract CredbullFixedYieldVaultWithUpsideTest is Test { assertEq(cblToken.balanceOf(alice), 200 ether, "Alice should now have the Tokens"); assertEq( - vaultParams.maturityVaultParams.baseVaultParams.asset.balanceOf(alice), + vaultParams.maturityVault.vault.asset.balanceOf(alice), assetBalanceBeforeWithdraw + assetToReceive, "Alice should receive finalBalance with 10% yeild" ); @@ -373,12 +362,12 @@ contract CredbullFixedYieldVaultWithUpsideTest is Test { function deposit(address user, uint256 assets, bool warp) internal returns (uint256 shares) { // first, approve the deposit vm.startPrank(user); - vaultParams.maturityVaultParams.baseVaultParams.asset.approve(address(vault), assets); + vaultParams.maturityVault.vault.asset.approve(address(vault), assets); cblToken.approve(address(vault), assets * ADDITIONAL_PRECISION); // wrap if set to true if (warp) { - vm.warp(vaultParams.windowVaultParams.depositWindow.opensAt); + vm.warp(vaultParams.windowPlugin.depositWindow.opensAt); } shares = vault.deposit(assets, user); @@ -388,12 +377,12 @@ contract CredbullFixedYieldVaultWithUpsideTest is Test { function mint(address user, uint256 shares, bool warp) internal returns (uint256 assets) { // first, approve the deposit vm.startPrank(user); - vaultParams.maturityVaultParams.baseVaultParams.asset.approve(address(vault), shares); + vaultParams.maturityVault.vault.asset.approve(address(vault), shares); cblToken.approve(address(vault), shares * ADDITIONAL_PRECISION); // wrap if set to true if (warp) { - vm.warp(vaultParams.windowVaultParams.depositWindow.opensAt); + vm.warp(vaultParams.windowPlugin.depositWindow.opensAt); } assets = vault.mint(shares, user); diff --git a/packages/contracts/test/src/CredbullUpsideVaultFactoryTest.t.sol b/packages/contracts/test/src/CredbullUpsideVaultFactoryTest.t.sol new file mode 100644 index 000000000..1f78bf409 --- /dev/null +++ b/packages/contracts/test/src/CredbullUpsideVaultFactoryTest.t.sol @@ -0,0 +1,57 @@ +//SPDX-License-Identifier: MIT + +pragma solidity ^0.8.19; + +import { Test } from "forge-std/Test.sol"; + +import { DeployVaultFactory } from "@script/DeployVaultFactory.s.sol"; +import { HelperConfig, NetworkConfig } from "@script/HelperConfig.s.sol"; + +import { UpsideVault } from "@credbull/vault/UpsideVault.sol"; +import { CredbullFixedYieldVaultWithUpside } from "@credbull/CredbullFixedYieldVaultWithUpside.sol"; +import { CredbullWhiteListProvider } from "@credbull/CredbullWhiteListProvider.sol"; +import { CredbullUpsideVaultFactory } from "@credbull/CredbullUpsideVaultFactory.sol"; +import { ParamsFactory } from "@test/test/vault/utils/ParamsFactory.t.sol"; + +contract CredbullUpsideVaultFactoryTest is Test { + CredbullUpsideVaultFactory private factory; + DeployVaultFactory private deployer; + HelperConfig private helperConfig; + CredbullWhiteListProvider private whiteListProvider; + + string private OPTIONS = "{}"; + + function setUp() public { + deployer = new DeployVaultFactory(); + (, factory, whiteListProvider, helperConfig) = deployer.runTest(); + } + + function test__CredbullUpsideVaultFactory__ShouldSuccessfullyCreateFactoryUpside() public { + NetworkConfig memory config = helperConfig.getNetworkConfig(); + address[] memory custodians = new address[](1); + custodians[0] = config.factoryParams.custodian; + CredbullUpsideVaultFactory vaultFactory = + new CredbullUpsideVaultFactory(config.factoryParams.owner, config.factoryParams.operator, custodians); + vaultFactory.hasRole(vaultFactory.OPERATOR_ROLE(), config.factoryParams.operator); + } + + function test__CredbullUpsideVaultFactory__CreateUpsideVaultFromFactory() public { + NetworkConfig memory config = helperConfig.getNetworkConfig(); + (UpsideVault.UpsideVaultParams memory params) = new ParamsFactory(config).createUpsideVaultParams(); + + params.fixedYieldVault.whiteListPlugin.whiteListProvider = address(whiteListProvider); + + vm.prank(config.factoryParams.owner); + factory.allowCustodian(params.fixedYieldVault.maturityVault.vault.custodian); + + vm.prank(config.factoryParams.operator); + CredbullFixedYieldVaultWithUpside vault = + CredbullFixedYieldVaultWithUpside(payable(factory.createVault(params, OPTIONS))); + + assertEq(vault.asset(), address(params.fixedYieldVault.maturityVault.vault.asset)); + assertEq(vault.name(), params.fixedYieldVault.maturityVault.vault.shareName); + assertEq(vault.symbol(), params.fixedYieldVault.maturityVault.vault.shareSymbol); + assertEq(address(vault.whiteListProvider()), params.fixedYieldVault.whiteListPlugin.whiteListProvider); + assertEq(vault.CUSTODIAN(), params.fixedYieldVault.maturityVault.vault.custodian); + } +} diff --git a/packages/contracts/test/src/CredbullWhiteListProviderTest.t.sol b/packages/contracts/test/src/CredbullWhiteListProviderTest.t.sol new file mode 100644 index 000000000..f0ad0b37d --- /dev/null +++ b/packages/contracts/test/src/CredbullWhiteListProviderTest.t.sol @@ -0,0 +1,35 @@ +//SPDX-License-Identifier: MIT + +pragma solidity ^0.8.19; + +import { Test } from "forge-std/Test.sol"; +import { CredbullWhiteListProvider } from "@credbull/CredbullWhiteListProvider.sol"; +import { WhiteListProvider } from "@credbull/provider/whiteList/WhiteListProvider.sol"; + +contract CredbullWhiteListProviderTest is Test { + CredbullWhiteListProvider private whiteListProvider; + address private owner = makeAddr("owner"); + address private alice = makeAddr("alice"); + + function setUp() public { + whiteListProvider = new CredbullWhiteListProvider(owner); + } + + function test__WhiteListProvider__SuccessfullyDeployWhiteListProvider() public { + whiteListProvider = new CredbullWhiteListProvider(owner); + assertEq(whiteListProvider.owner(), owner); + } + + function test__WhiteListProvider__RevertWhiteListProviderUpdateStatusIfLengthMismatch() public { + address[] memory whitelistAddresses = new address[](1); + whitelistAddresses[0] = alice; + + bool[] memory statuses = new bool[](2); + statuses[0] = true; + statuses[1] = true; + + vm.prank(owner); + vm.expectRevert(abi.encodeWithSelector(WhiteListProvider.LengthMismatch.selector)); + whiteListProvider.updateStatus(whitelistAddresses, statuses); + } +} diff --git a/packages/contracts/test/plugins/MaxCapPlugInTest.t.sol b/packages/contracts/test/src/plugin/MaxCapPluginTest.t.sol similarity index 57% rename from packages/contracts/test/plugins/MaxCapPlugInTest.t.sol rename to packages/contracts/test/src/plugin/MaxCapPluginTest.t.sol index b56c34c97..5cf9ea00a 100644 --- a/packages/contracts/test/plugins/MaxCapPlugInTest.t.sol +++ b/packages/contracts/test/src/plugin/MaxCapPluginTest.t.sol @@ -3,18 +3,21 @@ pragma solidity ^0.8.19; import { Test } from "forge-std/Test.sol"; -import { HelperVaultTest } from "../base/HelperVaultTest.t.sol"; -import { MaxCapVaultMock } from "../mocks/vaults/MaxCapVaultMock.m.sol"; -import { HelperConfig } from "../../script/HelperConfig.s.sol"; -import { MockStablecoin } from "../mocks/MockStablecoin.sol"; -import { MaxCapPlugIn } from "../../src/plugins/MaxCapPlugIn.sol"; -import { CredbullBaseVault } from "./../../src/base/CredbullBaseVault.sol"; - -contract MaxCapPlugInTest is Test { - MaxCapVaultMock private vault; - - CredbullBaseVault.BaseVaultParams private vaultParams; - MaxCapPlugIn.MaxCapParams private maxCapParams; + +import { HelperConfig } from "@script/HelperConfig.s.sol"; + +import { Vault } from "@credbull/vault/Vault.sol"; +import { MaxCapPlugin } from "@credbull/plugin/MaxCapPlugin.sol"; + +import { SimpleUSDC } from "@test/test/token/SimpleUSDC.t.sol"; +import { SimpleMaxCapVault } from "@test/test/vault/SimpleMaxCapVault.t.sol"; +import { ParamsFactory } from "@test/test/vault/utils/ParamsFactory.t.sol"; + +contract MaxCapPluginTest is Test { + SimpleMaxCapVault private vault; + + Vault.VaultParams private vaultParams; + MaxCapPlugin.MaxCapPluginParams private maxCapParams; HelperConfig private helperConfig; address private alice = makeAddr("alice"); @@ -25,14 +28,15 @@ contract MaxCapPlugInTest is Test { function setUp() public { helperConfig = new HelperConfig(true); - vaultParams = new HelperVaultTest(helperConfig.getNetworkConfig()).createBaseVaultTestParams(); - maxCapParams = new HelperVaultTest(helperConfig.getNetworkConfig()).createMaxCapParams(); + ParamsFactory pf = new ParamsFactory(helperConfig.getNetworkConfig()); + vaultParams = pf.createVaultParams(); + maxCapParams = pf.createMaxCapPluginParams(); - vault = new MaxCapVaultMock(vaultParams, maxCapParams); - precision = 10 ** MockStablecoin(address(vaultParams.asset)).decimals(); + vault = new SimpleMaxCapVault(vaultParams, maxCapParams); + precision = 10 ** SimpleUSDC(address(vaultParams.asset)).decimals(); - MockStablecoin(address(vaultParams.asset)).mint(alice, INITIAL_BALANCE * precision); - MockStablecoin(address(vaultParams.asset)).mint(bob, INITIAL_BALANCE * precision); + SimpleUSDC(address(vaultParams.asset)).mint(alice, INITIAL_BALANCE * precision); + SimpleUSDC(address(vaultParams.asset)).mint(bob, INITIAL_BALANCE * precision); } function test__MaxCapVault__ShouldRevertDepositIfReachedMaxCap() public { @@ -44,14 +48,14 @@ contract MaxCapPlugInTest is Test { // Edge case - when total deposited asset is exactly 1 million uint256 bobDepositAmount = maxCap - aliceDepositAmount; - MockStablecoin(address(vaultParams.asset)).mint(bob, bobDepositAmount); + SimpleUSDC(address(vaultParams.asset)).mint(bob, bobDepositAmount); deposit(bob, bobDepositAmount); uint256 additionalDepositAmount = 1 * precision; vm.startPrank(alice); vaultParams.asset.approve(address(vault), additionalDepositAmount); - vm.expectRevert(MaxCapPlugIn.CredbullVault__MaxCapReached.selector); + vm.expectRevert(MaxCapPlugin.CredbullVault__MaxCapReached.selector); vault.deposit(additionalDepositAmount, alice); vm.stopPrank(); } diff --git a/packages/contracts/test/src/plugin/WhiteListPluginTest.t.sol b/packages/contracts/test/src/plugin/WhiteListPluginTest.t.sol new file mode 100644 index 000000000..5a4243610 --- /dev/null +++ b/packages/contracts/test/src/plugin/WhiteListPluginTest.t.sol @@ -0,0 +1,143 @@ +//SPDX-License-Identifier: MIT + +pragma solidity ^0.8.19; + +import { Test } from "forge-std/Test.sol"; + +import { DeployVaultFactory } from "@script/DeployVaultFactory.s.sol"; +import { HelperConfig } from "@script/HelperConfig.s.sol"; + +import { CredbullWhiteListProvider } from "@credbull/CredbullWhiteListProvider.sol"; +import { Vault } from "@credbull/vault/Vault.sol"; +import { WhiteListPlugin } from "@credbull/plugin/WhiteListPlugin.sol"; + +import { SimpleUSDC } from "@test/test/token/SimpleUSDC.t.sol"; +import { SimpleWhiteListVault } from "@test/test/vault/SimpleWhiteListVault.t.sol"; +import { ParamsFactory } from "@test/test/vault/utils/ParamsFactory.t.sol"; + +contract WhiteListPluginTest is Test { + SimpleWhiteListVault private vault; + DeployVaultFactory private deployer; + CredbullWhiteListProvider private whiteListProvider; + + Vault.VaultParams private vaultParams; + WhiteListPlugin.WhiteListPluginParams private whiteListParams; + HelperConfig private helperConfig; + + address private alice = makeAddr("alice"); + address private bob = makeAddr("bob"); + uint256 private precision; + + uint256 private constant INITIAL_BALANCE = 1e6; + + function setUp() public { + deployer = new DeployVaultFactory(); + (,, whiteListProvider, helperConfig) = deployer.runTest(); + ParamsFactory pf = new ParamsFactory(helperConfig.getNetworkConfig()); + vaultParams = pf.createVaultParams(); + whiteListParams = pf.createWhiteListPluginParams(); + whiteListParams.whiteListProvider = address(whiteListProvider); + + vault = new SimpleWhiteListVault(vaultParams, whiteListParams); + precision = 10 ** SimpleUSDC(address(vaultParams.asset)).decimals(); + + address[] memory whiteListAddresses = new address[](2); + whiteListAddresses[0] = alice; + whiteListAddresses[1] = bob; + + bool[] memory statuses = new bool[](2); + statuses[0] = true; + statuses[1] = true; + + vm.startPrank(whiteListProvider.owner()); + vault.whiteListProvider().updateStatus(whiteListAddresses, statuses); + vm.stopPrank(); + + SimpleUSDC(address(vaultParams.asset)).mint(alice, INITIAL_BALANCE * precision); + SimpleUSDC(address(vaultParams.asset)).mint(bob, INITIAL_BALANCE * precision); + } + + function test__WhiteListVault__RevertDepositIfReceiverNotWhiteListed() public { + address[] memory whiteListAddresses = new address[](1); + whiteListAddresses[0] = alice; + + bool[] memory statuses = new bool[](1); + statuses[0] = false; + + vm.startPrank(whiteListProvider.owner()); + vault.whiteListProvider().updateStatus(whiteListAddresses, statuses); + vm.stopPrank(); + + uint256 depositAmount = 1000 * precision; + + vm.startPrank(alice); + vaultParams.asset.approve(address(vault), depositAmount); + + vm.expectRevert( + abi.encodeWithSelector(WhiteListPlugin.CredbullVault__NotWhiteListed.selector, alice, depositAmount) + ); + vault.deposit(depositAmount, alice); + vm.stopPrank(); + } + + function test__WhiteListVault__ShouldSkipCheckIfDepositIsLessThanThreshold() public { + address[] memory whiteListAddresses = new address[](1); + whiteListAddresses[0] = alice; + + bool[] memory statuses = new bool[](1); + statuses[0] = false; + + uint256 depositAmount = 100 * precision; + vm.startPrank(alice); + vaultParams.asset.approve(address(vault), depositAmount); + + vault.deposit(depositAmount, alice); + vm.stopPrank(); + + assertEq(vault.balanceOf(alice), depositAmount); + } + + function test__WhiteListVault__SucessfulDepositOnWhiteListVault() public { + uint256 depositAmount = 1000 * precision; + vm.startPrank(alice); + vaultParams.asset.approve(address(vault), depositAmount); + + vault.deposit(depositAmount, alice); + vm.stopPrank(); + + assertEq(vault.balanceOf(alice), depositAmount); + } + + function test__WhiteListVault__ShouldNotRevertOnWhiteListModifier() public { + address[] memory whiteListAddresses = new address[](1); + whiteListAddresses[0] = alice; + + bool[] memory statuses = new bool[](1); + statuses[0] = false; + + vm.startPrank(whiteListProvider.owner()); + vault.whiteListProvider().updateStatus(whiteListAddresses, statuses); + vm.stopPrank(); + + vault.toggleWhiteListCheck(false); + + deposit(alice, 10 * precision); + assertEq(vault.balanceOf(alice), 10 * precision); + } + + function test__WhiteListVault__ShouldToggleWhiteList() public { + bool beforeToggle = vault.checkWhiteList(); + vault.toggleWhiteListCheck(!beforeToggle); + bool afterToggle = vault.checkWhiteList(); + assertEq(afterToggle, !beforeToggle); + } + + function deposit(address user, uint256 assets) internal returns (uint256 shares) { + // first, approve the deposit + vm.startPrank(user); + vaultParams.asset.approve(address(vault), assets); + + shares = vault.deposit(assets, user); + vm.stopPrank(); + } +} diff --git a/packages/contracts/test/plugins/WindowPlugInTest.t.sol b/packages/contracts/test/src/plugin/WindowPluginTest.t.sol similarity index 75% rename from packages/contracts/test/plugins/WindowPlugInTest.t.sol rename to packages/contracts/test/src/plugin/WindowPluginTest.t.sol index 6ca1ae41a..e57f9ad4a 100644 --- a/packages/contracts/test/plugins/WindowPlugInTest.t.sol +++ b/packages/contracts/test/src/plugin/WindowPluginTest.t.sol @@ -3,18 +3,21 @@ pragma solidity ^0.8.19; import { Test } from "forge-std/Test.sol"; -import { HelperVaultTest } from "../base/HelperVaultTest.t.sol"; -import { WindowVaultMock } from "../mocks/vaults/WindowVaultMock.m.sol"; -import { HelperConfig } from "../../script/HelperConfig.s.sol"; -import { MockStablecoin } from "../mocks/MockStablecoin.sol"; -import { WindowPlugIn } from "../../src/plugins/WindowPlugIn.sol"; -import { CredbullBaseVault } from "../../src/base/CredbullBaseVault.sol"; - -contract WindowPlugInTest is Test { - WindowVaultMock private vault; - - CredbullBaseVault.BaseVaultParams private vaultParams; - WindowPlugIn.WindowVaultParams private windowParams; + +import { HelperConfig } from "@script/HelperConfig.s.sol"; + +import { Vault } from "@credbull/vault/Vault.sol"; +import { WindowPlugin } from "@credbull/plugin/WindowPlugin.sol"; + +import { SimpleUSDC } from "@test/test/token/SimpleUSDC.t.sol"; +import { SimpleWindowVault } from "@test/test/vault/SimpleWindowVault.t.sol"; +import { ParamsFactory } from "@test/test/vault/utils/ParamsFactory.t.sol"; + +contract WindowPluginTest is Test { + SimpleWindowVault private vault; + + Vault.VaultParams private vaultParams; + WindowPlugin.WindowPluginParams private windowParams; HelperConfig private helperConfig; address private alice = makeAddr("alice"); @@ -25,14 +28,15 @@ contract WindowPlugInTest is Test { function setUp() public { helperConfig = new HelperConfig(true); - vaultParams = new HelperVaultTest(helperConfig.getNetworkConfig()).createBaseVaultTestParams(); - windowParams = new HelperVaultTest(helperConfig.getNetworkConfig()).createWindowVaultParams(); + ParamsFactory pf = new ParamsFactory(helperConfig.getNetworkConfig()); + vaultParams = pf.createVaultParams(); + windowParams = pf.createWindowPluginParams(); - vault = new WindowVaultMock(vaultParams, windowParams); - precision = 10 ** MockStablecoin(address(vaultParams.asset)).decimals(); + vault = new SimpleWindowVault(vaultParams, windowParams); + precision = 10 ** SimpleUSDC(address(vaultParams.asset)).decimals(); - MockStablecoin(address(vaultParams.asset)).mint(alice, INITIAL_BALANCE * precision); - MockStablecoin(address(vaultParams.asset)).mint(bob, INITIAL_BALANCE * precision); + SimpleUSDC(address(vaultParams.asset)).mint(alice, INITIAL_BALANCE * precision); + SimpleUSDC(address(vaultParams.asset)).mint(bob, INITIAL_BALANCE * precision); } function test__WindowVault__RevertDepositIfBehindWindow() public { @@ -45,7 +49,7 @@ contract WindowPlugInTest is Test { vaultParams.asset.approve(address(vault), 10 * precision); vm.expectRevert( abi.encodeWithSelector( - WindowPlugIn.CredbullVault__OperationOutsideRequiredWindow.selector, + WindowPlugin.CredbullVault__OperationOutsideRequiredWindow.selector, windowParams.depositWindow.opensAt, windowParams.depositWindow.closesAt, block.timestamp @@ -64,7 +68,7 @@ contract WindowPlugInTest is Test { vaultParams.asset.approve(address(vault), 10 * precision); vm.expectRevert( abi.encodeWithSelector( - WindowPlugIn.CredbullVault__OperationOutsideRequiredWindow.selector, + WindowPlugin.CredbullVault__OperationOutsideRequiredWindow.selector, windowParams.depositWindow.opensAt, windowParams.depositWindow.closesAt, block.timestamp @@ -87,15 +91,15 @@ contract WindowPlugInTest is Test { vm.startPrank(alice); // given that the vault's redemption window is in the past - vm.warp(windowParams.matureWindow.closesAt + 1); + vm.warp(windowParams.redemptionWindow.closesAt + 1); // when Alice try to redeem 10 * precision // then the redemption should be reverted vm.expectRevert( abi.encodeWithSelector( - WindowPlugIn.CredbullVault__OperationOutsideRequiredWindow.selector, - windowParams.matureWindow.opensAt, - windowParams.matureWindow.closesAt, + WindowPlugin.CredbullVault__OperationOutsideRequiredWindow.selector, + windowParams.redemptionWindow.opensAt, + windowParams.redemptionWindow.closesAt, block.timestamp ) ); @@ -107,14 +111,14 @@ contract WindowPlugInTest is Test { uint256 shares = deposit(alice, 10 * precision); assertEq(vault.balanceOf(alice), 10 * precision); - MockStablecoin token = MockStablecoin(address(vaultParams.asset)); + SimpleUSDC token = SimpleUSDC(address(vaultParams.asset)); token.mint(address(vault), 10 * precision); vm.startPrank(alice); // given that the vault's redemption window is in the future // when Alice try to redeem 10 * precision // then the redemption should be reverted - vm.warp(windowParams.matureWindow.opensAt + 1); + vm.warp(windowParams.redemptionWindow.opensAt + 1); vault.redeem(shares, alice, alice); vm.stopPrank(); assertEq(vault.balanceOf(alice), 0); @@ -128,9 +132,9 @@ contract WindowPlugInTest is Test { // then the redemption should be reverted vm.expectRevert( abi.encodeWithSelector( - WindowPlugIn.CredbullVault__OperationOutsideRequiredWindow.selector, - windowParams.matureWindow.opensAt, - windowParams.matureWindow.closesAt, + WindowPlugin.CredbullVault__OperationOutsideRequiredWindow.selector, + windowParams.redemptionWindow.opensAt, + windowParams.redemptionWindow.closesAt, block.timestamp ) ); @@ -145,7 +149,7 @@ contract WindowPlugInTest is Test { assertEq(vault.balanceOf(alice), 10 * precision); } - function test__WindowVault__ShouldToggleWhitelist() public { + function test__WindowVault__ShouldToggleWhiteList() public { bool beforeToggle = vault.checkWindow(); vault.toggleWindowCheck(!beforeToggle); bool afterToggle = vault.checkWindow(); diff --git a/packages/contracts/test/extensions/MaturityVaultTest.t.sol b/packages/contracts/test/src/vault/MaturityVaultTest.t.sol similarity index 58% rename from packages/contracts/test/extensions/MaturityVaultTest.t.sol rename to packages/contracts/test/src/vault/MaturityVaultTest.t.sol index b6989fc8d..f7480dfc3 100644 --- a/packages/contracts/test/extensions/MaturityVaultTest.t.sol +++ b/packages/contracts/test/src/vault/MaturityVaultTest.t.sol @@ -3,15 +3,17 @@ pragma solidity ^0.8.19; import { Test } from "forge-std/Test.sol"; -import { HelperVaultTest } from "../base/HelperVaultTest.t.sol"; -import { MaturityVaultMock } from "../mocks/vaults/MaturityVaultMock.m.sol"; -import { HelperConfig } from "../../script/HelperConfig.s.sol"; -import { MockStablecoin } from "../mocks/MockStablecoin.sol"; -import { MaturityVault } from "../../src/extensions/MaturityVault.sol"; -import { HelperVaultTest } from "../base/HelperVaultTest.t.sol"; + +import { HelperConfig } from "@script/HelperConfig.s.sol"; + +import { MaturityVault } from "@credbull/vault/MaturityVault.sol"; + +import { SimpleMaturityVault } from "@test/test/vault/SimpleMaturityVault.t.sol"; +import { SimpleUSDC } from "@test/test/token/SimpleUSDC.t.sol"; +import { ParamsFactory } from "@test/test/vault/utils/ParamsFactory.t.sol"; contract MaturityVaultTest is Test { - MaturityVaultMock private vault; + SimpleMaturityVault private vault; MaturityVault.MaturityVaultParams private params; HelperConfig private helperConfig; @@ -24,13 +26,13 @@ contract MaturityVaultTest is Test { function setUp() public { helperConfig = new HelperConfig(true); - params = new HelperVaultTest(helperConfig.getNetworkConfig()).createMaturityVaultTestParams(); + params = new ParamsFactory(helperConfig.getNetworkConfig()).createMaturityVaultParams(); - vault = new MaturityVaultMock(params); - precision = 10 ** MockStablecoin(address(params.baseVaultParams.asset)).decimals(); + vault = new SimpleMaturityVault(params); + precision = 10 ** SimpleUSDC(address(params.vault.asset)).decimals(); - MockStablecoin(address(params.baseVaultParams.asset)).mint(alice, INITIAL_BALANCE * precision); - MockStablecoin(address(params.baseVaultParams.asset)).mint(bob, INITIAL_BALANCE * precision); + SimpleUSDC(address(params.vault.asset)).mint(alice, INITIAL_BALANCE * precision); + SimpleUSDC(address(params.vault.asset)).mint(bob, INITIAL_BALANCE * precision); } function test__MaturityVault__WithdrawAssetAndBurnShares() public { @@ -40,23 +42,22 @@ contract MaturityVaultTest is Test { uint256 shares = deposit(alice, depositAmount); // ----- Setup Part 2 - Deposit asset from custodian vault with 10% addition yeild ---- // - MockStablecoin(address(params.baseVaultParams.asset)).mint(params.baseVaultParams.custodian, 1 * precision); - uint256 finalBalance = - MockStablecoin(address(params.baseVaultParams.asset)).balanceOf(params.baseVaultParams.custodian); + SimpleUSDC(address(params.vault.asset)).mint(params.vault.custodian, 1 * precision); + uint256 finalBalance = SimpleUSDC(address(params.vault.asset)).balanceOf(params.vault.custodian); - vm.startPrank(params.baseVaultParams.custodian); - params.baseVaultParams.asset.approve(params.baseVaultParams.custodian, finalBalance); - params.baseVaultParams.asset.transferFrom(params.baseVaultParams.custodian, address(vault), finalBalance); + vm.startPrank(params.vault.custodian); + params.vault.asset.approve(params.vault.custodian, finalBalance); + params.vault.asset.transferFrom(params.vault.custodian, address(vault), finalBalance); vm.stopPrank(); vault.mature(); // ---- Assert Vault burns shares and Alice receive asset with additional 10% --- - uint256 balanceBeforeRedeem = params.baseVaultParams.asset.balanceOf(alice); + uint256 balanceBeforeRedeem = params.vault.asset.balanceOf(alice); vm.startPrank(alice); vault.approve(address(vault), shares); uint256 assets = vault.redeem(shares, alice, alice); - uint256 balanceAfterRedeem = params.baseVaultParams.asset.balanceOf(alice); + uint256 balanceAfterRedeem = params.vault.asset.balanceOf(alice); vm.stopPrank(); assertEq(balanceAfterRedeem, balanceBeforeRedeem + assets, "Alice should recieve finalBalance with 10% yeild"); @@ -80,16 +81,16 @@ contract MaturityVaultTest is Test { // ---- Setup Part 1 - Deposit Assets to the vault ---- // uint256 depositAmount = 10 * precision; deposit(alice, depositAmount); - uint256 finalBalance = depositAmount; - // ---- Transfer assets to vault --- - vm.startPrank(params.baseVaultParams.custodian); - params.baseVaultParams.asset.approve(params.baseVaultParams.custodian, finalBalance); - params.baseVaultParams.asset.transferFrom(params.baseVaultParams.custodian, address(vault), finalBalance); + // ---- Transfer fewer assets to vault (arbitrarily use half the assets) --- + uint256 finalBalance = depositAmount / 2; + vm.startPrank(params.vault.custodian); + params.vault.asset.approve(params.vault.custodian, finalBalance); + params.vault.asset.transferFrom(params.vault.custodian, address(vault), finalBalance); vm.stopPrank(); // ---- Assert it can't be matured yet --- - // vm.prank(params.contractRoles.operator); + // vm.prank(params.roles.operator); vm.expectRevert(MaturityVault.CredbullVault__NotEnoughBalanceToMature.selector); vault.mature(); } @@ -98,17 +99,16 @@ contract MaturityVaultTest is Test { uint256 depositAmount = 10 * precision; deposit(alice, depositAmount); - uint256 expectedAssetVaulue = ((depositAmount * (100 + params.promisedYield)) / 100); - - assertEq(vault.expectedAssetsOnMaturity(), expectedAssetVaulue); + uint256 expectedAssetValue = depositAmount; + assertEq(vault.expectedAssetsOnMaturity(), expectedAssetValue); } function test__MaturityVault__ShouldNotRevertOnMaturityModifier() public { uint256 depositAmount = 10 * precision; uint256 shares = deposit(alice, depositAmount); - vm.prank(params.baseVaultParams.custodian); - params.baseVaultParams.asset.transfer(address(vault), depositAmount); + vm.prank(params.vault.custodian); + params.vault.asset.transfer(address(vault), depositAmount); vm.startPrank(alice); vault.approve(address(vault), shares); @@ -116,7 +116,7 @@ contract MaturityVaultTest is Test { vault.toogleMaturityCheck(false); vault.redeem(shares, alice, alice); - assertEq(params.baseVaultParams.asset.balanceOf(alice), INITIAL_BALANCE * precision); + assertEq(params.vault.asset.balanceOf(alice), INITIAL_BALANCE * precision); vm.stopPrank(); } @@ -130,7 +130,7 @@ contract MaturityVaultTest is Test { function deposit(address user, uint256 assets) internal returns (uint256 shares) { // first, approve the deposit vm.startPrank(user); - params.baseVaultParams.asset.approve(address(vault), assets); + params.vault.asset.approve(address(vault), assets); shares = vault.deposit(assets, user); vm.stopPrank(); diff --git a/packages/contracts/test/base/CredbullBaseVaultTest.t.sol b/packages/contracts/test/src/vault/VaultTest.t.sol similarity index 71% rename from packages/contracts/test/base/CredbullBaseVaultTest.t.sol rename to packages/contracts/test/src/vault/VaultTest.t.sol index 1c2e91b6c..713bd3a9e 100644 --- a/packages/contracts/test/base/CredbullBaseVaultTest.t.sol +++ b/packages/contracts/test/src/vault/VaultTest.t.sol @@ -3,22 +3,26 @@ pragma solidity ^0.8.19; import { Test } from "forge-std/Test.sol"; -import { HelperVaultTest } from "./HelperVaultTest.t.sol"; -import { CredbullBaseVaultMock } from "../mocks/vaults/CredbullBaseVaultMock.m.sol"; -import { HelperConfig } from "../../script/HelperConfig.s.sol"; -import { MockStablecoin } from "../mocks/MockStablecoin.sol"; -import { CredbullBaseVault } from "../../src/base/CredbullBaseVault.sol"; -import { Math } from "@openzeppelin/contracts/utils/math/Math.sol"; + import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; -import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol"; +import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import { Math } from "@openzeppelin/contracts/utils/math/Math.sol"; + +import { HelperConfig } from "@script/HelperConfig.s.sol"; + +import { Vault } from "@credbull/vault/Vault.sol"; + +import { SimpleUSDC } from "@test/test/token/SimpleUSDC.t.sol"; +import { SimpleVault } from "@test/test/vault/SimpleVault.t.sol"; +import { ParamsFactory } from "@test/test/vault/utils/ParamsFactory.t.sol"; -contract CredbullBaseVaultTest is Test { +contract VaultTest is Test { using Math for uint256; - CredbullBaseVaultMock private vault; + SimpleVault private vault; HelperConfig private helperConfig; - CredbullBaseVault.BaseVaultParams private vaultParams; + Vault.VaultParams private vaultParams; address private alice = makeAddr("alice"); address private bob = makeAddr("bob"); @@ -30,44 +34,56 @@ contract CredbullBaseVaultTest is Test { function setUp() public { helperConfig = new HelperConfig(true); - vaultParams = new HelperVaultTest(helperConfig.getNetworkConfig()).createBaseVaultTestParams(); + vaultParams = new ParamsFactory(helperConfig.getNetworkConfig()).createVaultParams(); - vault = createBaseVaultMock(vaultParams); - precision = 10 ** MockStablecoin(address(vaultParams.asset)).decimals(); + vault = createTestVault(vaultParams); + precision = 10 ** SimpleUSDC(address(vaultParams.asset)).decimals(); - MockStablecoin(address(vaultParams.asset)).mint(alice, INITIAL_BALANCE * precision); - MockStablecoin(address(vaultParams.asset)).mint(bob, INITIAL_BALANCE * precision); + SimpleUSDC(address(vaultParams.asset)).mint(alice, INITIAL_BALANCE * precision); + SimpleUSDC(address(vaultParams.asset)).mint(bob, INITIAL_BALANCE * precision); } - function test__BaseVault__ShareNameAndSymbol() public view { + function test__Vault__ShareNameAndSymbol() public view { assertEq(vault.name(), vaultParams.shareName); assertEq(vault.symbol(), vaultParams.shareSymbol); } - function test__BaseVault__CustodianAddress() public view { + function test__Vault__CustodianAddress() public view { assertEq(vault.CUSTODIAN(), vaultParams.custodian); } - function test__BaseVault__ShouldRevertOnInvalidAsset() public { + function test__Vault__ShouldRevertOnInvalidAsset() public { address zeroAddress = address(0); - vm.expectRevert(abi.encodeWithSelector(CredbullBaseVault.CredbullVault__InvalidAsset.selector, zeroAddress)); - new CredbullBaseVaultMock(IERC20(zeroAddress), "Test", "test", vaultParams.custodian); + vm.expectRevert(abi.encodeWithSelector(Vault.CredbullVault__InvalidAsset.selector, zeroAddress)); + new SimpleVault( + Vault.VaultParams({ + asset: IERC20(zeroAddress), + shareName: "Test", + shareSymbol: "test", + custodian: vaultParams.custodian + }) + ); } - function test__BaseVault__ShouldRevertOnInvalidCustodianAddress() public { + function test__Vault__ShouldRevertOnInvalidCustodianAddress() public { address zeroAddress = address(0); - vm.expectRevert( - abi.encodeWithSelector(CredbullBaseVault.CredbullVault__InvalidCustodianAddress.selector, zeroAddress) + vm.expectRevert(abi.encodeWithSelector(Vault.CredbullVault__InvalidCustodianAddress.selector, zeroAddress)); + new SimpleVault( + Vault.VaultParams({ + asset: vaultParams.asset, + shareName: "Test", + shareSymbol: "test", + custodian: zeroAddress + }) ); - new CredbullBaseVaultMock(vaultParams.asset, "Test", "test", zeroAddress); } - function test__BaseVault__ShouldReturnCorrectDecimalValue() public view { - assertEq(vault.decimals(), MockStablecoin(address(vaultParams.asset)).decimals()); + function test__Vault__ShouldReturnCorrectDecimalValue() public view { + assertEq(vault.decimals(), SimpleUSDC(address(vaultParams.asset)).decimals()); } - function test__BaseVault__DepositAssetsAndGetShares() public { + function test__Vault__DepositAssetsAndGetShares() public { uint256 custodiansBalance = vaultParams.asset.balanceOf(vaultParams.custodian); // ---- Setup Part 1, Check balance before deposit ---- @@ -95,15 +111,15 @@ contract CredbullBaseVaultTest is Test { assertEq(vault.balanceOf(alice), depositAmount, "User should now have the Shares"); } - function test__BaseVault__WithdrawAssetAndBurnShares() public { + function test__Vault__WithdrawAssetAndBurnShares() public { // ---- Setup Part 1 - Deposit Assets to the vault ---- // uint256 depositAmount = 10 * precision; //Call internal deposit function uint256 shares = deposit(alice, depositAmount); // ----- Setup Part 2 - Deposit asset from custodian vault with 10% addition yeild ---- // - MockStablecoin(address(vaultParams.asset)).mint(vaultParams.custodian, 1 * precision); - uint256 finalBalance = MockStablecoin(address(vaultParams.asset)).balanceOf(vaultParams.custodian); + SimpleUSDC(address(vaultParams.asset)).mint(vaultParams.custodian, 1 * precision); + uint256 finalBalance = SimpleUSDC(address(vaultParams.asset)).balanceOf(vaultParams.custodian); vm.prank(vaultParams.custodian); vaultParams.asset.transfer(address(vault), finalBalance); @@ -119,7 +135,7 @@ contract CredbullBaseVaultTest is Test { assertEq(balanceAfterRedeem, balanceBeforeRedeem + assets, "Alice should recieve finalBalance with 10% yeild"); } - function test__BaseVault__totalAssetShouldReturnTotalDeposited() public { + function test__Vault__totalAssetShouldReturnTotalDeposited() public { uint256 depositAmount = 10 * precision; //Call internal deposit function deposit(alice, depositAmount); @@ -128,29 +144,25 @@ contract CredbullBaseVaultTest is Test { assertEq(vault.totalAssetDeposited(), depositAmount); } - function test__BaseVault__ShouldRevertOnTransferOutsideEcosystem() public { + function test__Vault__ShouldRevertOnTransferOutsideEcosystem() public { uint256 depositAmount = 100 * precision; deposit(alice, depositAmount); vm.prank(alice); - vm.expectRevert( - abi.encodeWithSelector(CredbullBaseVault.CredbullVault__TransferOutsideEcosystem.selector, address(alice)) - ); + vm.expectRevert(abi.encodeWithSelector(Vault.CredbullVault__TransferOutsideEcosystem.selector, address(alice))); vault.transfer(bob, 100 * precision); } - function test__BaseVault__ShouldRevertOnNativeTokenTransfer() public { - vm.expectRevert(CredbullBaseVault.CredbullVault__TransferOutsideEcosystem.selector); + function test__Vault__ShouldRevertOnNativeTokenTransfer() public { (bool isReceivedSuccess,) = address(vault).call{ value: 5 wei }(""); assertFalse(isReceivedSuccess, "Should fail: receive function is not allowed to accept Native tokens."); - vm.expectRevert(CredbullBaseVault.CredbullVault__TransferOutsideEcosystem.selector); (bool isFallbackSuccess,) = address(vault).call{ value: 8 wei }(abi.encodeWithSignature("nonExistentFunction()")); assertFalse(isFallbackSuccess, "Should fail: fallback function is not allowed to accept Native tokens."); } - function test__BaseVault__ShouldRevertOnFractionalDepositAmount_Fuzz(uint256 depositAmount) public { + function test__Vault__ShouldRevertOnFractionalDepositAmount_Fuzz(uint256 depositAmount) public { depositAmount = bound(depositAmount, 1, 1e6 * 1e6); if ((depositAmount % precision) > 0) { @@ -161,12 +173,12 @@ contract CredbullBaseVaultTest is Test { } function test__ShouldRevertIfDecimalIsNotSupported() public { - vm.expectRevert(abi.encodeWithSelector(CredbullBaseVault.CredbullVault__UnsupportedDecimalValue.selector, 24)); + vm.expectRevert(abi.encodeWithSelector(Vault.CredbullVault__UnsupportedDecimalValue.selector, 24)); vm.mockCall(address(vaultParams.asset), abi.encodeWithSelector(ERC20.decimals.selector), abi.encode(24)); - createBaseVaultMock(vaultParams); + createTestVault(vaultParams); } - function test__BaseVault__Deposit__Fuzz(uint256 depositAmount) public { + function test__Vault__Deposit__Fuzz(uint256 depositAmount) public { uint256 custodiansBalance = vaultParams.asset.balanceOf(vaultParams.custodian); // ---- Setup Part 1, Check balance before deposit ---- @@ -199,9 +211,7 @@ contract CredbullBaseVaultTest is Test { } } - function test__BaseVault__MultiDepositAndWithdraw__Fuzz(uint256 aliceDepositAmount, uint256 bobDepositAmount) - public - { + function test__Vault__MultiDepositAndWithdraw__Fuzz(uint256 aliceDepositAmount, uint256 bobDepositAmount) public { uint256 custodiansBalance = vaultParams.asset.balanceOf(vaultParams.custodian); // ---- Setup Part 1, Check balance before deposit ---- @@ -249,10 +259,10 @@ contract CredbullBaseVaultTest is Test { assertEq(vault.balanceOf(bob), bobShares, "Bob should now have the Shares"); // ----- Setup Part 2 - Deposit asset from custodian vault with 10% addition yeild ---- // - MockStablecoin(address(vaultParams.asset)).mint( + SimpleUSDC(address(vaultParams.asset)).mint( vaultParams.custodian, totalDepositAmount.mulDiv(10_00, MAX_PERCENTAGE) ); - uint256 finalBalance = MockStablecoin(address(vaultParams.asset)).balanceOf(vaultParams.custodian); + uint256 finalBalance = SimpleUSDC(address(vaultParams.asset)).balanceOf(vaultParams.custodian); vm.prank(vaultParams.custodian); vaultParams.asset.transfer(address(vault), finalBalance); @@ -288,16 +298,14 @@ contract CredbullBaseVaultTest is Test { } } - function test__BaseVault__WithdrawOnBehalfOf() public { + function test__Vault__WithdrawOnBehalfOf() public { uint256 depositAmount = 10 * precision; //Call internal deposit function uint256 shares = deposit(alice, depositAmount); // ----- Setup Part 2 - Deposit asset from custodian vault with 10% addition yeild ---- // - MockStablecoin(address(vaultParams.asset)).mint( - vaultParams.custodian, depositAmount.mulDiv(10_00, MAX_PERCENTAGE) - ); - uint256 finalBalance = MockStablecoin(address(vaultParams.asset)).balanceOf(vaultParams.custodian); + SimpleUSDC(address(vaultParams.asset)).mint(vaultParams.custodian, depositAmount.mulDiv(10_00, MAX_PERCENTAGE)); + uint256 finalBalance = SimpleUSDC(address(vaultParams.asset)).balanceOf(vaultParams.custodian); vm.prank(vaultParams.custodian); vaultParams.asset.transfer(address(vault), finalBalance); @@ -311,9 +319,9 @@ contract CredbullBaseVaultTest is Test { vault.redeem(shares, alice, alice); } - function test__BaseVault__WithdrawERC20() public { - MockStablecoin mock1 = new MockStablecoin(100 * precision); - MockStablecoin mock2 = new MockStablecoin(100 * precision); + function test__Vault__WithdrawERC20() public { + SimpleUSDC mock1 = new SimpleUSDC(100 * precision); + SimpleUSDC mock2 = new SimpleUSDC(100 * precision); mock1.mint(address(vault), 100 * precision); mock2.mint(address(vault), 100 * precision); @@ -328,7 +336,7 @@ contract CredbullBaseVaultTest is Test { assertEq(mock2.balanceOf(alice), 100 * precision); } - function test__BaseVault__ShouldRevertOnSendingETHToVault() public { + function test__Vault__ShouldRevertOnSendingETHToVault() public { (bool isReceivedSuccess,) = address(vault).call{ value: 5 wei }(""); assertFalse(isReceivedSuccess, "Should fail: receive function is not allowed to accept Native tokens."); @@ -337,16 +345,12 @@ contract CredbullBaseVaultTest is Test { assertFalse(isFallbackSuccess, "Should fail: fallback function is not allowed to accept Native tokens."); } - function test__BaseVault__ShouldRevertAllTransfers() public { - vm.expectRevert( - abi.encodeWithSelector(CredbullBaseVault.CredbullVault__TransferOutsideEcosystem.selector, address(alice)) - ); + function test__Vault__ShouldRevertAllTransfers() public { + vm.expectRevert(abi.encodeWithSelector(Vault.CredbullVault__TransferOutsideEcosystem.selector, address(alice))); vm.prank(alice); vault.transfer(bob, 100 * precision); - vm.expectRevert( - abi.encodeWithSelector(CredbullBaseVault.CredbullVault__TransferOutsideEcosystem.selector, alice) - ); + vm.expectRevert(abi.encodeWithSelector(Vault.CredbullVault__TransferOutsideEcosystem.selector, alice)); vm.prank(alice); vault.transferFrom(alice, bob, 100 * precision); } @@ -363,17 +367,12 @@ contract CredbullBaseVaultTest is Test { function depositWithRevert(address user, uint256 assets) internal returns (uint256 shares) { vm.startPrank(user); vaultParams.asset.approve(address(vault), assets); - vm.expectRevert(abi.encodeWithSelector(CredbullBaseVault.CredbullVault__InvalidAssetAmount.selector, assets)); + vm.expectRevert(abi.encodeWithSelector(Vault.CredbullVault__InvalidAssetAmount.selector, assets)); shares = vault.deposit(assets, alice); vm.stopPrank(); } - function createBaseVaultMock(CredbullBaseVault.BaseVaultParams memory _vaultParams) - internal - returns (CredbullBaseVaultMock) - { - return new CredbullBaseVaultMock( - _vaultParams.asset, _vaultParams.shareName, _vaultParams.shareSymbol, _vaultParams.custodian - ); + function createTestVault(Vault.VaultParams memory _vaultParams) internal returns (SimpleVault) { + return new SimpleVault(_vaultParams); } } diff --git a/packages/contracts/test/test/token/DecimalToken.t.sol b/packages/contracts/test/test/token/DecimalToken.t.sol new file mode 100644 index 000000000..54f28b0a1 --- /dev/null +++ b/packages/contracts/test/test/token/DecimalToken.t.sol @@ -0,0 +1,22 @@ +// SDPX-License-Identifier: MIT + +pragma solidity ^0.8.19; + +import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; + +import { OwnableToken } from "./OwnableToken.t.sol"; + +/** + * @notice A simple [ERC20] Token, with configurable `decimals` value. + * @dev The Symbol and Name computed based on `_decimals`. + */ +contract DecimalToken is OwnableToken { + constructor(uint256 initialSupply, uint8 _decimals) + OwnableToken( + string.concat("Decimal ", Strings.toString(_decimals), " Token"), + string.concat("DT", Strings.toString(_decimals)), + _decimals, + initialSupply + ) + { } +} diff --git a/packages/contracts/test/test/token/OwnableToken.t.sol b/packages/contracts/test/test/token/OwnableToken.t.sol new file mode 100755 index 000000000..f569c5994 --- /dev/null +++ b/packages/contracts/test/test/token/OwnableToken.t.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; + +/** + * @notice A configurable [ERC20] Token that is [Ownable]. The `initialSupply` is minted to `msg.sender` on + * construction. + * + * @dev All testing [ERC20] tokens should extend this token, with reasonable default value where appropriate. + */ +contract OwnableToken is ERC20, Ownable { + uint8 private tokenDecimals; + + constructor(string memory _name, string memory _symbol, uint8 _decimals, uint256 initialSupply) + ERC20(_name, _symbol) + Ownable(msg.sender) + { + tokenDecimals = _decimals; + + _mint(msg.sender, initialSupply); + } + + function decimals() public view override returns (uint8) { + return tokenDecimals; + } + + function mint(address to, uint256 amount) public { + _mint(to, amount); + } +} diff --git a/packages/contracts/test/test/token/SimpleToken.t.sol b/packages/contracts/test/test/token/SimpleToken.t.sol new file mode 100755 index 000000000..7f034a836 --- /dev/null +++ b/packages/contracts/test/test/token/SimpleToken.t.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import { OwnableToken } from "./OwnableToken.t.sol"; + +/** + * @notice A simple [ERC20] Token. + * @dev The Symbol, Name and decimals are hard-coded, so an instance cannot represent anything other than 'SMPL'. + */ +contract SimpleToken is OwnableToken { + constructor(uint256 initialSupply) OwnableToken("Simple Token", "SMPL", 18, initialSupply) { } +} diff --git a/packages/contracts/test/test/token/SimpleUSDC.t.sol b/packages/contracts/test/test/token/SimpleUSDC.t.sol new file mode 100755 index 000000000..a4d4420a8 --- /dev/null +++ b/packages/contracts/test/test/token/SimpleUSDC.t.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import { OwnableToken } from "./OwnableToken.t.sol"; + +/** + * @notice A simple [ERC20] Token, used to mimic USDC in tests. + * @dev The Symbol, Name and decimals are hard-coded, so an instance cannot represent anything other than 'sUSDC'. + */ +contract SimpleUSDC is OwnableToken { + constructor(uint256 initialSupply) OwnableToken("Simple USDC", "sUSDC", 6, initialSupply) { } +} diff --git a/packages/contracts/test/test/vault/SimpleMaturityVault.t.sol b/packages/contracts/test/test/vault/SimpleMaturityVault.t.sol new file mode 100644 index 000000000..d70a24af7 --- /dev/null +++ b/packages/contracts/test/test/vault/SimpleMaturityVault.t.sol @@ -0,0 +1,23 @@ +//SPDX-License-Identifier: MIT + +pragma solidity ^0.8.19; + +import { MaturityVault } from "@credbull/vault/MaturityVault.sol"; + +/** + * @notice A simple [MaturityVault] realisation for testing purposes. + */ +contract SimpleMaturityVault is MaturityVault { + constructor(MaturityVaultParams memory params) MaturityVault(params) { } + + modifier onWithdrawOrRedeem(address caller, address receiver, address owner, uint256 assets, uint256 shares) + override + { + _checkVaultMaturity(); + _; + } + + function toogleMaturityCheck(bool status) public { + _toggleMaturityCheck(status); + } +} diff --git a/packages/contracts/test/test/vault/SimpleMaxCapVault.t.sol b/packages/contracts/test/test/vault/SimpleMaxCapVault.t.sol new file mode 100644 index 000000000..a9c40c9e6 --- /dev/null +++ b/packages/contracts/test/test/vault/SimpleMaxCapVault.t.sol @@ -0,0 +1,30 @@ +//SPDX-License-Identifier: MIT + +pragma solidity ^0.8.19; + +import { MaxCapPlugin } from "@credbull/plugin/MaxCapPlugin.sol"; +import { Vault } from "@credbull/vault/Vault.sol"; + +/** + * @notice A simple [Vault] with [MaxCapPlugin] realisation, for testing purposes. + * @dev It could be called `MaxCapVault` as there is no name clash, but stuck with the naming convention. + */ +contract SimpleMaxCapVault is Vault, MaxCapPlugin { + constructor(VaultParams memory params, MaxCapPluginParams memory maxCapPluginParams) + Vault(params) + MaxCapPlugin(maxCapPluginParams) + { } + + modifier onDepositOrMint(address caller, address receiver, uint256 assets, uint256 shares) override { + _checkMaxCap(totalAssetDeposited + assets); + _; + } + + function toggleMaxCapCheck(bool status) public { + _toggleMaxCapCheck(status); + } + + function updateMaxCap(uint256 _value) public { + _updateMaxCap(_value); + } +} diff --git a/packages/contracts/test/test/vault/SimpleVault.t.sol b/packages/contracts/test/test/vault/SimpleVault.t.sol new file mode 100644 index 000000000..3f37f0c54 --- /dev/null +++ b/packages/contracts/test/test/vault/SimpleVault.t.sol @@ -0,0 +1,16 @@ +//SPDX-License-Identifier: MIT + +pragma solidity ^0.8.19; + +import { Vault } from "@credbull/vault/Vault.sol"; + +/** + * @notice A simple [Vault] realisation for testing purposes. + */ +contract SimpleVault is Vault { + constructor(Vault.VaultParams memory params) Vault(params) { } + + function withdrawERC20(address[] calldata _tokens, address _to) external { + _withdrawERC20(_tokens, _to); + } +} diff --git a/packages/contracts/test/test/vault/SimpleWhiteListVault.t.sol b/packages/contracts/test/test/vault/SimpleWhiteListVault.t.sol new file mode 100644 index 000000000..ee6208e00 --- /dev/null +++ b/packages/contracts/test/test/vault/SimpleWhiteListVault.t.sol @@ -0,0 +1,26 @@ +//SPDX-License-Identifier: MIT + +pragma solidity ^0.8.19; + +import { Vault } from "@credbull/vault/Vault.sol"; +import { WhiteListPlugin } from "@credbull/plugin/WhiteListPlugin.sol"; + +/** + * @notice A simple [Vault] with [WhiteListPlugin] realisation, for testing purposes. + * @dev It could be called `WhiteListVault` as there is no name clash, but stuck with the naming convention. + */ +contract SimpleWhiteListVault is Vault, WhiteListPlugin { + constructor(VaultParams memory params, WhiteListPluginParams memory whiteListPluginParams) + Vault(params) + WhiteListPlugin(whiteListPluginParams) + { } + + modifier onDepositOrMint(address caller, address receiver, uint256 assets, uint256 shares) override { + _checkIsWhiteListed(receiver, assets); + _; + } + + function toggleWhiteListCheck(bool status) public { + _toggleWhiteListCheck(status); + } +} diff --git a/packages/contracts/test/test/vault/SimpleWindowVault.t.sol b/packages/contracts/test/test/vault/SimpleWindowVault.t.sol new file mode 100644 index 000000000..2e0d122e5 --- /dev/null +++ b/packages/contracts/test/test/vault/SimpleWindowVault.t.sol @@ -0,0 +1,39 @@ +//SPDX-License-Identifier: MIT + +pragma solidity ^0.8.19; + +import { Vault } from "@credbull/vault/Vault.sol"; +import { WindowPlugin } from "@credbull/plugin/WindowPlugin.sol"; + +/** + * @notice A simple [Vault] with [WindowPlugin] realisation, for testing purposes. + * @dev It could be called `WindowVault` as there is no name clash, but stuck with the naming convention. + */ +contract SimpleWindowVault is Vault, WindowPlugin { + constructor(VaultParams memory params, WindowPluginParams memory windowPluginParams) + Vault(params) + WindowPlugin(windowPluginParams) + { } + + modifier onDepositOrMint(address caller, address receiver, uint256 assets, uint256 shares) override { + _checkIsDepositWithinWindow(); + _; + } + + modifier onWithdrawOrRedeem(address caller, address receiver, address owner, uint256 assets, uint256 shares) + override + { + _checkIsRedeemWithinWindow(); + _; + } + + function updateWindow(uint256 _depositOpen, uint256 _depositClose, uint256 _withdrawOpen, uint256 _withdrawClose) + public + { + _updateWindow(_depositOpen, _depositClose, _withdrawOpen, _withdrawClose); + } + + function toggleWindowCheck(bool status) public { + _toggleWindowCheck(status); + } +} diff --git a/packages/contracts/test/test/vault/utils/ParamsFactory.t.sol b/packages/contracts/test/test/vault/utils/ParamsFactory.t.sol new file mode 100644 index 000000000..2305cdcc1 --- /dev/null +++ b/packages/contracts/test/test/vault/utils/ParamsFactory.t.sol @@ -0,0 +1,92 @@ +//SPDX-License-Identifier: MIT + +pragma solidity ^0.8.19; + +import { Test } from "forge-std/Test.sol"; + +import { NetworkConfig } from "@script/HelperConfig.s.sol"; + +import { MaxCapPlugin } from "@credbull/plugin/MaxCapPlugin.sol"; +import { WhiteListPlugin } from "@credbull/plugin/WhiteListPlugin.sol"; +import { WindowPlugin } from "@credbull/plugin/WindowPlugin.sol"; +import { UpsideVault } from "@credbull/vault/UpsideVault.sol"; +import { FixedYieldVault } from "@credbull/vault/FixedYieldVault.sol"; +import { MaturityVault } from "@credbull/vault/MaturityVault.sol"; +import { Vault } from "@credbull/vault/Vault.sol"; + +/** + * @notice A test utility for creating 'Params' instances for the various [Vault] types. + */ +contract ParamsFactory is Test { + uint256 private constant PROMISED_FIXED_YIELD = 10; + NetworkConfig private networkConfig; + + constructor(NetworkConfig memory _networkConfig) { + networkConfig = _networkConfig; + } + + function createVaultParams() public returns (Vault.VaultParams memory params) { + address custodian = makeAddr("custodianAddress"); + + params = Vault.VaultParams({ + asset: networkConfig.usdcToken, + shareName: "Share_sep", + shareSymbol: "SYM_sep", + custodian: custodian + }); + } + + function createUpsideVaultParams() public returns (UpsideVault.UpsideVaultParams memory params) { + params = UpsideVault.UpsideVaultParams({ + fixedYieldVault: createFixedYieldVaultParams(), + cblToken: networkConfig.cblToken, + collateralPercentage: 20_00 + }); + } + + function createFixedYieldVaultParams() public returns (FixedYieldVault.FixedYieldVaultParams memory params) { + params = FixedYieldVault.FixedYieldVaultParams({ + maturityVault: createMaturityVaultParams(), + roles: createContractRoles(), + windowPlugin: createWindowPluginParams(), + whiteListPlugin: createWhiteListPluginParams(), + maxCapPlugin: createMaxCapPluginParams(), + promisedYield: PROMISED_FIXED_YIELD + }); + } + + function createMaturityVaultParams() public returns (MaturityVault.MaturityVaultParams memory params) { + params = MaturityVault.MaturityVaultParams({ vault: createVaultParams() }); + } + + function createMaxCapPluginParams() public pure returns (MaxCapPlugin.MaxCapPluginParams memory params) { + params = MaxCapPlugin.MaxCapPluginParams({ maxCap: 1e6 * 1e6 }); + } + + function createWhiteListPluginParams() public returns (WhiteListPlugin.WhiteListPluginParams memory params) { + params = WhiteListPlugin.WhiteListPluginParams({ + whiteListProvider: makeAddr("whiteListProviderAddress"), + depositThresholdForWhiteListing: 1000e6 + }); + } + + function createWindowPluginParams() public view returns (WindowPlugin.WindowPluginParams memory params) { + uint256 opensAt = block.timestamp; + uint256 closesAt = opensAt + 7 days; + uint256 year = 365 days; + + WindowPlugin.Window memory depositWindow = WindowPlugin.Window({ opensAt: opensAt, closesAt: closesAt }); + WindowPlugin.Window memory redemptionWindow = + WindowPlugin.Window({ opensAt: opensAt + year, closesAt: closesAt + year }); + + params = WindowPlugin.WindowPluginParams({ depositWindow: depositWindow, redemptionWindow: redemptionWindow }); + } + + function createContractRoles() public returns (FixedYieldVault.ContractRoles memory roles) { + roles = FixedYieldVault.ContractRoles({ + owner: networkConfig.factoryParams.owner, + operator: networkConfig.factoryParams.operator, + custodian: makeAddr("custodianAddress") + }); + } +} diff --git a/packages/ops/src/create-vault.ts b/packages/ops/src/create-vault.ts index 017d0333b..8a7842265 100644 --- a/packages/ops/src/create-vault.ts +++ b/packages/ops/src/create-vault.ts @@ -1,4 +1,4 @@ -import { CredbullFixedYieldVault__factory, CredbullVaultFactory__factory } from '@credbull/contracts'; +import { CredbullFixedYieldVault__factory, VaultFactory__factory } from '@credbull/contracts'; import { FixedYieldVault } from '@credbull/contracts/types/CredbullFixedYieldVault'; import { MaturityVault } from '@credbull/contracts/types/CredbullFixedYieldVault'; import { UpsideVault } from '@credbull/contracts/types/CredbullFixedYieldVaultWithUpside'; @@ -24,7 +24,7 @@ function createParams( config: any, params: { custodian: string; - kycProvider?: string; + whiteListProvider?: string; asset?: string; token?: string; matured?: boolean; @@ -36,7 +36,7 @@ function createParams( const activityReward = config.evm.address.activity_reward; const collateralPercentage = config.operation.createVault.collateral_percentage; - const kycProvider = params.kycProvider; + const whiteListProvider = params.whiteListProvider; const custodian = params.custodian; const week = 604800; @@ -53,7 +53,7 @@ function createParams( { type: 'treasury', address: treasury, percentage: 0.8 }, { type: 'activity_reward', address: activityReward, percentage: 1 }, { type: 'custodian', address: custodian }, - { type: 'kyc_provider', address: kycProvider }, + { type: 'whitelist_provider', address: whiteListProvider }, ]; const entities = params.upside @@ -73,49 +73,49 @@ function createParams( redemptionOpensAt: redemptionDateAsTimestamp, redemptionClosesAt: redemptionDateAsTimestamp + week, custodian: params.custodian, - kycProvider: params.kycProvider || '', + whiteListProvider: params.whiteListProvider || '', maxCap: (1e6 * 1e6).toString(), - depositThresholdForWhitelisting: (1000e6).toString(), + depositThresholdForWhiteListing: (1000e6).toString(), }; const maturityVaultParams: MaturityVault.MaturityVaultParamsStruct = { - baseVaultParams: { + vault: { asset: tempParams.asset, shareName: tempParams.shareName, shareSymbol: tempParams.shareSymbol, custodian: tempParams.custodian, }, - promisedYield: tempParams.promisedYield, }; const fixedYieldVaultParams: FixedYieldVault.FixedYieldVaultParamsStruct = { - maturityVaultParams, - contractRoles: { + maturityVault: maturityVaultParams, + roles: { owner: tempParams.owner, operator: tempParams.operator, custodian: tempParams.custodian, }, - windowVaultParams: { + windowPlugin: { depositWindow: { opensAt: tempParams.depositOpensAt, closesAt: tempParams.depositClosesAt, }, - matureWindow: { + redemptionWindow: { opensAt: tempParams.redemptionOpensAt, closesAt: tempParams.redemptionClosesAt, }, }, - kycParams: { - kycProvider: tempParams.kycProvider, - depositThresholdForWhitelisting: tempParams.depositThresholdForWhitelisting, + whiteListPlugin: { + whiteListProvider: tempParams.whiteListProvider, + depositThresholdForWhiteListing: tempParams.depositThresholdForWhiteListing, }, - maxCapParams: { + maxCapPlugin: { maxCap: tempParams.maxCap, }, + promisedYield: tempParams.promisedYield, }; const upsideVaultParams: UpsideVault.UpsideVaultParamsStruct = { - fixedYieldVaultParams, + fixedYieldVault: fixedYieldVaultParams, cblToken: tempParams.token, collateralPercentage: collateralPercentage, }; @@ -204,18 +204,18 @@ export async function createVault( // TODO: this is the problem - the vaultFactory Admin (owner) is needed here // but later we call to createVault we should be using the operator - const vaultFactoryAsAdmin = CredbullVaultFactory__factory.connect(factoryAddress!, adminSigner); + const vaultFactoryAsAdmin = VaultFactory__factory.connect(factoryAddress!, adminSigner); const allowTx = await vaultFactoryAsAdmin.allowCustodian(custodian); await allowTx.wait(); console.log(` Allowed Custodian ${custodian} on ${expectedFactoryName} ${factoryAddress}`); - const kycProvider = addresses.data.find((i: any) => i.contract_name === 'CredbullKYCProvider')?.address; - const asset = addresses.data.find((i: any) => i.contract_name === 'MockStablecoin')?.address; - const token = addresses.data.find((i: any) => i.contract_name === 'MockToken')?.address; + const whiteListProvider = addresses.data.find((i: any) => i.contract_name === 'CredbullWhiteListProvider')?.address; + const asset = addresses.data.find((i: any) => i.contract_name === 'SimpleUSDC')?.address; + const token = addresses.data.find((i: any) => i.contract_name === 'SimpleToken')?.address; - const [vaultParams, createVaultParams, tempParams] = createParams(config, { + const [, createVaultParams, tempParams] = createParams(config, { custodian, - kycProvider, + whiteListProvider, asset, token, matured: isMatured, diff --git a/packages/ops/src/deposit-with-upside.ts b/packages/ops/src/deposit-with-upside.ts index 325fcf110..edf3bc13e 100644 --- a/packages/ops/src/deposit-with-upside.ts +++ b/packages/ops/src/deposit-with-upside.ts @@ -1,4 +1,4 @@ -import { MockStablecoin__factory, MockToken__factory } from '@credbull/contracts'; +import { SimpleToken__factory, SimpleUSDC__factory } from '@credbull/contracts'; import { parseUnits } from 'ethers/lib/utils'; import { whitelist } from './utils/admin'; @@ -67,7 +67,7 @@ export async function depositWithUpside(config: any): Promise { const depositAmount = parseUnits(toDeposit.toString(), await asset.decimals()); console.log(' Bob decides to mint his deposit amount of the Asset=', displayAsset(depositAmount)); - const mockUsdc = MockStablecoin__factory.connect(asset.address, userBob.signer); + const mockUsdc = SimpleUSDC__factory.connect(asset.address, userBob.signer); const mintAssetTx = await mockUsdc.mint(userBob.address, depositAmount); await mintAssetTx.wait(); await logBalances(); @@ -79,7 +79,7 @@ export async function depositWithUpside(config: any): Promise { const tokenAmount = parseUnits(toDeposit.toString(), await token.decimals()); console.log(' Bob decides to mint his deposit amount of Token=', displayToken(tokenAmount)); - const mockToken = MockToken__factory.connect(token.address, userBob.signer); + const mockToken = SimpleToken__factory.connect(token.address, userBob.signer); const mintTokenTx = await mockToken.mint(userBob.address, tokenAmount); await mintTokenTx.wait(); await logBalances(); diff --git a/packages/ops/src/deposit.ts b/packages/ops/src/deposit.ts index c75f68e12..77d060d30 100644 --- a/packages/ops/src/deposit.ts +++ b/packages/ops/src/deposit.ts @@ -1,4 +1,4 @@ -import { MockStablecoin__factory } from '@credbull/contracts'; +import { SimpleUSDC__factory } from '@credbull/contracts'; import { BigNumber } from 'ethers'; import { whitelist } from './utils/admin'; @@ -60,7 +60,7 @@ export async function deposit(config: any) { await logBalances(); const depositAmount = BigNumber.from(toDeposit).mul(10 ** (await asset.decimals())); - const mockUsdc = MockStablecoin__factory.connect(asset.address, userBob.signer); + const mockUsdc = SimpleUSDC__factory.connect(asset.address, userBob.signer); const mintTx = await mockUsdc.mint(userBob.address, depositAmount); await mintTx.wait(); console.log(' Bob buys (mints) his deposit amount of USDC=', displayAsset(depositAmount)); diff --git a/packages/ops/src/redeem-with-upside.ts b/packages/ops/src/redeem-with-upside.ts index 68502715d..f268aea4c 100644 --- a/packages/ops/src/redeem-with-upside.ts +++ b/packages/ops/src/redeem-with-upside.ts @@ -1,4 +1,4 @@ -import { MockStablecoin__factory } from '@credbull/contracts'; +import { SimpleUSDC__factory } from '@credbull/contracts'; import { formatUnits } from 'ethers/lib/utils'; import { loadConfiguration } from './utils/config'; @@ -55,7 +55,7 @@ export async function redeemWithUpside(config: any): Promise { console.log(' Bob decides to redeem all his Shares=', formatUnits(redeemAmount, await vault.decimals())); if (redeemAmount.lte(0)) throw new Error('No Shares to redeem.'); - const mockUsdc = MockStablecoin__factory.connect(asset.address, userBob.signer); + const mockUsdc = SimpleUSDC__factory.connect(asset.address, userBob.signer); const mintAssetTx = await mockUsdc.mint(vaultData.address, redeemAmount); await mintAssetTx.wait(); console.log(' Bob mints the redeem amount of Asset to the Vault=', displayAsset(redeemAmount)); diff --git a/packages/ops/src/redeem.ts b/packages/ops/src/redeem.ts index 83bf65e68..a95eab3d4 100644 --- a/packages/ops/src/redeem.ts +++ b/packages/ops/src/redeem.ts @@ -1,4 +1,4 @@ -import { MockStablecoin__factory } from '@credbull/contracts'; +import { SimpleUSDC__factory } from '@credbull/contracts'; import { formatUnits } from 'ethers/lib/utils'; import { loadConfiguration } from './utils/config'; @@ -50,10 +50,10 @@ export async function redeem(config: any): Promise { ); await logBalances(); - const mockUsdc = MockStablecoin__factory.connect(asset.address, userBob.signer); + const mockUsdc = SimpleUSDC__factory.connect(asset.address, userBob.signer); const mintTx = await mockUsdc.mint(vault.address, redeemAmount); await mintTx.wait(); - console.log(' Bob mints some USDC, using `MockStableCoin`, to the Vault. Minted=', displayAsset(redeemAmount)); + console.log(' Bob mints some USDC to the Vault. Minted=', displayAsset(redeemAmount)); await logBalances(); const approveTx = await vault.approve(vault.address, redeemAmount); diff --git a/packages/sdk/test/src/utils/contracts.ts b/packages/sdk/test/src/utils/contracts.ts index 521968d0e..9b1559a2b 100644 --- a/packages/sdk/test/src/utils/contracts.ts +++ b/packages/sdk/test/src/utils/contracts.ts @@ -1,8 +1,4 @@ -import { - CredbullFixedYieldVault, - CredbullFixedYieldVaultWithUpside, - MockStablecoin__factory, -} from '@credbull/contracts'; +import { CredbullFixedYieldVault, CredbullFixedYieldVaultWithUpside, SimpleUSDC__factory } from '@credbull/contracts'; import { BigNumber, ContractTransaction, Signer, ethers } from 'ethers'; import { User } from './user'; @@ -16,7 +12,7 @@ export async function __mockMint( signer: Signer | ethers.providers.Provider, ): Promise { return vault.asset().then(async (address) => { - const asset = MockStablecoin__factory.connect(address, signer); + const asset = SimpleUSDC__factory.connect(address, signer); return asset.mint(to, amount); }); } @@ -28,7 +24,7 @@ export async function __mockMintToken( signer: Signer | ethers.providers.Provider, ): Promise { return vault.token().then(async (address) => { - const token = MockStablecoin__factory.connect(address, signer); + const token = SimpleUSDC__factory.connect(address, signer); return token.mint(to, amount); }); } diff --git a/yarn.lock b/yarn.lock index ccc9ca1c1..6631b80f7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -642,7 +642,7 @@ __metadata: ethers: ^5.7.2 js-toml: ^1.0.0 prettier: ^3.2.2 - solhint: ^4.1.1 + solhint: ^5.0.1 typechain: ^8.3.2 typescript: ^5.4.5 languageName: unknown @@ -6868,9 +6868,9 @@ __metadata: linkType: hard "caniuse-lite@npm:^1.0.30001579": - version: 1.0.30001638 - resolution: "caniuse-lite@npm:1.0.30001638" - checksum: 82e47b2bfac107c662e03bfd3321bfd9493f87240c77a9bfba7ea2cc9e0b81d9238152aed903fb19e60557879e4f48b57e2c6300677391b92a060fbf0a340e30 + version: 1.0.30001639 + resolution: "caniuse-lite@npm:1.0.30001639" + checksum: 0d9291cc47ffaad5806716bff6fef41eec21f86a448370bc30a72823fcaf24ba5ccb4704841e6a60f078ddf2e9987e3d23f4d3ca0fffc51f6cb0400b7411ad28 languageName: node linkType: hard @@ -15703,9 +15703,9 @@ __metadata: languageName: node linkType: hard -"solhint@npm:^4.1.1": - version: 4.5.4 - resolution: "solhint@npm:4.5.4" +"solhint@npm:^5.0.1": + version: 5.0.1 + resolution: "solhint@npm:5.0.1" dependencies: "@solidity-parser/parser": ^0.18.0 ajv: ^6.12.6 @@ -15731,7 +15731,7 @@ __metadata: optional: true bin: solhint: solhint.js - checksum: 1c869d85048bbef988bf6ac855d53fc8faf07d88cf90f4da9619ec53ee617bc910fe8d9bf06251de22f1c3292b800754e77e4b060e7b8536f8076e4733a1162c + checksum: ff961f5e3e62172b6e26cda758b4b2e266cd07fdc32f280bfbafeb9eda99177326515aaeb5dfff531eeb03c01e432488783f4406439e7524c8da1afa0235a44e languageName: node linkType: hard