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
12 changes: 12 additions & 0 deletions packages/money-account-balance-service/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Add `getMoneyAccountBalance` method that fetches the account's mUSD wallet balance and vault shares valued in mUSD in a single Multicall3 `aggregate3` request. ([#9100](https://github.com/MetaMask/core/pull/9100))
- Add optional `underlyingToken` field to `VaultConfig` (validated by `VaultConfigStruct`). When present, `getMusdBalance` reads the underlying mUSD token address from config and skips the on-chain `Accountant.base()` call; when absent it falls back to reading `base()` on-chain. ([#9100](https://github.com/MetaMask/core/pull/9100))
- Add support for configuring the balance `staleTime` at runtime via the `moneyAccountBalanceStaletime` remote feature flag. The flag is read during `init()` and updated on `RemoteFeatureFlagController:stateChange`; absent or malformed values fall back to the default of 60 seconds. ([#9100](https://github.com/MetaMask/core/pull/9100))

### Changed

- **BREAKING:** Rename `musdSHFvd` to `vmusd` across the public API to align with the vmUSD token name: ([#9100](https://github.com/MetaMask/core/pull/9100))
- `getMusdSHFvdBalance` method → `getVmusdBalance`
- `MoneyAccountBalanceServiceGetMusdSHFvdBalanceAction` type → `MoneyAccountBalanceServiceGetVmusdBalanceAction`
- `MoneyAccountBalanceService:getMusdSHFvdBalance` messenger action string → `MoneyAccountBalanceService:getVmusdBalance`
- `MoneyAccountBalanceResponse.musdSHFvdValueInMusd` property → `vmusdValueInMusd`
- Increase the default `staleTime` for on-chain balance reads (`getMusdBalance`, `getVmusdBalance`, `getMusdEquivalentValue`, and the default for `getExchangeRate`) from 30 seconds to 60 seconds. This default is now overridable via the `moneyAccountBalanceStaletime` remote feature flag. ([#9100](https://github.com/MetaMask/core/pull/9100))
- Bump `@metamask/utils` from `^11.9.0` to `^11.11.0` ([#9074](https://github.com/MetaMask/core/pull/9074))
- Bump `@metamask/controller-utils` from `^12.1.0` to `^12.2.0` ([#9058](https://github.com/MetaMask/core/pull/9058), [#9083](https://github.com/MetaMask/core/pull/9083))
- Bump `@metamask/base-data-service` from `^0.1.2` to `^0.1.3` ([#8799](https://github.com/MetaMask/core/pull/8799))
Expand Down
61 changes: 60 additions & 1 deletion packages/money-account-balance-service/src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Hex } from '@metamask/utils';
import { Duration, Hex, inMilliseconds } from '@metamask/utils';

export const VEDA_PERFORMANCE_API_BASE_URL = 'https://api.sevenseas.capital';

Expand All @@ -8,11 +8,70 @@ export const VEDA_PERFORMANCE_API_BASE_URL = 'https://api.sevenseas.capital';
*/
export const VAULT_CONFIG_FEATURE_FLAG_KEY = 'moneyAccountVaultConfig';

/**
* The key under which the Money account balance `staleTime` (in milliseconds)
* is stored in `RemoteFeatureFlagController` state's `remoteFeatureFlags` map.
* Falls back to {@link DEFAULT_BALANCE_STALE_TIME} when absent or malformed.
*/
export const MONEY_ACCOUNT_BALANCE_STALETIME_FEATURE_FLAG_KEY =

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure it makes sense to store the feature flags in the core library. To me it feels more like a client concern, and in general most of feature flags seem to be defined in the clients - so defining some of them in core seems to make the situation more confusing.

I understand that VAULT_CONFIG_FEATURE_FLAG_KEY is already defined in this package, so I’m happy to approve - but IMO we should move away from this pattern

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, the changelog says it's moneyAccountBalanceStaleTime - note the capital T. Would be good to get them matching ;)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. I've fixed the typo in the changelog!

As discussed, we'll open a separate PR if we decide to move feature flags to the client.

'moneyAccountBalanceStaletime';

/**
* Default `staleTime` (in milliseconds) for on-chain Money account balance
* reads, used when {@link MONEY_ACCOUNT_BALANCE_STALETIME_FEATURE_FLAG_KEY} is
* absent or malformed.
*/
export const DEFAULT_BALANCE_STALE_TIME = inMilliseconds(1, Duration.Minute);

export const VEDA_API_NETWORK_NAMES: Record<Hex, string> = {
'0xa4b1': 'arbitrum',
'0x8f': 'monad',
};

/**
* Multicall3 contract address by chain ID, used to batch the Money account
* balance reads into a single RPC request. Multicall3 is deployed at the same
* canonical address on every supported chain.
*
* Source: https://github.com/mds1/multicall/blob/main/deployments.json
*/
export const MULTICALL3_ADDRESS_BY_CHAIN_ID: Record<Hex, Hex> = {
'0xa4b1': '0xcA11bde05977b3631167028862bE2a173976CA11', // Arbitrum One
'0x8f': '0xcA11bde05977b3631167028862bE2a173976CA11', // Monad mainnet
};

/**
* Minimal ABI for the Multicall3 `aggregate3` function.
*/
export const MULTICALL3_ABI = [
{
name: 'aggregate3',
type: 'function',
stateMutability: 'payable',
inputs: [
{
name: 'calls',
type: 'tuple[]',
components: [
{ name: 'target', type: 'address' },
{ name: 'allowFailure', type: 'bool' },
{ name: 'callData', type: 'bytes' },
],
},
],
outputs: [
{
name: 'returnData',
type: 'tuple[]',
components: [
{ name: 'success', type: 'bool' },
{ name: 'returnData', type: 'bytes' },
],
},
],
},
] as const;

/**
* Minimal ABI for the Veda Accountant contract. Covers:
* - base (0x5001f3b5) — the underlying ERC20 base asset address
Expand Down
4 changes: 3 additions & 1 deletion packages/money-account-balance-service/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@ export type {
MoneyAccountBalanceServiceMessenger,
} from './money-account-balance-service';
export type {
MoneyAccountBalanceServiceGetMoneyAccountBalanceAction,
MoneyAccountBalanceServiceGetMusdBalanceAction,
MoneyAccountBalanceServiceGetMusdSHFvdBalanceAction,
MoneyAccountBalanceServiceGetVmusdBalanceAction,
MoneyAccountBalanceServiceGetExchangeRateAction,
MoneyAccountBalanceServiceGetMusdEquivalentValueAction,
MoneyAccountBalanceServiceGetVaultApyAction,
} from './money-account-balance-service-method-action-types';
export type {
ExchangeRateResponse,
MoneyAccountBalanceResponse,
MusdEquivalentValueResponse,
NormalizedVaultApyResponse,
} from './response.types';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,39 @@ export type MoneyAccountBalanceServiceGetMusdBalanceAction = {
};

/**
* Fetches the musdSHFvd (Veda vault share) ERC-20 balance for the given
* Fetches the account's total Money balance inputs in a single batched RPC
* request via Multicall3's `aggregate3`
*
* @param accountAddress - The Money account's Ethereum address.
* @returns The mUSD balance and the mUSD-equivalent value of vault shares as
* raw uint256 strings. The total balance is the sum of the mUSD balance and the mUSD-equivalent value of vault shares.
* @throws {@link VaultConfigNotAvailableError} if vault config has not been loaded.
*/
export type MoneyAccountBalanceServiceGetMoneyAccountBalanceAction = {
type: `MoneyAccountBalanceService:getMoneyAccountBalance`;
handler: MoneyAccountBalanceService['getMoneyAccountBalance'];
};

/**
* Fetches the vmUSD (Veda vault share) ERC-20 balance for the given
* account address via RPC.
*
* @param accountAddress - The Money account's Ethereum address.
* @returns The musdSHFvd balance as a raw uint256 string.
* @returns The vmUSD balance as a raw uint256 string.
* @throws {@link VaultConfigNotAvailableError} if vault config has not been loaded.
*/
export type MoneyAccountBalanceServiceGetMusdSHFvdBalanceAction = {
type: `MoneyAccountBalanceService:getMusdSHFvdBalance`;
handler: MoneyAccountBalanceService['getMusdSHFvdBalance'];
export type MoneyAccountBalanceServiceGetVmusdBalanceAction = {
type: `MoneyAccountBalanceService:getVmusdBalance`;
handler: MoneyAccountBalanceService['getVmusdBalance'];
};

/**
* Fetches the current exchange rate from the Veda Accountant contract via
* RPC. The rate represents the conversion factor from musdSHFvd shares to
* RPC. The rate represents the conversion factor from vmUSD shares to
* the underlying mUSD asset.
*
* @param options - The options for the query.
* @param options.staleTime - The stale time for the query. Defaults to 30 seconds.
* @param options.staleTime - Cache stale time override for this query.
* @returns The exchange rate as a raw uint256 string.
* @throws {@link VaultConfigNotAvailableError} if vault config has not been loaded.
*/
Expand All @@ -46,14 +60,11 @@ export type MoneyAccountBalanceServiceGetExchangeRateAction = {
};

/**
* Computes the mUSD-equivalent value of the account's musdSHFvd holdings.
* Internally fetches the musdSHFvd balance and exchange rate (using cached
* values when available within their staleTime windows), then multiplies
* them.
* Fetches the mUSD-equivalent value of the account's vmUSD vault shares
* via `Lens.balanceOfInAssets` RPC.
*
* @param accountAddress - The Money account's Ethereum address.
* @returns The musdSHFvd balance, exchange rate, and computed
* mUSD-equivalent value as raw uint256 strings.
* @returns The mUSD-equivalent value of vault shares as a raw uint256 string.
* @throws {@link VaultConfigNotAvailableError} if vault config has not been loaded.
*/
export type MoneyAccountBalanceServiceGetMusdEquivalentValueAction = {
Expand All @@ -77,7 +88,8 @@ export type MoneyAccountBalanceServiceGetVaultApyAction = {
*/
export type MoneyAccountBalanceServiceMethodActions =
| MoneyAccountBalanceServiceGetMusdBalanceAction
| MoneyAccountBalanceServiceGetMusdSHFvdBalanceAction
| MoneyAccountBalanceServiceGetMoneyAccountBalanceAction
| MoneyAccountBalanceServiceGetVmusdBalanceAction
| MoneyAccountBalanceServiceGetExchangeRateAction
| MoneyAccountBalanceServiceGetMusdEquivalentValueAction
| MoneyAccountBalanceServiceGetVaultApyAction;
Loading
Loading