# UP Assistants: Digital Assistants For Everyone

In a not-too-distant tomorrow, people own sleek, digital identities called **Universal Profiles (UPs)** on LUKSO. These UPs house everything from collectibles to social tokens, making them the beating heart of each individual’s on-chain life. Yet as these profiles grow, so do the complexities of managing who sends what—and why.

Enter the **Universal Assistant Protocol (UAP)**, a powerful new layer that ensures every incoming asset or transaction to your UP gets the attention it deserves. When something arrives—like an NFT or a cryptographic message—the **UAP’s Universal Receiver Delegate (URDuap)** steps in as the dedicated concierge. It checks a registry of your chosen “Executive Assistants,” specialized mini-contracts trained to handle tasks you’ve defined in advance, such as automatic tipping, forwarders, or specialized refining for certain tokens.

Soon, these Executive Assistants will be joined by “Screener Assistants,” vigilant watchers that can evaluate each incoming transfer and decide if it should be allowed, blocked, or modified. Think of it like a trusted guard at your digital door, ensuring only the transfers that match your exact preferences get through—so unwanted tokens or tricky spam never clutter your identity.

Over time, the UAP turns your Universal Profile into something more than an address—it becomes a curated experience, shaped by your own rules and logic. Whether you automatically tip creators, refine game tokens into premium rewards, or simply filter out spam, the UAP coordinates it all in a smooth, transparent way. It’s the next step in forging truly intelligent on-chain identities, where **you** decide exactly how assets, messages, and possibilities flow into your life.

<figure><img src="https://3689982843-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FBynSJM9ZOgVHmkRbMqHb%2Fuploads%2FWGmY4SgSwdzvndbnLyuq%2Fimage.png?alt=media&amp;token=dae23052-408b-49f6-ac11-33499d221263" alt=""><figcaption><p>All the Assistants. All the Power.</p></figcaption></figure>


# Quickstart

To get started, head to <https://upassistants.com/> to setup your UP profile for using UP Assistants

<figure><img src="https://3689982843-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FBynSJM9ZOgVHmkRbMqHb%2Fuploads%2FlKHCrN7v2MfeCq8K1q0O%2FScreenshot%202025-02-21%20at%204.07.59%20PM.png?alt=media&amp;token=e0fa6fcf-2bff-468c-bbd2-c10d59f95775" alt=""><figcaption></figcaption></figure>

## Sign in

