Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions src/api/reserve/config/addresses.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,6 @@ export const RESERVE_ADDRESS_CONFIGS: ReserveAddressConfig[] = [
assets: ['CELO', 'USDT'],
description: 'Reserve assets held in the Aave protocol',
},
{
address: '0x619600F4ec13C38868841cB83100F611eCF94eE8',
chain: Chain.CELO,
category: AddressCategory.MENTO_RESERVE,
label: 'Falcon Finance Custodied Funds',
assets: ['CELO'],
description: 'Reserve assets custodied by Falcon Finance',
},
{
address: '0xaa8299fc6a685b5f9ce9bda8d0b3ea3d54731976',
chain: Chain.CELO,
Expand Down
31 changes: 10 additions & 21 deletions src/api/v2/config/reserve-addresses.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,37 +17,26 @@ export type CustodianType = 'hot' | 'cold' | 'ops';

export interface ReserveAddress {
address: string;
chain: Chain;
chains: Chain[];
label: string;
custodianType: CustodianType;
description?: string;
}

/* prettier-ignore */
export const RESERVE_ADDRESSES: ReserveAddress[] = [
// --- Celo ---
{ address: '0x9380fA34Fd9e4Fd14c06305fd7B6199089eD4eb9', chain: Chain.CELO, label: 'Mento Pools Liquidity Reserve', custodianType: 'hot' },
{ address: '0x87647780180b8f55980c7d3ffefe08a9b29e9ae1', chain: Chain.CELO, label: 'Custody Multisig', custodianType: 'cold' },
{ address: '0xD3D2e5c5Af667DA817b2D752d86c8f40c22137E1', chain: Chain.CELO, label: 'Ops Multisig', custodianType: 'ops' },
{ address: '0x6dec25d7be9bf6c6fc302977629f2e801e98611c', chain: Chain.CELO, label: 'Operational Account', custodianType: 'ops' },
{ address: '0x13a9803d547332c81ebc6060f739821264dbcf1e', chain: Chain.CELO, label: 'Operational Account', custodianType: 'ops' },
{ address: '0x619600F4ec13C38868841cB83100F611eCF94eE8', chain: Chain.CELO, label: 'Falcon Finance', custodianType: 'cold' },
{ address: '0xaa8299fc6a685b5f9ce9bda8d0b3ea3d54731976', chain: Chain.CELO, label: 'Rebalancer Bot', custodianType: 'ops' },
// --- Ethereum ---
{ address: '0x9380fA34Fd9e4Fd14c06305fd7B6199089eD4eb9', chain: Chain.ETHEREUM, label: 'Mento Pools Liquidity Reserve', custodianType: 'hot' },
{ address: '0xd0697f70E79476195B742d5aFAb14BE50f98CC1E', chain: Chain.ETHEREUM, label: 'ETH Custody Multisig', custodianType: 'cold' },
{ address: '0xD3D2e5c5Af667DA817b2D752d86c8f40c22137E1', chain: Chain.ETHEREUM, label: 'Ops Multisig', custodianType: 'ops' },
{ address: '0xaa8299fc6a685b5f9ce9bda8d0b3ea3d54731976', chain: Chain.ETHEREUM, label: 'Rebalancer Bot', custodianType: 'ops' },
{ address: '0x6dec25d7be9bf6c6fc302977629f2e801e98611c', chain: Chain.ETHEREUM, label: 'Operational Account', custodianType: 'ops' },
// --- Monad ---
{ address: '0x4255Cf38e51516766180b33122029A88Cb853806', chain: Chain.MONAD, label: 'ReserveV2', custodianType: 'hot' },
{ address: '0x87647780180B8f55980C7D3fFeFe08a9B29e9aE1', chain: Chain.MONAD, label: 'Reserve Safe', custodianType: 'cold' },
{ address: '0x6dec25d7be9bf6c6fc302977629f2e801e98611c', chain: Chain.MONAD, label: 'Operational Account', custodianType: 'ops' },
{ address: '0x13a9803d547332c81ebc6060f739821264dbcf1e', chain: Chain.MONAD, label: 'Operational Account', custodianType: 'ops' },
{ address: '0x9380fA34Fd9e4Fd14c06305fd7B6199089eD4eb9', chains: [Chain.CELO, Chain.ETHEREUM], label: 'Mento V2 Liquidity Reserve', custodianType: 'hot', description: 'Active liquidity for stablecoin swaps in Mento V2' },
{ address: '0x4255Cf38e51516766180b33122029A88Cb853806', chains: [Chain.CELO, Chain.MONAD], label: 'Mento V3 Liquidity Reserve', custodianType: 'hot', description: 'Active liquidity for stablecoin swaps in Mento V3' },
{ address: '0x87647780180B8f55980C7D3fFeFe08a9B29e9aE1', chains: [Chain.CELO, Chain.MONAD], label: 'Reserve Safe', custodianType: 'cold', description: 'Mento Reserve Asset Custody' },
{ address: '0xd0697f70E79476195B742d5aFAb14BE50f98CC1E', chains: [Chain.ETHEREUM], label: 'Reserve Safe', custodianType: 'cold', description: 'Mento Reserve Asset Custody' },
{ address: '0xD3D2e5c5Af667DA817b2D752d86c8f40c22137E1', chains: [Chain.CELO, Chain.ETHEREUM], label: 'Ops Safe', custodianType: 'ops', description: 'Accounts used to provide liquidity to FPMMs and other protocols on behalf of the reserve' },
{ address: '0x13a9803d547332c81ebc6060f739821264dbcf1e', chains: [Chain.CELO, Chain.MONAD], label: 'Ops Account', custodianType: 'ops', description: 'Accounts used to provide liquidity to FPMMs and other protocols on behalf of the reserve' },
{ address: '0xaa8299fc6a685b5f9ce9bda8d0b3ea3d54731976', chains: [Chain.CELO, Chain.ETHEREUM], label: 'Rebalancer Bot', custodianType: 'ops', description: 'Account executing active rebalancing on behalf of the reserve' },
];

/** Get all reserve addresses for a specific chain */
export function getReserveAddressesByChain(chain: Chain): ReserveAddress[] {
return RESERVE_ADDRESSES.filter((a) => a.chain === chain);
return RESERVE_ADDRESSES.filter((a) => a.chains.includes(chain));
}

/** Check if an address is a reserve address (case-insensitive) on any chain */
Expand Down
2 changes: 1 addition & 1 deletion src/api/v2/controllers/v2-addresses.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export class V2AddressesController {
) {}

@Get()
@ApiOperation({ summary: 'Get reserve addresses grouped by network and category' })
@ApiOperation({ summary: 'Get reserve addresses with chain and custodian metadata' })
@ApiResponse({ status: 200, type: V2AddressesResponseDto })
async getAddresses(): Promise<V2AddressesResponseDto> {
return this.cacheWarmerService.getOrRevalidate<V2AddressesResponseDto>(V2_CACHE_KEYS.ADDRESSES, () =>
Expand Down
15 changes: 3 additions & 12 deletions src/api/v2/dto/v2-addresses.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,12 @@ import { Chain } from '@types';

export class V2AddressDto {
@ApiProperty() address: string;
@ApiProperty({ enum: Chain, isArray: true }) chains: Chain[];
@ApiProperty() label: string;
@ApiProperty({ enum: ['hot', 'cold', 'ops'], required: false }) custodian_type?: string;
@ApiProperty({ enum: ['hot', 'cold', 'ops'] }) custodian_type: string;
@ApiProperty({ required: false }) description?: string;
}

export class V2AddressCategoryDto {
@ApiProperty() category: string;
@ApiProperty({ type: [V2AddressDto] }) addresses: V2AddressDto[];
}

export class V2NetworkAddressesDto {
@ApiProperty({ enum: Chain }) chain: Chain;
@ApiProperty({ type: [V2AddressCategoryDto] }) categories: V2AddressCategoryDto[];
}

export class V2AddressesResponseDto {
@ApiProperty({ type: [V2NetworkAddressesDto] }) networks: V2NetworkAddressesDto[];
@ApiProperty({ type: [V2AddressDto] }) reserve: V2AddressDto[];
}
75 changes: 11 additions & 64 deletions src/api/v2/services/v2-addresses.service.ts
Original file line number Diff line number Diff line change
@@ -1,71 +1,18 @@
import { Injectable } from '@nestjs/common';
import { getReserveAddressesByChain } from '../config/reserve-addresses.config';
import { CDP_TROVE_CONFIGS, CDP_REGISTRIES } from '../config/cdp.config';
import { V2AddressesResponseDto, V2NetworkAddressesDto, V2AddressCategoryDto } from '../dto/v2-addresses.dto';
import { Chain } from '@types';
import { RESERVE_ADDRESSES } from '../config/reserve-addresses.config';
import { V2AddressesResponseDto } from '../dto/v2-addresses.dto';

@Injectable()
export class V2AddressesService {
getAddresses(): V2AddressesResponseDto {
const networkMap = new Map<Chain, Map<string, V2AddressCategoryDto>>();
const chainOrder = [Chain.CELO, Chain.ETHEREUM, Chain.MONAD];

for (const chain of chainOrder) {
const addresses = getReserveAddressesByChain(chain);
if (addresses.length === 0) continue;

const categoryMap = new Map<string, V2AddressCategoryDto>();
const categoryKey = 'Mento Reserve';
categoryMap.set(categoryKey, { category: categoryKey, addresses: [] });

const group = categoryMap.get(categoryKey)!;
for (const addr of addresses) {
if (!group.addresses.some((a) => a.address.toLowerCase() === addr.address.toLowerCase())) {
group.addresses.push({
address: addr.address,
label: addr.label,
custodian_type: addr.custodianType,
});
}
}

networkMap.set(chain, categoryMap);
}

// Add CDP contract addresses
for (const cdp of CDP_TROVE_CONFIGS) {
if (cdp.status !== 'active') continue;

const contractAddress = cdp.contractAddress || CDP_REGISTRIES[cdp.stablecoin];
if (!contractAddress) continue;

if (!networkMap.has(cdp.chain)) {
networkMap.set(cdp.chain, new Map());
}

const categoryMap = networkMap.get(cdp.chain)!;
const categoryKey = 'CDP Contract';

if (!categoryMap.has(categoryKey)) {
categoryMap.set(categoryKey, { category: categoryKey, addresses: [] });
}

const label = cdp.contractAddress ? `${cdp.stablecoin} TroveManager` : `${cdp.stablecoin} AddressesRegistry`;

categoryMap.get(categoryKey)!.addresses.push({
address: contractAddress,
label,
description: `CDP system for minting ${cdp.stablecoin} with ${cdp.collateralToken} collateral`,
});
}

const networks: V2NetworkAddressesDto[] = chainOrder
.filter((c) => networkMap.has(c))
.map((chain) => ({
chain,
categories: Array.from(networkMap.get(chain)!.values()),
}));

return { networks };
return {
reserve: RESERVE_ADDRESSES.map((addr) => ({
address: addr.address,
chains: addr.chains,
label: addr.label,
custodian_type: addr.custodianType,
description: addr.description,
})),
};
}
}
Loading