Skip to content

Commit 2deb59b

Browse files
committed
feat: changes based on core-platform review
1 parent 142edb6 commit 2deb59b

6 files changed

Lines changed: 75 additions & 98 deletions

File tree

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
1-
export {
2-
MoneyAccountBalanceService,
3-
serviceName as moneyAccountBalanceServiceName,
4-
} from './money-account-balance-service';
1+
export { MoneyAccountBalanceService } from './money-account-balance-service';
52
export type {
63
MoneyAccountBalanceServiceActions,
74
MoneyAccountBalanceServiceEvents,
85
MoneyAccountBalanceServiceMessenger,
9-
MoneyAccountBalanceServiceConfig,
106
} from './money-account-balance-service';
117
export type {
128
MoneyAccountBalanceServiceGetMusdBalanceAction,
@@ -18,5 +14,5 @@ export type {
1814
export type {
1915
ExchangeRateResponse,
2016
MusdEquivalentValueResponse,
21-
VaultApyResponse,
17+
NormalizedVaultApyResponse,
2218
} from './response.types';

packages/money-account-balance-service/src/money-account-balance-service.test.ts

Lines changed: 5 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,7 @@ import type {
1010
import nock, { cleanAll as nockCleanAll } from 'nock';
1111

1212
import { VedaResponseValidationError } from './errors';
13-
import type {
14-
MoneyAccountBalanceServiceConfig,
15-
MoneyAccountBalanceServiceMessenger,
16-
} from './money-account-balance-service';
13+
import type { MoneyAccountBalanceServiceMessenger } from './money-account-balance-service';
1714
import {
1815
MoneyAccountBalanceService,
1916
serviceName,
@@ -144,16 +141,13 @@ function createServiceMessenger(
144141
* Builds the service under test with messenger action stubs for the two
145142
* NetworkController dependencies.
146143
*
147-
* @param args - Optional overrides for the service config and constructor options.
148-
* @param args.config - Partial config merged over {@link DEFAULT_CONFIG}.
149-
* @param args.options - Partial constructor options passed to the service.
144+
* @param args - Optional overrides for the service constructor options.
145+
* @param args.options - Partial constructor options merged over {@link DEFAULT_CONFIG}.
150146
* @returns The constructed service together with messenger instances and mock stubs.
151147
*/
152148
function createService({
153-
config = {},
154149
options = {},
155150
}: {
156-
config?: Partial<MoneyAccountBalanceServiceConfig>;
157151
options?: Partial<
158152
ConstructorParameters<typeof MoneyAccountBalanceService>[0]
159153
>;
@@ -192,7 +186,7 @@ function createService({
192186

193187
const service = new MoneyAccountBalanceService({
194188
messenger,
195-
config: { ...DEFAULT_CONFIG, ...config },
189+
...DEFAULT_CONFIG,
196190
...options,
197191
});
198192

@@ -567,20 +561,6 @@ describe('MoneyAccountBalanceService', () => {
567561
expect(result).toStrictEqual(MOCK_VAULT_APY_NORMALIZED);
568562
});
569563

570-
it('uses a custom vedaApiBaseUrl when provided', async () => {
571-
nock('https://custom-veda-api.example.com')
572-
.get(`/performance/arbitrum/${MOCK_VAULT_ADDRESS}`)
573-
.reply(200, MOCK_VAULT_APY_RAW_RESPONSE);
574-
575-
const { service } = createService({
576-
config: { vedaApiBaseUrl: 'https://custom-veda-api.example.com' },
577-
});
578-
579-
const result = await service.getVaultApy();
580-
581-
expect(result).toStrictEqual(MOCK_VAULT_APY_NORMALIZED);
582-
});
583-
584564
it('throws HttpError on a non-200 response', async () => {
585565
nock('https://api.sevenseas.capital')
586566
.get(`/performance/arbitrum/${MOCK_VAULT_ADDRESS}`)
@@ -725,7 +705,7 @@ describe('MoneyAccountBalanceService', () => {
725705
.reply(200, MOCK_VAULT_APY_RAW_RESPONSE);
726706

727707
const { service } = createService({
728-
config: { vaultChainId: '0x1' as const },
708+
options: { vaultChainId: '0x1' as const },
729709
});
730710

731711
const result = await service.getVaultApy();

packages/money-account-balance-service/src/money-account-balance-service.ts

Lines changed: 61 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ import { normalizeVaultApyResponse } from './requestNormalization';
3030
import type {
3131
ExchangeRateResponse,
3232
MusdEquivalentValueResponse,
33-
VaultApyResponse,
33+
NormalizedVaultApyResponse,
3434
} from './response.types';
35-
import { VaultApyResponseStruct } from './structs';
35+
import { VaultApyRawResponseStruct } from './structs';
3636

3737
// === GENERAL ===
3838

@@ -108,24 +108,6 @@ export type MoneyAccountBalanceServiceMessenger = Messenger<
108108
MoneyAccountBalanceServiceEvents | AllowedEvents
109109
>;
110110

111-
export type MoneyAccountBalanceServiceConfig = {
112-
/** The address of the Veda vault (musdSHFvd token contract). */
113-
vaultAddress: Hex;
114-
/** The chain ID of the Veda vault. */
115-
vaultChainId: Hex;
116-
/** The address of the Veda Accountant contract. */
117-
accountantAddress: Hex;
118-
/** The address of the underlying token (mUSD). Must be on the same chain as the vault. */
119-
underlyingTokenAddress: Hex;
120-
/**
121-
* The decimals of the underlying token. Also determines the precision of
122-
* the Accountant's `getRate()` return value.
123-
*/
124-
underlyingTokenDecimals: number;
125-
/** Base URL for the Veda Seven Seas performance API. Defaults to https://api.sevenseas.capital. */
126-
vedaApiBaseUrl?: string;
127-
};
128-
129111
// === SERVICE DEFINITION ===
130112

131113
/**
@@ -142,44 +124,64 @@ export type MoneyAccountBalanceServiceConfig = {
142124
* ```ts
143125
* const service = new MoneyAccountBalanceService({
144126
* messenger: moneyAccountBalanceServiceMessenger,
145-
* config: {
146-
* vaultAddress: '0x...',
147-
* vaultChainId: '0xa4b1',
148-
* accountantAddress: '0x...',
149-
* underlyingTokenAddress: '0x...',
150-
* underlyingTokenDecimals: 6,
151-
* },
127+
* vaultAddress: '0x...',
128+
* vaultChainId: '0xa4b1',
129+
* accountantAddress: '0x...',
130+
* underlyingTokenAddress: '0x...',
131+
* underlyingTokenDecimals: 6,
152132
* });
153133
*
154134
* const { balance } = await service.getMusdBalance('0xYourMoneyAccount...');
155135
* ```
156136
*/
137+
138+
type MoneyAccountBalanceServiceOptions = {
139+
messenger: MoneyAccountBalanceServiceMessenger;
140+
vaultAddress: Hex;
141+
vaultChainId: Hex;
142+
accountantAddress: Hex;
143+
underlyingTokenAddress: Hex;
144+
underlyingTokenDecimals: number;
145+
policyOptions?: CreateServicePolicyOptions;
146+
};
147+
157148
export class MoneyAccountBalanceService extends BaseDataService<
158149
typeof serviceName,
159150
MoneyAccountBalanceServiceMessenger
160151
> {
161-
readonly #config: MoneyAccountBalanceServiceConfig;
162-
163152
readonly #networkName: string;
164153

154+
readonly #vaultAddress: Hex;
155+
156+
readonly #vaultChainId: Hex;
157+
158+
readonly #accountantAddress: Hex;
159+
160+
readonly #underlyingTokenAddress: Hex;
161+
162+
readonly #underlyingTokenDecimals: number;
163+
165164
/**
166165
* Constructs a new MoneyAccountBalanceService.
167166
*
168167
* @param args - The constructor arguments.
169168
* @param args.messenger - The messenger suited for this service.
169+
* @param args.vaultAddress - The address of the Veda vault (e.g. musdSHFvd token contract).
170+
* @param args.vaultChainId - The chain ID of the Veda vault.
171+
* @param args.accountantAddress - The address of the Veda Accountant contract.
172+
* @param args.underlyingTokenAddress - The address of the underlying token (e.g. mUSD). Must be on the same chain as the vault.
173+
* @param args.underlyingTokenDecimals - The decimals of the underlying token.
170174
* @param args.policyOptions - Options to pass to `createServicePolicy`,
171-
* which is used to wrap each request.
172-
* @param args.config - The configuration for the service.
173175
*/
174176
constructor({
175177
messenger,
178+
vaultAddress,
179+
vaultChainId,
180+
accountantAddress,
181+
underlyingTokenAddress,
182+
underlyingTokenDecimals,
176183
policyOptions = {},
177-
config,
178-
}: {
179-
messenger: MoneyAccountBalanceServiceMessenger;
180-
config: MoneyAccountBalanceServiceConfig;
181-
policyOptions?: CreateServicePolicyOptions;
182-
}) {
184+
}: MoneyAccountBalanceServiceOptions) {
183185
super({
184186
name: serviceName,
185187
messenger,
@@ -191,13 +193,14 @@ export class MoneyAccountBalanceService extends BaseDataService<
191193
},
192194
});
193195

194-
this.#config = {
195-
...config,
196-
vedaApiBaseUrl: config.vedaApiBaseUrl ?? VEDA_PERFORMANCE_API_BASE_URL,
197-
};
196+
this.#vaultAddress = vaultAddress;
197+
this.#vaultChainId = vaultChainId;
198+
this.#accountantAddress = accountantAddress;
199+
this.#underlyingTokenAddress = underlyingTokenAddress;
200+
this.#underlyingTokenDecimals = underlyingTokenDecimals;
198201

199202
this.#networkName =
200-
VEDA_API_NETWORK_NAMES[this.#config.vaultChainId] ??
203+
VEDA_API_NETWORK_NAMES[this.#vaultChainId] ??
201204
DEFAULT_VEDA_API_NETWORK_NAME;
202205

203206
this.messenger.registerMethodActionHandlers(
@@ -207,7 +210,7 @@ export class MoneyAccountBalanceService extends BaseDataService<
207210
}
208211

209212
/**
210-
* Resolves a Web3Provider for {@link MoneyAccountBalanceServiceConfig.vaultChainId} by looking up the
213+
* Resolves a Web3Provider for {@link MoneyAccountBalanceServiceOptions.vaultChainId} by looking up the
211214
* network configuration and client via the messenger.
212215
*
213216
* @returns A Web3Provider connected to the vault chain.
@@ -217,12 +220,12 @@ export class MoneyAccountBalanceService extends BaseDataService<
217220
#getProvider(): Web3Provider {
218221
const config = this.messenger.call(
219222
'NetworkController:getNetworkConfigurationByChainId',
220-
this.#config.vaultChainId,
223+
this.#vaultChainId,
221224
);
222225

223226
if (!config) {
224227
throw new Error(
225-
`No network configuration found for chain ${this.#config.vaultChainId}`,
228+
`No network configuration found for chain ${this.#vaultChainId}`,
226229
);
227230
}
228231

@@ -235,9 +238,7 @@ export class MoneyAccountBalanceService extends BaseDataService<
235238
);
236239

237240
if (!networkClient?.provider) {
238-
throw new Error(
239-
`No provider found for chain ${this.#config.vaultChainId}`,
240-
);
241+
throw new Error(`No provider found for chain ${this.#vaultChainId}`);
241242
}
242243

243244
return new Web3Provider(networkClient.provider);
@@ -271,7 +272,7 @@ export class MoneyAccountBalanceService extends BaseDataService<
271272
queryKey: [`${this.name}:getMusdBalance`, accountAddress],
272273
queryFn: async () => {
273274
const balance = await this.#fetchErc20Balance(
274-
this.#config.underlyingTokenAddress,
275+
this.#underlyingTokenAddress,
275276
accountAddress,
276277
);
277278
return { balance };
@@ -292,7 +293,7 @@ export class MoneyAccountBalanceService extends BaseDataService<
292293
queryKey: [`${this.name}:getMusdSHFvdBalance`, accountAddress],
293294
queryFn: async () => {
294295
const balance = await this.#fetchErc20Balance(
295-
this.#config.vaultAddress,
296+
this.#vaultAddress,
296297
accountAddress,
297298
);
298299
return { balance };
@@ -310,22 +311,22 @@ export class MoneyAccountBalanceService extends BaseDataService<
310311
* @param options.staleTime - The stale time for the query. Defaults to 30 seconds.
311312
* @returns The exchange rate as a raw uint256 string.
312313
*/
313-
async getExchangeRate(options?: {
314-
staleTime?: number;
315-
}): Promise<ExchangeRateResponse> {
314+
async getExchangeRate({
315+
staleTime = inMilliseconds(30, Duration.Second),
316+
}: { staleTime?: number } = {}): Promise<ExchangeRateResponse> {
316317
return this.fetchQuery({
317318
queryKey: [`${this.name}:getExchangeRate`],
318319
queryFn: async () => {
319320
const provider = this.#getProvider();
320321
const contract = new Contract(
321-
this.#config.accountantAddress,
322+
this.#accountantAddress,
322323
ACCOUNTANT_ABI,
323324
provider,
324325
);
325326
const rate = await contract.getRate();
326327
return { rate: rate.toString() };
327328
},
328-
staleTime: options?.staleTime ?? inMilliseconds(30, Duration.Second),
329+
staleTime,
329330
});
330331
}
331332

@@ -353,7 +354,7 @@ export class MoneyAccountBalanceService extends BaseDataService<
353354

354355
const musdEquivalentValue = (
355356
(balanceBigInt * rateBigInt) /
356-
10n ** BigInt(this.#config.underlyingTokenDecimals)
357+
10n ** BigInt(this.#underlyingTokenDecimals)
357358
).toString();
358359

359360
return {
@@ -368,13 +369,13 @@ export class MoneyAccountBalanceService extends BaseDataService<
368369
*
369370
* @returns The normalized vault APY response.
370371
*/
371-
async getVaultApy(): Promise<VaultApyResponse> {
372+
async getVaultApy(): Promise<NormalizedVaultApyResponse> {
372373
return this.fetchQuery({
373374
queryKey: [`${this.name}:getVaultApy`],
374375
queryFn: async () => {
375376
const url = new URL(
376-
`/performance/${this.#networkName}/${this.#config.vaultAddress}`,
377-
this.#config.vedaApiBaseUrl,
377+
`/performance/${this.#networkName}/${this.#vaultAddress}`,
378+
VEDA_PERFORMANCE_API_BASE_URL,
378379
);
379380

380381
const response = await fetch(url);
@@ -389,7 +390,7 @@ export class MoneyAccountBalanceService extends BaseDataService<
389390
const rawResponse = await response.json();
390391

391392
// Validate raw response inside queryFn to avoid poisoned cache.
392-
if (!is(rawResponse, VaultApyResponseStruct)) {
393+
if (!is(rawResponse, VaultApyRawResponseStruct)) {
393394
throw new VedaResponseValidationError(
394395
'Malformed response received from Veda performance API',
395396
);

packages/money-account-balance-service/src/requestNormalization.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Infer } from '@metamask/superstruct';
22

3-
import type { VaultApyResponse } from './response.types';
4-
import { VaultApyResponseStruct } from './structs';
3+
import type { NormalizedVaultApyResponse } from './response.types';
4+
import { VaultApyRawResponseStruct } from './structs';
55

66
/**
77
* Normalizes the raw response from the Veda performance API into the expected
@@ -11,8 +11,8 @@ import { VaultApyResponseStruct } from './structs';
1111
* @returns The normalized response.
1212
*/
1313
export function normalizeVaultApyResponse(
14-
rawResponse: Infer<typeof VaultApyResponseStruct>,
15-
): VaultApyResponse {
14+
rawResponse: Infer<typeof VaultApyRawResponseStruct>,
15+
): NormalizedVaultApyResponse {
1616
const { Response: response } = rawResponse;
1717

1818
return {

packages/money-account-balance-service/src/response.types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export type MusdEquivalentValueResponse = {
2424
* Only `apy` and `timestamp` are guaranteed to be present — all other fields
2525
* are optional because the Veda API omits them when the vault has no activity.
2626
*/
27-
export type VaultApyResponse = {
27+
export type NormalizedVaultApyResponse = {
2828
aggregationPeriod?: string; // E.g. "7 days"
2929
apy: number;
3030
chainAllocation?: {

packages/money-account-balance-service/src/structs.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,15 @@ import {
88
} from '@metamask/superstruct';
99

1010
/**
11-
* Superstruct schema for {@link VaultApyResponse}.
11+
* Superstruct schema for {@link NormalizedVaultApyResponse}.
1212
*
1313
* Uses `type()` (loose validation) so that unknown fields returned by the
1414
* Veda API do not cause validation failures.
1515
*
1616
* Only `apy` and `timestamp` are required — all other fields are optional
1717
* because the Veda API omits some fields when the vault has no activity.
1818
*/
19-
export const VaultApyResponseStruct = type({
19+
export const VaultApyRawResponseStruct = type({
2020
Response: type({
2121
aggregation_period: optional(string()),
2222
apy: number(),

0 commit comments

Comments
 (0)