Asset Managers

Overview

Arcadia Accounts offer users the flexibility to delegate control of their assets to third-party Asset Managers. Asset Managers are smart contracts that execute specific strategies on behalf of an account owner, such as rebalancing or compounding liquidity positions. By leveraging Asset Managers, users can optimize the performance of their accounts while maintaining control over the delegation process.

Key Features

  1. Delegation: Users can authorize an Asset Manager to perform actions on their behalf.

  2. Full Access: The Asset Manager has access to all assets within the assigned Arcadia Account.

  3. Flexible Strategies: Asset Managers can perform complex operations, such as rebalancing or interacting with DeFi protocols.

  4. Health Check for Margin Accounts: Asset Managers must ensure that a margin account remains in a healthy state after executing actions.

  5. Spot Accounts: No health check is required for operations on spot accounts.

Workflow

1. Setting an Asset Manager

The account owner assigns an Asset Manager to their account by calling the setAssetManager() function:

account.setAssetManager(assetManager, true);
  • Parameters:

    • assetManager: Address of the Asset Manager contract.

    • true: Enables the Asset Manager.

Once set, the Asset Manager can perform actions using the flashAction() function.

2. Performing a Flash Action

The flashAction() function enables Asset Managers to execute complex operations. It allows the chaining of multiple actions in a single transaction, with the following capabilities:

  • Withdraw Assets: Transfer assets from the Arcadia Account to the actionTarget.

  • Direct Transfers: Transfer assets directly from the account owner to the actionTarget.

  • Execute External Logic: Interact with DeFi protocols via the actionTarget (e.g., staking, swapping, or claiming rewards).

  • Deposit Back: Deposit the resultant tokens back into the Arcadia Account.

At the end of the flash action, a health check ensures the margin account remains solvent (collateral value > liabilities). If the check fails, the transaction reverts.

Flash Action Parameters

flashAction(
    address actionTarget,
    bytes memory actionData
);
  • actionTarget: The contract address where external logic is executed.

  • actionData: Encoded data containing:

    • withdrawData: Asset withdrawal details from the Arcadia Account to the actionTarget.

    • transferFromOwnerData: Asset transfer details from the owner to the actionTarget.

    • permit: Permit for the Permit2 transfer.

    • signature: Signature for the Permit2 transfer.

    • actionTargetData: The encoded calldata required to perform the series of contract calls needed to execute a specific action or operation with the assets.

How Chaining of Calls Works

The flashAction() function enables chaining by executing a series of tightly coupled operations in a single transaction. Here’s a step-by-step breakdown:

  1. Decoding Input Data: The function decodes the actionData input into its respective components:

    • Withdrawal details (withdrawData)

    • Transfer details (transferFromOwnerData)

    • Permit details for Permit2

    • Action target logic (actionTargetData)

  2. Asset Withdrawal: Using _withdraw(), assets are transferred from the Arcadia Account to the actionTarget based on the withdrawData.

  3. Direct Transfers: If transferFromOwnerData specifies additional assets, _transferFromOwner() transfers them from the owner’s wallet to the actionTarget.

  4. Permit-Based Transfers: If a signature and permit are provided, _transferFromOwnerWithPermit() is called to initiate a Permit2-based asset transfer.

  5. External Logic Execution: The Asset Manager calls executeAction() on the actionTarget, passing the actionTargetData to interact with external protocols (e.g., swapping tokens, staking).

  6. Deposit Back to Account: After executing external logic, _deposit() transfers the resulting assets back into the Arcadia Account. The _deposit() function uses depositData, which is returned from the executeAction() call on the actionTarget, to determine the assets and amounts to deposit.

  7. Health Check (Margin Accounts Only): The isAccountUnhealthy() function ensures the margin account remains solvent. If not, the transaction reverts.

Interfaces for Asset Managers

To interact with the flashAction() function, developers must implement the following interfaces:

// Struct with information to pass to and from the actionTarget.
struct ActionData {
    // Array of the contract addresses of the assets.
    address[] assets;
    // Array of the IDs of the assets.
    uint256[] assetIds;
    // Array with the amounts of the assets.
    uint256[] assetAmounts;
    // Array with the types of the assets.
    uint256[] assetTypes;
}

interface IActionBase {
    /**
     * @notice Calls an external target contract with arbitrary calldata.
     * @param actionTargetData A bytes object containing the encoded input for the actionTarget.
     * @return resultData An ActionData struct with the final balances of this actionTarget contract.
     */
    function executeAction(bytes calldata actionTargetData) external returns (ActionData memory);
}

Requirements for Asset Managers

An Asset Manager should implement the following steps to function correctly:

  1. Call flashAction() on the Account:

    • The Asset Manager must call the flashAction() function on the Arcadia Account.

    • The input to flashAction() includes:

      • The address of the actionTarget contract.

      • Encoded actionData, which must be formatted as follows:

        (
            ActionData memory withdrawData,
            ActionData memory transferFromOwnerData,
            IPermit2.PermitBatchTransferFrom memory permit,
            bytes memory signature,
            bytes memory actionTargetData
        ) = abi.decode(actionData, (ActionData, ActionData, IPermit2.PermitBatchTransferFrom, bytes, bytes));
  2. Implement executeAction() in the ActionTarget Contract:

    • The actionTarget contract must include an executeAction() function that:

      • Accepts actionTargetData as input.

      • Executes all the required logic to perform the desired operation or strategy.

      • Returns an ActionData struct that contains the addresses and amounts of assets to be deposited back into the Arcadia Account.

  3. Handle the Returned Data:

    • The ActionData struct returned by executeAction() is used to call _deposit() and finalize the process by returning the assets to the Arcadia Account.

Last updated