Protocol

Assets and balances

Vestige tracks native USDC and ERC20-compatible tokens in separate accounting maps. The dApp should make this separation obvious to users.

Native USDC accounting

On Arc, the native asset is USDC. The contract exposes USDC-named payable functions so the frontend and wallet prompts can be presented in the correct asset language.

The native USDC balance is stored per owner in nativeUSDCBalances(owner). This is the value shown as the main vault balance in the dashboard.

  • depositUSDC() credits msg.sender's existing vault.
  • depositUSDCFor(owner) credits another existing owner's vault.
  • withdrawUSDC(amount) moves native USDC back to the owner while owner controls are valid.
  • claimUSDC(owner, receiver) lets the heir claim native USDC to an explicit receiver.
mapping(address => uint256) public nativeUSDCBalances;

ERC20-compatible token accounting

ERC20 balances are stored per owner and token address. Deposits use SafeERC20 and credit the actual received amount, which is safer than assuming requested amount equals received amount.

The contract does not attempt to claim every token in one transaction. The heir claims tokens individually. This avoids gas problems from unbounded token lists.

mapping(address => mapping(address => uint256)) public tokenBalances;

Tracked tokens

getTrackedTokens(owner) returns token addresses that were registered during the current vault lifecycle. The list is for frontend discovery. Critical claim logic does not iterate over it.

activeTokenCounts(owner) stores the number of token contracts with non-zero balances. This allows disableVault to know whether ERC20 assets remain without looping through historical tokens.

tracked list
address[] used by the frontend to display token rows
active count
non-zero token balance count used for empty-vault checks
epoch
internal tracker reset when a vault lifecycle is disabled

Asset risks

Native USDC is the intended primary asset. ERC20 support is intentionally broad but not magic: strange token behavior can still create strange UX. Builders should treat unknown tokens conservatively.

  • Fee-on-transfer tokens may credit less than requested; the contract accounts for received amount.
  • Rebasing tokens may make displayed balances harder to reason about.
  • NFTs are not supported by this contract surface.
  • Tokens with malicious callbacks or non-standard behavior need separate review.