We currently support the rich experience facilitated by Universal Profiles through the Universal Profiles [browser extension](https://chromewebstore.google.com/detail/universal-profiles/abpickdkkbnbcoepogfhkhennhfhehfn?hl=en) on LUKSO.

<div><figure><img src="https://3689982843-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FBynSJM9ZOgVHmkRbMqHb%2Fuploads%2FRDU0yicOO27ervoKmrUM%2FScreenshot%202025-02-24%20at%2023.40.26.png?alt=media&amp;token=16e26171-b74a-46f0-b5c4-f5ea1389d389" alt="" width="188"><figcaption></figcaption></figure> <figure><img src="https://3689982843-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FBynSJM9ZOgVHmkRbMqHb%2Fuploads%2FMZGA1L2koez9Qp8wq6BD%2FScreenshot%202025-02-24%20at%2023.41.36.png?alt=media&amp;token=f34b7364-c28d-4141-9293-9d99ed90076a" alt="" width="375"><figcaption></figcaption></figure></div>

## Give the UP Browser Extension the necessary permissions to subscribe to the protocol

For the purposes of this demo, we'll install the protocol via the Tip Assistant.&#x20;

This step is required to allow UAP's Univeral Receiver to be installed on your 🆙<br>

![](https://3689982843-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FBynSJM9ZOgVHmkRbMqHb%2Fuploads%2FWP9nxv8wmtYOIogT9lXF%2FScreenshot%202025-02-25%20at%2000.51.45.png?alt=media\&token=aa0cce12-5197-4319-8f4c-df447b1594e8) <img src="https://3689982843-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FBynSJM9ZOgVHmkRbMqHb%2Fuploads%2FXiZ4p00cFQLO6z1pHcot%2FScreenshot%202025-02-25%20at%2000.53.06.png?alt=media&amp;token=0e3a38a6-f22a-4874-8f3f-ba435e9cd7a3" alt="" data-size="original">

<figure><img src="https://3689982843-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FBynSJM9ZOgVHmkRbMqHb%2Fuploads%2FFEUp6YqRp9RMxIPlF0e7%2FScreenshot%202025-02-25%20at%2000.54.02.png?alt=media&amp;token=e2c9c37d-6057-41c5-83e3-cbfc0b2a7549" alt="" width="375"><figcaption></figcaption></figure>

## Install the Universal Assistant Protocol on your 🆙

This step sets UAP's Universal Receiver Delegate to handle LSP0, LSP6 and LSP7 transactions on your behalf, depending on which Universal Assistants you have installed. Installing the protocol by itself will not change any existing behavior on your Universal Profile without installing the actual assistant (next step). The exception to this is the unlikely case that you have already installed a Universal Receiver Delegate in which case this will replace it.

&#x20;Learn more about [LSP1 - Universal Receiver Delegate](https://docs.lukso.tech/standards/accounts/lsp1-universal-receiver-delegate/)

<figure><img src="https://3689982843-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FBynSJM9ZOgVHmkRbMqHb%2Fuploads%2F7NCRqDpJCdOvFZYilDFM%2FScreenshot%202025-02-25%20at%2000.57.47.png?alt=media&amp;token=5d5c6eab-5ac1-4b62-b595-74cbf519eba3" alt=""><figcaption></figcaption></figure>

## Configure and activate assistants

Once the protocol is successfully installed on your 🆙, you'll see a configuration screen specific to that assistant. In this case the Tip Assistant allows you to transfer a percentage of LYX received on your 🆙 to another wallet. This might be useful to have a "savings" wallet or tip a community wallet.

<br>

<figure><img src="https://3689982843-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FBynSJM9ZOgVHmkRbMqHb%2Fuploads%2FagYGAZOQoisGpQt3w1h8%2FScreenshot%202025-02-25%20at%2001.07.04.png?alt=media&amp;token=230fce6b-f889-4e03-82b4-7751da747f09" alt=""><figcaption><p>First, enter a valid destination (could be another 🆙 or an EOA) </p></figcaption></figure>

<figure><img src="https://3689982843-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FBynSJM9ZOgVHmkRbMqHb%2Fuploads%2FLH56MYIaFZjyQ5TbHv2s%2FScreenshot%202025-02-25%20at%2001.08.01.png?alt=media&amp;token=b9f8a39f-05e3-440c-ac1d-281cb095e69c" alt=""><figcaption><p>Confirm the transaction to store assistant configuration in your 🆙</p></figcaption></figure>

##

<figure><img src="https://3689982843-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FBynSJM9ZOgVHmkRbMqHb%2Fuploads%2F8nt5yNZp9UT3rbqVoQCF%2FScreenshot%202025-02-25%20at%2001.08.19.png?alt=media&amp;token=eea84265-902e-4ae7-8dd5-01df29e9c982" alt=""><figcaption><p>Note that the assistant is now marked ACTIVE</p></figcaption></figure>

##

You can deactivate your assistant anytime

<figure><img src="https://3689982843-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FBynSJM9ZOgVHmkRbMqHb%2Fuploads%2FtmDIMl6K3aqevpWJ8GkH%2FScreenshot%202025-02-25%20at%2001.11.57.png?alt=media&amp;token=79430131-f8e8-40cf-b5f8-765757e03285" alt=""><figcaption></figcaption></figure>

##


# UP Assistant Usecases

The way Universal Assistants Protocol is designed allows anyone to build flexible and unique automation UP Assistants which can act on incoming LYX, LSP7 and LSP8 assets. Here are so some examples of what is possible to build:

#### **1. Wallet Automation & Management**

* **Auto-Splitter**: Automatically distributes incoming LYX tokens based on predefined rules (e.g., splitting income between multiple wallets).
* **Auto-Swap Assistant**: Converts incoming LYX or LSP7 tokens to stablecoins or other assets via a DEX.
* **Savings & Investment Assistant**: Routes a percentage of received funds to a designated investment or staking contract.

#### **2. Subscription & Payment Services**

* **Recurring Payments Manager**: Automates subscription payments by deducting LYX at specified intervals.
* **Pay-Per-Use Contracts**: Enables automatic payments for metered services (e.g., cloud services, API access).
* **Payroll Manager**: Distributes salaries to multiple employees based on preset schedules.

#### **3. Digital Identity & Reputation Management**

* **Trust Score Manager**: Updates a user’s reputation score based on incoming assets (e.g., receiving verified tokens from known sources).
* **Badge & Certification Issuer**: Automatically grants NFTs (LSP8) as proof of participation or achievements.

#### **4. NFT & Digital Collectibles Management**

* **NFT Auto-Accept & Organizer**: Sorts and stores incoming LSP8 NFTs in predefined collections or marketplaces.
* **NFT Royalty Splitter**: Automatically distributes royalties from secondary sales based on ownership records.
* **Dynamic NFT Updater**: Updates metadata or attributes of NFTs upon receiving LSP8 transactions.

#### **5. DAO & Governance Tools**

* **Auto-Delegation Assistant**: Routes governance tokens (LSP7) to delegate votes to a chosen representative.
* **Proposal Auto-Voter**: Casts votes on governance proposals based on pre-set preferences.

#### **6. Smart Donations & Charity**

* **Conditional Donations Assistant**: Releases funds only when predefined conditions are met (e.g., recipient verifies identity or impact metrics).
* **Carbon Credit & Green Donations Manager**: Accepts eco-related tokens and routes them to green projects.

#### **7. Automated Compliance & Security**

* **Whitelist & Blacklist Enforcer**: Rejects or redirects transactions from unauthorized sources.
* **KYC & AML Compliance Checker**: Flags transactions from high-risk addresses and reports them.
* **Security Escrow Agent**: Holds funds until predefined security conditions are met.

#### **8. Gaming & Metaverse Integrations**

* **In-Game Asset Distributor**: Automatically assigns NFTs (LSP8) or tokens (LSP7) upon in-game achievements.
* **Guild Treasury Manager**: Distributes LYX or other tokens among members based on contribution tracking.

#### **9. Social & Creator Economy**

* **Tip Collector & Distributor**: Manages incoming tips and distributes them among team members.
* **Content Unlocker**: Grants access to exclusive content based on received LSP7 or LSP8 tokens.
* **Crowdfunding Assistant**: Manages campaign funds, returning them if funding goals are unmet.

#### **10. Real-World Asset Tokenization**

* **Rent & Royalty Collector**: Automates rent payments or royalty distributions using tokenized assets.
* **Asset Transfer Validator**: Ensures compliance when transferring tokenized real estate, shares, or physical assets.


# Supported Blockchains

The Universal Assistant Protocol and UP Assistants are currently deployed on LUKSO and LUKSO Testnet. The latest protocol contract deployments can be found here: <https://upassistants.com/contracts>


# Catalog page

We have a range of UP Assistants that can automate various tasks on your LUKSO's UP profile. Browse our catalog for both testnet and mainnet assistants:

* Mainnet: <https://upassistants.com/lukso/catalog>
* Testnet: <https://upassistants.com/lukso-testnet/catalog>

<figure><img src="https://3689982843-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FBynSJM9ZOgVHmkRbMqHb%2Fuploads%2FwbI1auHRrVkIzCvCetwl%2FScreenshot%202025-02-25%20at%2001.15.35.png?alt=media&amp;token=25a1e7bb-ed3f-4185-a802-50321bf2bfa1" alt=""><figcaption></figcaption></figure>


# Global Settings page

To access your Global Settings / Profile page, click on your connected wallet in the top right of the nav bar and hit Global Settings

<figure><img src="https://3689982843-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FBynSJM9ZOgVHmkRbMqHb%2Fuploads%2FCpyDtgLmG4Zuf5jhCB5y%2FScreenshot%202025-02-25%20at%2001.14.20.png?alt=media&amp;token=5ffb5e3d-e90b-4911-a14c-f17142b27edd" alt=""><figcaption></figcaption></figure>

From this view you're able to review your activated assistants (if any) and unsubscribe from all assistants and the UAP protocol.

<figure><img src="https://3689982843-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FBynSJM9ZOgVHmkRbMqHb%2Fuploads%2FaXWaD8gAXw0o4P6we7jP%2FScreenshot%202025-02-25%20at%2001.17.00.png?alt=media&amp;token=8c345683-b394-4ee6-8197-d8ea53ee5b39" alt=""><figcaption></figcaption></figure>


# Wallets

We currently only support Universal Profiles [browser extension](https://my.universalprofile.cloud/) as we require features only supported by Universal Profiles such as Universal Receiver Delegate.


# Overview

If you're unfamiliar with LSP1 Universal Receiver, please check [Lukso's guide on LSP1](https://github.com/lukso-network/LIPs/blob/main/LSPs/LSP-1-UniversalReceiver.md).

Our [UniversalReceiverDelegateUAP](https://github.com/yearone-io/universal-assistant-protocol/blob/main/contracts/UniversalReceiverDelegateUAP.sol)  contract serves as a Universal Receiver Delegate tailored for the Universal Assistant Protocol (UAP). It extends a base universal receiver delegate, allowing it to intercept and handle incoming transactions on a Universal Profile. The primary purpose is to dynamically evaluate transaction types and, based on on-chain configurations stored in the profile’s data, delegate the transaction processing to a series of "assistant" contracts—specifically, executive and screener assistants (coming soon).

When a transaction is received, the contract’s `universalReceiverDelegate` function is invoked. This function first attempts to fetch a type-specific configuration using a generated mapping key that incorporates the transaction’s `typeId`. If a configuration exists, it decodes an ordered list of executive assistant addresses from the returned data. In cases where no configuration is found, it simply defers to the default behavior defined in its parent contract.

Overall, this design enables flexible and modular transaction handling on Universal Profiles. By leveraging on-chain configurations to dynamically determine which assistant contracts to engage, the system supports customizable behavior for different transaction types while maintaining a robust security model through screening and trust verification mechanisms.


# Protocol Architecture

{% @mermaid/diagram content="graph LR

subgraph User Identity
UP\[Universal Profile - LSP0]
subgraph LSP0 Components
ERC725X
ERC725Y
LSP1\[UP Universal Receiver Delegate - LSP1]
end
UP --> ERC725X
UP --> ERC725Y
UP --> LSP1
KM\[Key Manager - LSP6] -->|Manages Access| UP
end

Tokens\[Digital Asset Contracts - LSP7/LSP8 or Other Payloads] -->|Send Transactions| UP

UP -->|Delegates to| URDuap\[Universal Receiver Delegate - Universal Assistant Protocol]

URDuap -->|Accesses Configurations from| ERC725Y

URDuap -->|Invokes| ExecutiveAssistants

ExecutiveAssistants -->|Modify| Value\_and\_Data\[Value and Data]

ExecutiveAssistants -->|Interact with| ThirdParties\[Third Parties, ex: Vault]

URDuap -->|Defaults to| LSP1" %}

### Detailed Component Descriptions and Interactions

#### 1. LUKSO Universal Profile (UP) - LSP0

**Components:**

* **ERC725X**: Allows executing generic function calls.
* **ERC725Y**: Provides a key-value data store for arbitrary data.
* **Universal Receiver Delegate (LSP1)**: Handles incoming transactions and messages.

**Role:**

* Acts as the user’s on-chain identity.
* Stores configurations and preferences via the ERC725Y key-value store.
* Delegates transaction handling to a Universal Receiver Delegate.

**Interactions:**

* **Receives transactions** from digital asset contracts (e.g., LSP7 or LSP8).
* **Delegates incoming transactions** to the Universal Assistant Protocol's Universal Receiver Delegate (`URDuap`).
* **Access controlled** by the Key Manager (KM).

***

#### 2. Key Manager (KM) - LSP6

**Role:**

* Manages permissions and access control for the UP.

**Responsibilities:**

* Determines who can modify the UP’s data and configurations.
* Ensures only authorized entities can interact with sensitive functions.

**Interactions:**

* Manages access to the UP (ERC725X, ERC725Y).
* Enforces permission checks for data updates or contract calls.

***

#### 3. Digital Asset Contracts - LSP7/LSP8

**Role:**

* Represent fungible (LSP7) or non-fungible (LSP8) tokens within the LUKSO ecosystem.

**Interactions:**

* Send transactions (e.g., token transfers) to the UP.
* Trigger the Universal Receiver Delegate upon asset transfer or interaction.

***

#### 4. Universal Receiver Delegate for Universal Assistant Protocol (URDuap)

**Role:**

* The Universal Assistant Protocol’s specialized Universal Receiver Delegate that handles incoming transactions.

**Responsibilities:**

* Receives `typeId` and `data` from the UP.
* Looks up any **Executive Assistants** configured under that `typeId`.
* Calls each **Executive Assistant** in order, passing them the current `value` and `data`.
* Executes the returned operations (on behalf of the UP) via `IERC725X.execute(...)`.
* **Falls back** to the default LSP1 delegate behavior if no Assistants are found.

**Interactions:**

* **Delegated to by the UP**: Receives all inbound calls from the UP.
* **Accesses ERC725Y**: Reads user-defined config for each `typeId`.
* **Invokes Executive Assistants**: Calls their `execute(...)` function in sequence.
* **Updates `value` and `data`**: Receives possibly updated values from each Assistant.
* **Defaults to LSP1**: If no relevant Assistants are configured or none are invoked.

***

#### 5. ERC725Y Data Store

**Role:**

* Key-value store within the UP for configuration and user preferences.

**Responsibilities:**

* Maps `typeId` to an ordered list of **Executive Assistant** contract addresses.
* May also store per-Assistant settings used when the Assistant is invoked.
* Accessible by `URDuap` to retrieve necessary data.

**Interactions:**

* Queried by `URDuap` for the list of Assistants mapped to a given `typeId`.
* Manages data keys such as:
  * `UAPTypeConfig:<typeId>` → Encoded addresses of the Executive Assistants.
  * `UAPExecutiveConfig:<assistantAddress>` → Custom assistant settings.

***

#### 6. Executive Assistants

**Role:**

* Modular contracts that implement specific logic to handle transactions.

**Responsibilities:**

* Must implement the `execute(...)` function (see `IExecutiveAssistant` in the code).
* Process transaction data and optionally alter the `value` and `data` that flow to subsequent Assistants.
* Return an operation to be executed (if needed) via `IERC725X.execute(...)`.

**Interactions:**

* Called in sequence by `URDuap`.
* Receive the current `value` and `data`.
* Return updates to `value` and `data`, plus instructions for an on-chain operation.
* May interact with external contracts (e.g., Vaults, token registries, etc.).

***

#### 7. (Planned) Screener Assistants

**Role:**

* **Future Feature**:
* Will intercept incoming transactions/data to decide if any Executive Assistants should be invoked or if the transaction should be rejected/modified beforehand.

**Responsibilities:**

* (TBD) Could hold evaluation logic to allow or deny transaction flow.
* Potentially attach additional instructions or modifications prior to any Executive Assistant call.

**Interactions:**

* (TBD) Will be triggered by `URDuap` before normal Executive Assistant invocation.
* Will store their logic and configurations in the UP’s ERC725Y storage.

> **Note**: The Screener Assistant architecture is still under development and is **not** included in this release.

***

#### 8. Default Universal Receiver Delegate (LSP1)

**Role:**

* The standard fallback Universal Receiver Delegate in the UP.

**Responsibilities:**

* Provides a default handling mechanism for incoming transactions.
* Invoked by `URDuap` if no custom logic or Assistants are configured for a specific `typeId`.

**Interactions:**

* Performs standard actions if no UAP-specific configuration is present.


# Transaction flow

## Detailed Universal Assistant Protocol Transaction Flow

***

{% @mermaid/diagram content="sequenceDiagram
participant User
participant LSP7\_Token as LSP7/LSP8 Token Contract
participant UP as Universal Profile (ERC725Y)
participant URDuap
participant ERC725Y as ERC725Y Data Store
participant ExecAssistant1 as Executive Assistant 1
participant ExecAssistant2 as Executive Assistant 2
participant ExecAssistantN as Executive Assistant N
participant ThirdParty as Third Party
participant LSP1 as Default Universal Receiver Delegate (LSP1)

```
%% Step 1: User initiates a transaction (e.g., token transfer) to the Universal Profile
User->>LSP7_Token: Transfer tokens or send payload to UP
LSP7_Token->>UP: Notify Transfer (typeId, data)

%% Step 2: UP delegates handling to URDuap
UP->>URDuap: universalReceiverDelegate(notifier, value, typeId, data)

%% Step 3: URDuap fetches Executive Assistants
URDuap->>ERC725Y: Read addresses for typeId (UAPTypeConfig:<typeId>)
ERC725Y-->>URDuap: Return [ExecAssistant1, ExecAssistant2, ..., ExecAssistantN]

%% Step 4: URDuap calls each Executive Assistant in sequence
loop For each ExecAssistant
    URDuap->>ExecAssistant: execute(upAddress, notifier, currentValue, typeId, currentData)
    ExecAssistant-->>URDuap: (operationType, target, execValue, callData, newDataAfterExec)

    %% URDuap executes the returned operation on the UP
    URDuap->>UP: IERC725X.execute(operationType, target, execValue, callData)

    %% Assistant may interact externally (Third Parties)
    alt External interaction
        ExecAssistant->>ThirdParty: Forward or handle external call
    end

    %% URDuap updates value/data for the next Assistant in sequence
    URDuap->>URDuap: currentValue and currentData updated
end

%% Step 5: If no Assistants or none were applicable, default to LSP1
alt No ExecAssistant invoked
    URDuap->>LSP1: Fallback to standard LSP1 behavior
end
URDuap->>UP: Return final action
UP->>User: Transaction processed
```

" %}

#### **Flow Explanation**

1. **User Initiates Transaction:**
   * A **User** sends a transaction to a **Universal Profile (UP)** (i.e. interacts with an LSP7/LSP8 token contract to transfer tokens).
   * The **token contract** calls the UP’s Universal Receiver function with `typeId` and `data`.
2. **UP Delegates to `URDuap`:**
   * The **UP** forwards the call to the **URDuap** (`universalReceiverDelegate(...)`).
3. **`URDuap` Fetches Executive Assistants:**
   * **URDuap** reads from the **ERC725Y** data store using a key like `UAPTypeConfig:<typeId>`.
   * This key contains an encoded list of Executive Assistant addresses.
4. **`URDuap` Invokes Each Executive Assistant:**
   * For each Executive Assistant in the list, **URDuap** calls `execute(...)` within the same transaction context.
   * The Assistant returns operation instructions (e.g., `IERC725X.execute(...)`) plus possibly updated `value` and `data`.
   * **URDuap** then executes those instructions on the UP’s behalf.
   * This may include external interactions with third-party contracts.
5. **Fallback to LSP1:**
   * If no Executive Assistants are configured or none are invoked, **URDuap** calls the default LSP1 delegate.
   * Finally, **URDuap** returns control to the UP, completing the transaction.

***


# Creating assistants

The contracts/interfaces below can be found in the [universal-assistant-protocol](https://github.com/yearone-io/universal-assistant-protocol) repo.

### Creating and Integrating a New Executive Assistant

#### 1. Overview

An **Executive Assistant** is any contract that implements the `IExecutiveAssistant` interface. When the **Universal Receiver Delegate (URDuap)** is triggered in the Universal Profile (UP), it will:

1. Look up which Executive Assistants are associated with the `typeId`.
2. Call each Assistant’s `execute(...)` function, passing in context about the current transaction (`upAddress`, `notifier`, `value`, `typeId`, and `data`).
3. Receive back instructions on what operation to perform via the UP’s `ERC725X.execute(...)` function, plus optionally updated `value` and `data` for subsequent Assistants.

By implementing the `IExecutiveAssistant` interface, you gain access to a powerful extension point to customize how certain incoming transfers or messages are processed.

***

#### 2. Implement the `IExecutiveAssistant` Interface

Your custom Executive Assistant **must** implement the following function signature:

```solidity
function execute(
    address upAddress, 
    address notifier, 
    uint256 value, 
    bytes32 typeId, 
    bytes memory data
)
    external 
    returns (
        uint256 operationType, 
        address target, 
        uint256 execValue, 
        bytes memory execData, 
        bytes memory newDataAfterExec
    );
```

* **`upAddress`**: The UP address that is delegating this call to the URDuap.
* **`notifier`**: The contract or account that triggered the universal receiver (e.g., a token contract sending LSP7/LSP8 tokens).
* **`value`**: The amount of native tokens (e.g., LYX) sent with the transaction.
* **`typeId`**: A bytes32 value identifying the type of incoming asset or event.
* **`data`**: Additional data relevant to the transaction (as forwarded by the token contract or the caller).

You must return:

1. **`operationType`**: The type of `IERC725X.execute` operation (0 = `CALL`, 1 = `CREATE`, 2 = `CREATE2`, etc.).
2. **`target`**: The address on which the UP will execute the operation (`execTarget`).
3. **`execValue`**: The amount of native tokens sent along with this operation.
4. **`execData`**: The encoded call data to execute on `target`.
5. **`newDataAfterExec`**: Arbitrary bytes that become the `data` parameter for the **next** Assistant in the chain (if any). This is how you can pass along updated context or instructions.

> **Note**: Returning `(0, address(0), 0, "", data)` would effectively mean "do nothing except pass along the `data`," which can be useful if your Assistant only updates `value` or modifies the data for the next Assistant but does not need to call an external contract.

***

#### 3. Storing and Reading Configuration

Often, your Assistant needs additional settings or instructions (for example, a recipient address, a percentage, or a specific token ID). Because Assistants run in their **own** contract context when called by the URDuap, they can:

**Use the UP’s ERC725Y Storage**

* Store configuration under a known key derived from your Assistant’s address.
* For example, the code uses a key like `UAPExecutiveConfig:<assistantAddress>` to store arbitrary settings.
* You can read from the UP’s storage with something like:

  ```solidity
  IERC725Y upERC725Y = IERC725Y(upAddress);
  bytes32 settingsKey = // e.g., keccak256("UAPExecutiveConfig") combined with assistantAddress
  bytes memory settingsData = upERC725Y.getData(settingsKey);
  // decode settingsData to retrieve your config
  ```

**Example** (taken from `TipAssistant`):

```solidity
bytes32 settingsKey = getSettingsDataKey(address(this));
bytes memory settingsData = upERC725Y.getData(settingsKey);

(address tipAddress, uint256 tipPercentage) = abi.decode(
    settingsData, 
    (address, uint256)
);
```

In this example, the Assistant expects the user to have stored `(tipAddress, tipPercentage)` in the UP’s ERC725Y store. If that data is missing or invalid, the Assistant reverts or defaults.

***

#### 4. Adding Your Assistant to a `typeId`

1. **Compute the Key**: The URDuap uses:

   ```solidity
   bytes32 typeConfigKey = LSP2Utils.generateMappingKey(
       bytes10(keccak256("UAPTypeConfig")),
       bytes20(typeId)
   );
   ```

   to locate an array of Executive Assistant addresses for a given `typeId`.
2. **Encode an Array of Addresses**: The URDuap’s `customDecodeAddresses` function expects:

   * **First 2 bytes**: The number of addresses (in `uint16`).
   * **Then**: Each address in 20 bytes (no padding, just consecutive addresses).

   You can encode this on the client side or in a script. For example (in JavaScript/TypeScript, pseudo-code):

   ```ts
   function encodeAssistants(addresses: string[]): string {
     const num = addresses.length;
     const hexCount = num.toString(16).padStart(4, '0'); // for uint16
     // encode addresses in hex
     let encoded = '0x' + hexCount;
     addresses.forEach(addr => {
       encoded += addr.replace(/^0x/, '');
     });
     return encoded;
   }
   ```
3. **Set the Data** in the UP:

   ```solidity
   IERC725Y(upAddress).setData(typeConfigKey, encodedAssistants);
   ```

Once the `typeId` is mapped to your Assistant(s), the URDuap will automatically invoke them in the specified order whenever a transaction arrives with that `typeId`.

***

#### 5. Best Practices & Considerations

1. **Keep Logic Focused**
   * Each Assistant should do **one** well-defined task (e.g., tipping, refining, forwarding, etc.).
   * Complex or multi-step logic might be split into separate Assistants for clarity and composability.
2. **Handle Missing or Invalid Configuration Gracefully**
   * If your Assistant depends on config in `ERC725Y` that might not exist, consider reverting with a clear error message or defaulting to a safe no-op.
3. **Reverts vs. Bubbles**
   * If your Assistant fails (reverts), the entire URDuap flow reverts. Decide carefully whether to revert or to continue with partial success.
   * Provide meaningful revert reasons or error events to help users debug.
4. **Avoid Unbounded Loops**
   * The URDuap will invoke each Assistant in order. If your Assistant triggers additional loops or calls that might be unbounded, you risk hitting gas limits.
5. **Beware of Re-entrancy**
   * If your Assistant performs external calls with non-trivial logic, consider re-entrancy safeguards (e.g., checks-effects-interactions pattern).
   * Typically, `IERC725X.execute(...)` calls can be considered safe, but be mindful of external calls your Assistant might make.
6. **Gas Efficiency**
   * Keep the computation in `execute(...)` as minimal as possible to avoid large overhead in normal UP usage.
   * Store only necessary data on-chain.
   * Consider using well-optimized libraries for encoding/decoding if your logic is complex.
7. **Test Thoroughly**
   * Write unit tests and integration tests against your custom Assistant.
   * Verify correct behavior when receiving different `value`, `typeId`, or `data`.
8. **Security Audits**
   * Because Assistants can instruct the UP to execute arbitrary operations, a bug in your Assistant can lead to unexpected or dangerous calls.
   * Make sure to audit for any potential logic flaws or vulnerabilities.

***

#### 6. Example: Creating a New “MyCoolAssistant”

Below is a minimal example of a new Assistant that might:

* Read a stored “recipientAddress” from the UP’s ERC725Y data.
* Always forward a fixed portion of `value` to that recipient.

```solidity
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.24;

import {IExecutiveAssistant} from "./IExecutiveAssistant.sol";
import {IERC725Y} from "@erc725/smart-contracts/contracts/interfaces/IERC725Y.sol";
import {ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol";

contract MyCoolAssistant is IExecutiveAssistant, ERC165 {
    // Custom error for no configuration found
    error NoConfigFound();

    function supportsInterface(bytes4 interfaceId) 
        public view override(ERC165) 
        returns (bool) 
    {
        return interfaceId == type(IExecutiveAssistant).interfaceId 
            || super.supportsInterface(interfaceId);
    }

    function execute(
        address upAddress, 
        address /*notifier*/, 
        uint256 value, 
        bytes32 /*typeId*/, 
        bytes memory data
    )
        external 
        override 
        returns (
            uint256 operationType, 
            address target, 
            uint256 execValue, 
            bytes memory execData, 
            bytes memory newDataAfterExec
        )
    {
        // 1. Fetch config from UP
        IERC725Y upERC725Y = IERC725Y(upAddress);
        bytes32 settingsKey = _computeSettingsKey(address(this));
        bytes memory settings = upERC725Y.getData(settingsKey);
        if (settings.length == 0) {
            revert NoConfigFound();
        }

        // 2. Decode recipient
        address recipient = abi.decode(settings, (address));
        // 3. Forward 10% of the value
        uint256 forwardAmount = (value * 10) / 100;

        // 4. Return operation instructions
        // operationType = 0 (CALL), target = recipient, execValue = forwardAmount
        // no call data needed for a plain value transfer, so execData = ""
        // newDataAfterExec is the updated data for next assistant (we reduce the value by the forwardAmount)
        return (
            0, 
            recipient, 
            forwardAmount, 
            "", 
            abi.encode(value - forwardAmount, data)
        );
    }

    function _computeSettingsKey(address assistantAddr) internal pure returns (bytes32) {
        // same pattern used in examples (UAPExecutiveConfig plus assistantAddr)
        bytes32 firstWordHash = keccak256(bytes("UAPExecutiveConfig"));
        bytes memory temp = bytes.concat(
            bytes10(firstWordHash),
            bytes2(0),
            bytes20(assistantAddr)
        );
        return bytes32(temp);
    }
}
```

**Configuration Steps**:

1. Deploy `MyCoolAssistant`.
2. Set `UAPTypeConfig:<typeId>` in your UP’s ERC725Y to include the address of `MyCoolAssistant`.
3. Store the “recipient” under the key `UAPExecutiveConfig:myCoolAssistantAddress`.

With that, whenever a transfer or call with the matching `typeId` arrives, the URDuap will call `MyCoolAssistant.execute(...)`, which in turn forwards 10% of the provided `value` to the configured recipient.

***

### Final Thoughts

* Reach out to the YearOne team for integrating the Executive Assistant you build directly into the <https://upassistants.com> UI.
* **Executive Assistants** give developers modular, composable “plugins” to process incoming transactions on a Universal Profile.
* By storing or reading settings from the UP’s `ERC725Y` data store, you can create highly configurable logic for specific token types (`typeId`), event types, or other scenarios.
* Always design and **test** your Assistants carefully to avoid security pitfalls or unexpected behaviors.

This is an evolving ecosystem, and future releases will add **Screener Assistants**, which will act as gatekeepers before any Executive Assistant logic is invoked. Until then, the approach outlined here (implementing `IExecutiveAssistant` and registering your contract under a `typeId`) is the primary way to integrate with the UAP.


# Deployment

The commands below can be run within [universal-assistant-protocol](https://github.com/yearone-io/universal-assistant-protocol) repo.

## Deployments

Ensure your .env file is configured.

Deploy the UAP URD and multiple assistants at once:

```bash
npx hardhat deployContracts \
  --network luksoTestnet \
  --names "UniversalReceiverDelegateUAP,ForwarderAssistant" \
  --paths "contracts,contracts/executive-assistants"
```

## Verifications

Verify the UAP URD and multiple assistants post-deployment:

```bash
npx hardhat verifyContracts \
  --network luksoTestnet \
  --names "UniversalReceiverDelegateUAP,TipAssistant,BurntPixRefinerAssistant,ForwarderAssistant" \
  --addresses "0xcf44a050c9b1fc87141d77b646436443bdc05a2b,0xf24c39a4d55994e70059443622fc166f05b5ff14,0x34a8ad9cf56dece5790f64f790de137b517169c6,0x67cc9c63af02f743c413182379e0f41ed3807801" \
  --paths "contracts,contracts/executive-assistants,contracts/executive-assistants,contracts/executive-assistants"
```


# Future proposal: Screener Assistants

**Screener Assistants** will be introduced in a future release.

They are intended to:

* Act as a gatekeeper to incoming transactions before Executive Assistants run.
* Potentially block, modify, or augment the transaction data/`value` if certain conditions are met.

The final architecture is **TBD**. Stay tuned for updates.


