# What's Mimic

<figure><img src="https://216358192-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F2K6E4Us9xYRIC0Tt0SIZ%2Fuploads%2FBa9E9vhjvIR90DIO8KJj%2FWhite.png?alt=media&amp;token=89c83aaa-78e2-4848-92c0-524d07e6c111" alt=""><figcaption></figcaption></figure>

**A developer platform to build blockchain applications**

Since 2022, Mimic has been evolving toward a singular vision: making blockchain development accessible without compromising control. Through years of iteration, experimentation, and close engagement with real-world challenges, Mimic has grown into a fully programmable developer platform. One that lets them define *what should happen*, without having to manage *how it happens*.

Mimic is built from the ground up to remove the friction of traditional blockchain development. Instead of dealing with transaction executions and coordinating smart contract behavior, developers can focus on expressing their business logic in scalable familiar code. Mimic handles execution, consistency, and security as a unified system.

By combining serverless functions, intent-based execution, and built-in policies, Mimic turns fragmented blockchain workflows into a cohesive and deterministic system. This enables developers to build and scale applications, agents, and protocols with greater speed, confidence, and operational clarity—while retaining full transparency and control over system behavior.


# What's Mimic Protocol

<figure><img src="https://216358192-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F2K6E4Us9xYRIC0Tt0SIZ%2Fuploads%2FBa9E9vhjvIR90DIO8KJj%2FWhite.png?alt=media&amp;token=89c83aaa-78e2-4848-92c0-524d07e6c111" alt=""><figcaption></figcaption></figure>

**Blockchain Execution Protocol**

Mimic Protocol is the permissionless, non-custodial, intent-based blockchain protocol that powers Mimic. It provides the decentralized execution, coordination, and verification guarantees required to safely turn developer-defined logic into real outcomes, without relying on trusted intermediaries or custodial components.

At its core, Mimic Protocol defines how intents are created, broadcast, executed, and settled in a trustless environment. It coordinates a network of independent actors—oracles, relayers, solvers, and settlers—that collaboratively plan, execute, and verify actions under open and enforceable rules. Assets, authority, and constraints always remain under user control.

By separating intent definition from execution and settlement, Mimic Protocol enables a competitive and verifiable execution environment. Solvers compete to fulfill intents under optimal conditions, while on-chain enforcement guarantees correctness, finality, and adherence to user-defined policies. This architecture ensures deterministic outcomes, resistance to manipulation, and full transparency at every step.


# How it works

A new standard for automated blockchain operations

### Introduction

Imagine building blockchain-powered applications without ever worrying about smart contract deployment, oracle integrations, RPC reliability, gas management, or transaction timing. With Mimic Protocol, developers write simple, expressive logic in code—**and the network handles everything else**. No onchain boilerplate, no custom automation flows, no operational overhead.

Mimic has evolved into a programmable execution layer that lets builders define *what* should happen onchain and *when*, without touching Solidity or maintaining infrastructure. Through years of iteration and hands-on experience with the limitations of trustless environments, Mimic is designed from the ground up to eliminate the friction of traditional blockchain development.

Instead of orchestrating transactions, monitoring conditions, or wiring together oracles and relayers, developers express intent-level behavior while Mimic provides the scheduling, data sourcing, and secure execution. Complex multi-step flows become unified, reliable automations—with built-in function planning, decentralized data access, and fail-safe guarantees.

The result is a new way to build onchain logic for apps, agents, and protocols: **programmable, composable, and fully managed by the network**, so you can focus on your application—not the machinery behind it.

**Key Takeaways**

* **Automation:** Simplify repetitive functions, enforce conditional logic, and handle cross-chain operations without manual intervention.
* **Trustless and Deterministic:** Built on cryptographic proofs and a network of independent actors (oracles, relayers, and solvers), so you don’t have to trust any single party.
* **Flexible:** Define exactly what you need—data sources, triggers, conditions—then pay only for executions that happen, not for ongoing maintenance.
* **Easy-to-use:** Write code in a familiar environment, compile it to a deterministic form, and deploy it. The protocol’s tooling and documentation make integration straightforward, even for complex logic.

***

### How does it work?

Mimic is built in three layers, each focusing on a distinct part of the automation pipeline, ensuring transparency, reliability, and modularity:

**Planning Layer**

Here, you define **functions**—logical units of automation. A function describes what data is needed, how to interpret it, and what conditions must be met to create intents. An intent represents an actionable instruction on the blockchain.

Oracles supply trustworthy signed data (e.g., block info, contract states, or prices), while relayers execute your defined logic to decide whether intents should be generated.

**Execution Layer**

Once intents are created, it’s handled by a coordination engine called **Axia**.

Axia broadcasts the intent to a network of solvers that compete to fulfill it under optimal conditions (lowest fees, fastest execution, highest reliability). The best solver is chosen to carry out the action on-chain, ensuring a competitive and cost-efficient environment.

**Security Layer**

Finally, the **Settler** contracts enforce that everything was done correctly. It verifies the solver’s actions, ensures that user-defined restrictions are respected, and finalizes the transaction outcome.

This layer ensures no half-finished states, no replay attacks, and no deviation from the intended behavior.

***

### A developer’s perspective: Defining a function

You write logic that runs whenever conditions are met. The following snippet shows a hypothetical scenario: checking if the token balance of an account has reached a certain threshold in order to transfer tokens or not.

{% @github-files/github-code-block url="<https://github.com/mimic-protocol/examples/blob/main/examples/04-transfer-balance-threshold-with-oracles/src/function.ts>" visible="false" %}

[Github link](https://github.com/mimic-protocol/examples/blob/main/examples/04-transfer-balance-threshold-with-oracles/src/function.ts)

**What’s happening here?**

* Your code runs inside the Planning Layer.
* It fetches data from oracles (prices and blockchain state) and checks a condition.
* If the condition holds, it creates an intent to perform a transfer, effectively handing off to the Execution Layer.
* Later, the solvers network picks this up, executes the best route, and the Settler finalizes the transaction on-chain.

***

### **Manifest configuration**

Your code is paired with a manifest file YAML defining:

* Function descriptive metadata
* Which trigger alternative will be used for the function.
* External parameters like the threshold (which can be adjusted without changing code).

{% @github-files/github-code-block url="<https://github.com/mimic-protocol/examples/blob/main/examples/04-transfer-balance-threshold-with-oracles/manifest.yaml>" visible="false" %}

[Github link](https://github.com/mimic-protocol/examples/blob/main/examples/04-transfer-balance-threshold-with-oracles/manifest.yaml)

### **Publishing your function**

Once you’re happy with your logic and configuration, you can compile it into a WebAssembly module and deploy it to the network.

```bash
# Compile the function
mimic compile

# Deploy the function
mimic deploy --api-key YOUR_DEPLOYMENT_KEY
```

By deploying, you announce your function is ready to be tracked by relayers, who will start executing it automatically under the conditions you set. For more details on the CLI commands, see the [CLI documentation](https://docs.mimic.fi/developers/cli).

***

### Next steps

1. [**Try out a simple function**](/examples/build-a-simple-function)

   Begin experimenting by following our step-by-step guides to write, compile, and deploy a basic function. This hands-on experience will help you understand the workflow, get comfortable with the tooling, and prepare you for building more complex, production-grade automations.
2. [**See more examples**](/examples/build-a-simple-function)

   Dive into additional use cases and real-world scenarios to spark ideas and discover how you can leverage Mimic for your specific needs. From automated contract maintenance to cross-chain data orchestration, exploring more examples will inspire you to craft tailored automation strategies.
3. [**Explore the whitepaper**](https://docs.mimic.fi/resources/whitepaper)

   For a comprehensive understanding of the underlying architecture, trust models, consensus mechanisms, and incentive structures that power Mimic, start with the whitepaper. It provides the technical depth and formal proofs to help you fully grasp how the protocol works and why it’s secure.
4. [**Check the roadmap**](/general/roadmap)

   Explore the Mimic team’s roadmap to see how the protocol will evolve over time. The roadmap provides insight into upcoming features, iterative enhancements, and the pragmatic steps planned to broaden Mimic’s capabilities. Stay informed and help shape the future of on-chain automation.


# Roadmap

This roadmap outlines the journey of Mimic Protocol from a developer-oriented release to a fully decentralized, incentive-driven automation network. Each phase is designed to gradually introduce key components, test their robustness, and improve the user experience before broadening participation and enabling economic incentives.

## Phase 0 — Developer environment MVP

### Goal

Establish a solid, developer-friendly foundation for Mimic Protocol. This initial phase focuses on delivering essential tooling and infrastructure so developers can experiment, build confidence, and shape the product through feedback. Minimal decentralization and no economic incentives will keep complexity low and foster rapid iteration.

### **Key deliverables**

* **Lib & CLI**

  Provide a software development kit and a compiler toolchain that let developers write functions in a high-level language, compile them to WASM, and easily integrate with Mimic’s logic.
* **Off-chain Registry**

  Host function definitions, manifests, and triggers will be stored in a private repository. This avoids prematurely introducing on-chain registries.
* **Off-chain Verifier**

  Implement a solid verification process for relayers off-chain, following the same scope and interface without relying on on-chain implementations for now.
* **Explorer App**

  A web-based explorer that lets developers monitor, debug, and visualize their functions’ execution, inputs, and outputs in real-time.
* **Private Mimic Relayer**

  Initially, Mimic will run a single trusted relayer to handle function execution in a free-tier mode. This streamlines early development and iteration without complexity.
* **Trusted Mimic Oracle**

  Initially, Mimic will provide a single trusted oracle to handle function inputs without full decentralization in a free-tier mode. Developers can rely on these data feeds to test their functions.
* **Private Solvers**

  Integrate the Axia module to handle intent execution with a whitelisted solvers set. No open competition at this stage.
* **Settler for Swap-Type Intents**

  Implement a baseline settler contract to finalize swap-related intents, ensuring a straightforward demo use case for automated operations.

### **Rationale**

Phase 0 ensures developers can quickly see that Mimic’s technology works. By avoiding premature complexity (like on-chain registries or open participation), we can refine UX, improve tooling, and learn from feedback.

***

## Phase 1 — Multichain support

### Goal

Build on the successes of Phase 0 by expanding Mimic’s features to support cross-chain operations and accommodate non-EVM environments. This broader functionality paves the way for increased adoption and demonstrates Mimic’s ability to handle more diverse and complex scenarios.

### **Key deliverables**

* **Cross-Chain Swap-Type Intents**

  Extend the baseline settler contract to handle swaps across multiple chains. Developers can define cross-chain swap intents that lock assets on one chain and execute corresponding operations on another, showcasing Mimic’s multi-chain capabilities.
* **Support for Non-EVM Chains**

  Implement new security layers and private solver solution for non-EVM chains. This means expanding the off-chain processes, and ensuring oracles/relayers can interact seamlessly with different consensus rules, block times, or transaction formats.

### **Rationale**

By offering cross-chain swap functionality and supporting diverse chain environments, Mimic becomes far more versatile. Teams can test advanced workflows and develop automation use cases that span multiple ecosystems—a critical step toward broader market adoption. This iterative approach also provides valuable insights into how Mimic’s architecture handles the additional complexity of multi-chain interactions, helping the team refine the system before opening it up to full decentralization and incentives.

***

## Phase 2 — Decentralizing the solvers network

### **Goal**

Expand from private to semi-open participation by introducing decentralized solvers. This lays the groundwork for competition, better pricing, and an early taste of open-network dynamics.

### **Key deliverables**

* **KYC Process for Solvers**

  Implement a simple vetting process to ensure reliable solvers join the network, maintaining a controlled environment during the transition.
* **Solvers Queues API**

  Provide an interface for solvers to queue up, receive intents, and submit proposals to Axia.
* **Open Solvers Network**

  Gradually open solver participation beyond the private set. Solvers can compete for intents, improving efficiency and pricing while still operating in a partially controlled ecosystem.

### **Rationale**

By introducing a competitive solver environment early, we’ll test assumptions about solver behavior, pricing mechanisms, and user satisfaction in a constrained scenario. Feedback here will guide the full decentralization and incentive design in later phases.

***

## Phase 3 — Expanding the oracles network

### **Goal**

Broaden data sourcing capabilities by onboarding more oracles while maintaining a controlled environment. Although still no direct incentives or penalties, adding diversity improves the resilience and reliability of data feeds.

### **Key deliverables**

* **KYC Process for Oracles**

  Introduce a vetting process to ensure data quality. Onboard a small set (5-10) of reputable oracles to test how multiple data sources combine in consensus mechanisms.
* **Oracles Queues API**

  Allow oracles to register their data availability and respond to queries through a standardized API.
* **Open Oracles Network**

  Expand beyond the initial trusted oracle set. While still capped and vetted, this step gives us insight into how multiple oracles affect data accuracy, latency, and consensus.

### **Rationale**

With multiple oracles in place, functions can rely on more diverse data. This phase primes the network for a more fully decentralized data layer, and lets us analyze how oracle variety impacts functions, consensus, and performance.

***

## Phase 4 — Expanding the relayers network

### **Goal**

Decentralize function execution by inviting external relayers. Until now, relayers were controlled or singular; this phase democratizes the execution environment, bringing it closer to the final vision.

### **Key deliverables**

* **KYC Process for Relayers**

  Screen new relayers to ensure reliability and honesty. This maintains quality as we open the gates.
* **On-Chain Functions Registry**

  Move from off-chain registries to an on-chain registry backed by smart contracts and IPFS, enabling trustless discovery and verification of functions.
* **On-Chain Verifier**

  Move from off-chain to an on-chain verifier contract that allows proving correctness of executions. No rewards or penalties yet; just a way to submit and verify proofs.
* **Functions Broadcast Mechanism**

  Provide a reliable, permissionless means for functions to be discovered and claimed by any relayer.
* **Open Relayers Network**

  Allow multiple relayers to pick functions, execute them, and submit proofs. This finalizes the primary infrastructure for a fully decentralized execution pipeline.

### **Rationale**

Decentralizing relayers ensures no single point of failure and brings us closer to the true trustless environment. Testing this with a vetted set first allows adjustments before enabling rewards and penalties.

***

## Phase 5 — Enabling economic incentives

### **Goal**

Introduce a utility token, staking mechanisms, rewards, and penalties. This is the final piece that transforms the network from a controlled testing ground into a fully open, self-sustaining, and economically driven system.

### **Key deliverables**

* **Utility Token & Staking Contracts**

  Introduce a governance and utility token that participants stake to provide security and signal reliability.
* **Governance Tooling**

  Empower the community to guide the protocol’s evolution, adjust parameters, and propose improvements.
* **Protocol Fees & Rewards**

  Enable fees for function execution, reward honest participants, and penalize malicious actors through slashing. This creates an incentive-aligned ecosystem where participants compete and collaborate for mutual benefit.
* **Fully Open Participation**

  Now anyone can become an oracle, relayer, or solver, backed by economic incentives that drive network health and performance.

### **Rationale**

Bringing in token-based incentives and governance cements Mimic as a fully decentralized and economically sound protocol. Participants are now motivated to maintain high standards, and the protocol can scale autonomously.

***

## Summary

* **Phase 0:** Developer-focused MVP with minimal complexity.
* **Phase 1:** Cross-chain intents.
* **Phase 2:** Introduce decentralized solvers and competition.
* **Phase 3:** Expand the oracles network while maintaining controlled environment.
* **Phase 4:** Expand the relayer network preparing for full trustlessness.
* **Phase 5:** Enable economic incentives and governance for a fully decentralized ecosystem.

By gradually rolling out features, ensuring quality and security at each step, and gathering feedback before expanding, Mimic Protocol sets the stage for a robust, trustless, and incentivized automation framework that evolves hand-in-hand with its community.


# Build a simple function

This guide provides step-by-step instructions on how to build and deploy a function to automate a blockchain operation using Mimic Protocol.

### **Workflow overview**

The process consists of the following steps:

1. **Initialize your project**: Start a working directory to develop your function from scratch.
2. **Define the manifest**: Specify function inputs, ABIs, and metadata in a manifest file.
3. **Write the function logic**: Implement your function logic.
4. **Build**: Validate the manifest, generate supporting artifacts, and compile the function logic.
5. **Deploy**: Upload your build output to a function registry, making it available for relayers to execute.

***

### Initialize your project <a href="#id-1.-initialize" id="id-1.-initialize"></a>

Let's start a new working directory to develop your function. To do that you can run the following command:

```bash
npx @mimicprotocol/cli init ./my-mimic-function
```

Let's continue analyzing the structure of this project.

***

### **Manifest definition**

The manifest file provides the configuration for your function, including:

* **Metadata**: Name, description, and version of the function.
* **Inputs**: Parameters required by the function logic.
* **ABIs**: Smart contract ABIs to generate type-safe interfaces for the function.

Save this configuration in a `manifest.yaml` file:

{% @github-files/github-code-block url="<https://github.com/mimic-protocol/examples/blob/main/examples/04-transfer-balance-threshold-with-oracles/manifest.yaml>" visible="false" %}

[Github link](https://github.com/mimic-protocol/examples/blob/main/examples/04-transfer-balance-threshold-with-oracles/manifest.yaml)

This manifest file defines different inputs that will be accessible from the function logic code thanks to the types generation process that will be explained in the next section.

Note that `inputs` and `abis` can be written in YAML as lists of single-key objects (as shown above). They are merged into maps during validation, and duplicate keys are rejected. ABI paths are resolved relative to the directory of your `manifest.yaml`.

Additionally, each input may include an optional description using the object form:

```yaml
inputs:
  - amount:
      type: uint256
      description: Amount to transfer in wei
  - recipient:
      type: address
      description: Target account address
```

For the purpose of this example you will need the ERC20 ABI, you can copy it from here:

{% file src="/files/RVbks3Xm1ai4RZWygXNX" %}

***

### Generate types

This steps allows you to validate the manifest definitions and generate the corresponding code to access both your declared inputs and the contract objects for your declared ABIs.

To do this you can run the `codegen` command using the CLI:

```bash
yarn mimic codegen
```

This command will output the generated types to `./src/types` by default. It will also assume your manifest file is called `manifest.yaml`. However, you can specify a different manifest or output paths using the following parameters:

```bash
yarn mimic codegen --manifest manifest.yml --output src/types
```

If you pass the `--clean` flag, you will be asked to confirm before deleting the existing contents of the output directory.

***

### **Writing the function logic**

The function logic is implemented in AssemblyScript and must export:

1. **Input type**: The generated `inputs` type from the previous step.
2. **Main function**: The core function logic, which receives the inputs as an argument.

Create a file `./src/function.ts` and implement the logic:

{% @github-files/github-code-block url="<https://github.com/mimic-protocol/examples/blob/main/examples/04-transfer-balance-threshold-with-oracles/src/function.ts>" visible="false" %}

[Github link](https://github.com/mimic-protocol/examples/blob/main/examples/04-transfer-balance-threshold-with-oracles/src/function.ts)

As you can see, the generated contract artifacts can be accessed from your function code.

Mimic functions express actions as **operations** wrapped inside an intent. Three operation types are available:

* **Transfer** — move tokens between addresses
* **Generic Call** — execute smart contract functions
* **Swap** — exchange tokens on a DEX (same-chain or cross-chain)

***

### Compile process

The compile process converts your function logic and manifest into deployable artifacts:

* `build/function.wasm` - Compiled WebAssembly binary
* `build/manifest.json` - Processed manifest configuration

Run the compile command:

```bash
yarn mimic compile
```

By default, outputs are saved in the `build` directory. You can customize the paths:

```bash
yarn mimic compile --function src/function.ts --manifest manifest.yaml --output build
```

Here is an example of the output produced by this command:

```bash
build/
├── function.wasm         # Compiled WASM binary
├── manifest.json     # Validated manifest
```

***

### Deploy your function

This is where you upload your function artifacts to the network so others can discover it. To do this you can run the `deploy` command using the CLI:

```bash
yarn mimic deploy --api-key [DEPLOYMENT_KEY]
```

You can generate a deployment key from the explorer app, where you can login using your wallet.

By default, this command will run code generation and compilation, then deploy the generated artifacts from the `build` directory. You can skip the build steps by passing `--skip-compile` if you already have up-to-date artifacts.

You can specify a different input/output directory using the following parameters:

```bash
yarn mimic deploy --input build --output build
```

This command will upload your artifacts to the Mimic Registry (which stores them on IPFS) and pin the resultant CID so it can be discovered by others. The CID is also written to `CID.json` in the specified output directory.

***

### Trigger your function

After deploying your function, you can now add a trigger, to tell which trigger relayers should use to run your function. This means defining the parameters declared in your `manifest.yml` file. This is done in the [explorer UI](https://protocol.mimic.fi/) where you will be requested to sign your trigger with your wallet or with the SDK.

1. Open the explorer and locate the function you just deployed under the functions section.
2. Add or edit your trigger parameters
3. Sign the new trigger

This signature ensures relayers know the trigger is authorized by the function owner.

You can update or deprecate this trigger at any point in time to reflect changes, without needing to redeploy the function code again. Just sign the new trigger in the explorer, and relayers will pick up the latest version.

***

### Next steps

1. [**Read more about the Lib**](/developers/library)

   Learn about available APIs for creating intents and interacting with contracts
2. [**Learn more about the CLI**](/developers/cli)

   Discover advanced CLI commands for testing, validating, and managing functions
3. [**Build more complex use cases**](/use-cases/dollar-cost-averaging-dca)\
   Expand your automation examples


# Using off-chain data

This page shows how to enrich your Mimic functions with **off‑chain data**. You’ll learn three common patterns:

1. **Pricing** convert token balances to USD
2. **Discovery of relevant tokens** for a user across a chain and bulk‑transfer them
3. **Custom subgraph queries** (e.g., fetch a Uniswap pool price)

We’ll walk through each pattern, the inputs they require, and implementation details you should keep in mind (precision, slippage, and fees).

> Pre-reqs: You’ve already read the basic function guide and can `mimic codegen`, `mimic compile`, and `mimic deploy`.

***

### Use price feeds to act on a USD threshold

**Goal:** Top up a recipient if their token balance (in USD) falls below a threshold.

{% @github-files/github-code-block url="<https://github.com/mimic-protocol/examples/blob/main/examples/04-transfer-balance-threshold-with-oracles/src/function.ts>" visible="false" %}

[Github link](https://github.com/mimic-protocol/examples/blob/main/examples/04-transfer-balance-threshold-with-oracles/src/function.ts)

**Notes**

* Convert all human‑readable decimals using `BigInt.fromStringDecimal(value, decimals)` to avoid precision loss.
* `maxFee` is specified in token units here; pass a USD‑denominated cap instead by using `TokenAmount.fromStringDecimal(DenominationToken.USD(), ...)` (see next example).

***

### Find relevant tokens and send them in one go

**Goal**: Detect which tokens a user actually holds on a chain and transfer any non‑zero balances to a recipient, paying a single USD‑capped fee.

{% @github-files/github-code-block url="<https://github.com/mimic-protocol/examples/blob/main/examples/08-relevant-tokens-query/src/function.ts>" visible="false" %}

[Github link](https://github.com/mimic-protocol/examples/blob/main/examples/08-relevant-tokens-query/src/function.ts)

**Notes**

* `getRelevantTokens` helps you focus on balances that matter. Supply an allow‑list if you want strict control over which tokens are considered.
* The fee cap is set in **USD** via `DenominationToken.USD()`; the runtime handles conversion.

***

### Query a subgraph for price and swap with slippage

**Goal**: Fetch a Uniswap pool price from a subgraph, compute expected output, apply slippage in BPS, and submit a swap intent.

{% @github-files/github-code-block url="<https://github.com/mimic-protocol/examples/blob/main/examples/09-subgraph-query/src/function.ts>" visible="false" %}

[Github link](https://github.com/mimic-protocol/examples/blob/main/examples/09-subgraph-query/src/function.ts)

**Why `PRICE_PRECISION = 40`?**

* Subgraph prices are strings with decimal precision. We parse them into a big integer using a high fixed precision (40) to minimize rounding error before scaling to token decimals. Match this with your downstream math so `upscale/downscale` lands on correct integer units.

**Slippage in BPS**

* `slippageBps = 50` → 0.50% buffer. We compute `minAmountOut = expectedOut * (1 − bps/10_000)`.

**Edge cases**

* Ensure the pool exists (`data.pools.length > 0`).
* Consider stable pools whose price may deviate
* Handle tokens with non‑standard decimals (e.g., 6, 8).


# Events and Function chaining

This page shows how to link your Mimic functions by **emitting and listening to custom events**. You’ll learn the full flow:

1. **Emitting an event** from a function
2. Creating an event trigger to **trigger another function** from the event
3. **Reading the event data** in the triggered function

> Pre-reqs: You’ve already read the basic function guide and can `mimic codegen`, `mimic compile`, and `mimic deploy`.

***

### Emit a custom event

**Goal:** Add an event with arbitrary information to an operation so it's emitted on-chain when the intent is executed.

Events are attached to **operations** (not to the intent itself), so you call `.addEvent()` on any operation builder — `EvmCallBuilder`, `SwapBuilder`, or `TransferBuilder` — before calling `.send()`.

```typescript
import { Address, Bytes, ChainId, Ethereum, EvmCallBuilder, evm, EvmEncodeParam, TokenAmount } from '@mimicprotocol/lib-ts'

export default function main(): void {
  const topic = evm.keccak('First function')
  const data = evm.encode([EvmEncodeParam.fromValue('address', '0xSomeAddress')])
  const fee = TokenAmount.fromStringDecimal(Ethereum.USDC, '1')

  EvmCallBuilder.forChain(ChainId.ETHEREUM)
    .addCall(Address.fromString('0xContractAddress'), callData)
    .addEvent(Bytes.fromHexString(topic), Bytes.fromHexString(data))
    .addUser('0xSmartAccountAddress')
    .send(fee)
}
```

The same `.addEvent()` method is available on `SwapBuilder` and `TransferBuilder`:

```typescript
SwapBuilder.forChains(ChainId.ETHEREUM, ChainId.OPTIMISM)
  .addTokenInFromStringDecimal(Ethereum.USDC, '1000')
  .addTokenOutFromStringDecimal(Optimism.USDC, '990', recipient)
  .addEvent(Bytes.fromHexString(topic), Bytes.fromHexString(data))
  .send()
```

***

### Trigger a function from a custom event

**Goal:** Automatically execute a second function every time an intent from the first function is executed.

```typescript
import { Chains, Client, TriggerType } from '@mimicprotocol/sdk'
import { AbiCoder, keccak256, toUtf8Bytes } from 'ethers'

async function main(): Promise<void> {
  const MIMIC_PROTOCOL_SETTLER = '0xSettlerAddress'
  const INTENT_EXECUTED_TOPIC = '0xee2c98c99b683f71058b8744fea294a411482f07d55c98b392917e9286f22f13'
  const USER_TOPIC = AbiCoder.defaultAbiCoder().encode(['address'], ['0xUserAddress'])
  const FIRST_FUNCTION_TOPIC = keccak256(toUtf8Bytes('First function'))

  const config = {
    type: TriggerType.Event
    chainId: Chains.SomeChain,
    contract: MIMIC_PROTOCOL_SETTLER,
    topics: [
      [INTENT_EXECUTED_TOPIC],
      [USER_TOPIC],
      [FIRST_FUNCTION_TOPIC],
    ],
  }

  const client = new Client({ signer })
  await client.triggers.signAndCreate({ SECOND_FUNCTION_CID, config, ... })
}
```

**Notes**

* The code above is a backend script, not a function.
* This section shows how to trigger a function from a custom event. However, it's also possible to **trigger functions from any smart contract event**, such as ERC-20 token transfers.

***

### Read event data

**Goal:** Access information included in the event.

```typescript
import { Address, environment, evm } from '@mimicprotocol/lib-ts'
import { IntentExecutedEvent } from './types/Settler'

export default function main(): void {
  const trigger = environment.getContext().triggerPayload.getEventData()
  const event = IntentExecutedEvent.decode(trigger.topics, trigger.eventData)
  const str = evm.decode(new EvmDecodeParam('address', event.data.toHexString()))
  const someAddress = Address.fromString(str) // 0xSomeAddress
}
```

***

### Use case

For a complete use case using custom events, see [Bridge and invest in Aave](/use-cases/bridge-and-invest-in-aave), where one function transfers tokens between chains and emits an event, and another function reacts to that event by investing the bridged tokens.


# Upgrade your EOA to a Mimic 7702

Traditional EOAs are designed for manual interaction and typically require repeated approvals and signatures, making them a poor fit for automated workflows.

This guide shows how to upgrade an existing EOA into a **Mimic 7702 smart account**, enabling automation-friendly behavior **without deploying a new smart account contract**.

***

### Can I deploy a smart account contract instead?

Yes, that's possible. However, there are some downsides to bear in mind:

* Deployment requires gas
* A new address must be managed
* Funds often need to be migrated

For many users, this upfront complexity is unnecessary.

***

### What EIP-7702 enables

EIP-7702 allows an EOA to **authorize a smart account implementation** via a special transaction.

This means:

* The EOA keeps the same address
* No deployment step is required
* The account can behave like a smart account when needed

***

### How Mimic uses EIP-7702

Mimic uses EIP-7702 to let EOAs opt into richer execution behavior only when required.

Once upgraded:

* The EOA can participate in automation flows
* Execution logic is delegated safely
* Repeated approvals are avoided

All execution complexity is handled by Mimic.

***

### Upgrading your EOA

Mimic provides a small [command-line tool](https://github.com/mimic-fi/mimic-7702-upgrade/) that performs the upgrade in a single transaction.

At a high level:

1. Configure your RPC and private key
2. Specify the official Mimic Smart Account address
3. Run the upgrade command

From your command line, clone the repository:

```bash
git clone https://github.com/mimic-fi/mimic-7702-upgrade
```

Enter the cloned repository and install dependencies:

```bash
cd mimic-7702-upgrade && yarn
```

Create a `.env` file from the example:

```bash
cp .env.example .env
```

Fill in the following variables:

* `RPC_URL` – RPC endpoint for the target chain
* `PRIVATE_KEY` – EOA private key to be upgraded
* `SMART_ACCOUNT_ADDRESS` – Official Mimic EIP-7702 Smart Account implementation address

{% hint style="warning" %}
EIP-7702 authorization is powerful. Only authorize Smart Account addresses provided by official Mimic sources.
{% endhint %}

#### Upgrade your EOA

```bash
yarn upgrade-7702
```

This sends a zero-value self-transaction containing an EIP-7702 authorization that upgrades the EOA to a Mimic smart account.

#### Check status

```bash
yarn status
```

This prints basic wallet and network information and provides helpful explorer links for manual verification.

#### Rollback your EOA

```bash
yarn downgrade-7702
```

This sends a zero-value self-transaction containing an EIP-7702 authorization that rolls back your EOA to its original status.


# Dollar-Cost Averaging (DCA)

The goal of this function is to periodically buy a fixed amount of a token using slippage-protected swaps.

For example, suppose the inputs are:

* Token In: USDC
* Token Out: WETH

And the cron trigger schedule is `30 19 * * 0`, meaning:

* `30` -> minute
* `19` -> hour UTC
* `*` -> every day of the month
* `*` -> every month
* `0` -> 0 = Sunday, 1 = Monday, etc

Then the function will buy 100 USDC worth of WETH every Sunday at 7:30 PM UTC.

### Function

{% @github-files/github-code-block url="<https://github.com/mimic-protocol/examples/blob/main/examples/12-dollar-cost-averaging/src/function.ts>" visible="false" %}

[Github link](https://github.com/mimic-protocol/examples/blob/main/examples/12-dollar-cost-averaging/src/function.ts)

### Manifest

{% @github-files/github-code-block url="<https://github.com/mimic-protocol/examples/blob/main/examples/12-dollar-cost-averaging/manifest.yaml>" visible="false" %}

[Github link](https://github.com/mimic-protocol/examples/blob/main/examples/12-dollar-cost-averaging/manifest.yaml)


# Fee collection

The goal of this function is to swap multiple tokens for USDC, and transfer the USDC to another account.

### Function

{% @github-files/github-code-block url="<https://github.com/mimic-protocol/examples/blob/main/examples/14-fee-collection/src/function.ts>" visible="false" %}

[Github link](https://github.com/mimic-protocol/examples/blob/main/examples/14-fee-collection/src/function.ts)

### Manifest

{% @github-files/github-code-block url="<https://github.com/mimic-protocol/examples/blob/main/examples/14-fee-collection/manifest.yaml>" visible="false" %}

[Github link](https://github.com/mimic-protocol/examples/blob/main/examples/14-fee-collection/manifest.yaml)


# Automated refunds

The goal here is to integrate a backend to send refunds through Mimic Protocol.

### Function

{% @github-files/github-code-block url="<https://github.com/mimic-protocol/examples/blob/main/examples/11-automated-refunds/src/function.ts>" visible="false" %}

[Github link](https://github.com/mimic-protocol/examples/blob/main/examples/11-automated-refunds/src/function.ts)

### Manifest

{% @github-files/github-code-block url="<https://github.com/mimic-protocol/examples/blob/main/examples/11-automated-refunds/manifest.yaml>" visible="false" %}

[Github link](https://github.com/mimic-protocol/examples/blob/main/examples/11-automated-refunds/manifest.yaml)

### Backend

{% @github-files/github-code-block url="<https://github.com/mimic-protocol/examples/blob/main/examples/11-automated-refunds/src/create-trigger.ts>" visible="false" %}

[Github link](https://github.com/mimic-protocol/examples/blob/main/examples/11-automated-refunds/src/create-trigger.ts)


# Tokens rebalancing

The goal of this function is to rebalance a three-token portfolio to reach specific target weights (measured in basis points), using USD valuations and slippage-protected swaps.

For example, suppose the targets are:

* 50% BTC
* 30% ETH
* 20% DAI

If the portfolio currently holds:

* $6,500 in BTC (65%)
* $2,500 in ETH (25%)
* $1,000 in DAI (10%)

Since BTC is overweight while ETH and DAI are underweight, the function will swap $500 worth of BTC into ETH and $1,000 worth of BTC into DAI to restore the target balance.

### Function

{% @github-files/github-code-block url="<https://github.com/mimic-protocol/examples/blob/main/examples/10-rebalancing-tokens/src/function.ts>" visible="false" %}

[Github link](https://github.com/mimic-protocol/examples/blob/main/examples/10-rebalancing-tokens/src/function.ts)

### Manifest

{% @github-files/github-code-block url="<https://github.com/mimic-protocol/examples/blob/main/examples/10-rebalancing-tokens/manifest.yaml>" visible="false" %}

[Github link](https://github.com/mimic-protocol/examples/blob/main/examples/10-rebalancing-tokens/manifest.yaml)

The ABI used for this example can be downloaded below:

{% file src="/files/RVbks3Xm1ai4RZWygXNX" %}


# Bridge and invest in Aave

This example involves two functions. The goal of the first function is to bridge tokens from one chain to another, and the goal of the second function is to invest in Aave the tokens received on the destination chain.

To achieve this, the bridge must complete before the investment begins. Mimic enables this kind of function concatenation by allowing one function to emit a custom event that triggers other functions in response.

The first function should include something as follows:

```tsx
SwapBuilder.forChains(ChainId.SOURCE, ChainId.DESTINATION)
  .addTokenInFromStringDecimal(tokenIn, '1000')
  .addTokenOutFromStringDecimal(tokenOut, '990', recipient)
  .addEvent(Bytes.fromHexString('0xCustomId'), Bytes.fromHexString('0xDataForTheOtherFunction'))
  .send()
```

And the trigger for the second function should look like:

```typescript
const config = {
  type: TriggerType.Event
  chainId: Chains.Optimism,
  contract: MIMIC_PROTOCOL_SETTLER,
  topics: [
    [INTENT_EXECUTED_TOPIC],
    [encode('0xUser')],
    ['0xCustomId'],
  ],
}

await client.triggers.signAndCreate({ ..., config })
```

With this trigger configuration, the invest function will automatically execute every time an intent from user `0xUser` emits an event containing `0xCustomId` on Optimism.

## 1. Bridge

### Function

{% @github-files/github-code-block url="<https://github.com/mimic-protocol/examples/blob/main/examples/13-bridge-and-invest-aave/src/bridge.ts>" visible="false" %}

[Github link](https://github.com/mimic-protocol/examples/blob/main/examples/13-bridge-and-invest-aave/src/bridge.ts)

### Manifest

{% @github-files/github-code-block url="<https://github.com/mimic-protocol/examples/blob/main/examples/13-bridge-and-invest-aave/manifest.bridge.yaml>" visible="false" %}

[Github link](https://github.com/mimic-protocol/examples/blob/main/examples/13-bridge-and-invest-aave/manifest.bridge.yaml)

## 2. Invest

### Function

{% @github-files/github-code-block url="<https://github.com/mimic-protocol/examples/blob/main/examples/13-bridge-and-invest-aave/src/invest.ts>" visible="false" %}

[Github link](http://github.com/mimic-protocol/examples/blob/main/examples/13-bridge-and-invest-aave/src/invest.ts)

### Manifest

{% @github-files/github-code-block url="<https://github.com/mimic-protocol/examples/blob/main/examples/13-bridge-and-invest-aave/manifest.invest.yaml>" visible="false" %}

[Github link](https://github.com/mimic-protocol/examples/blob/main/examples/13-bridge-and-invest-aave/manifest.invest.yaml)

### Backend

{% @github-files/github-code-block url="<https://github.com/mimic-protocol/examples/blob/main/examples/13-bridge-and-invest-aave/src/create-trigger.invest.ts>" visible="false" %}

[Github link](https://github.com/mimic-protocol/examples/blob/main/examples/13-bridge-and-invest-aave/src/create-trigger.invest.ts)

The ABIs used for this example can be downloaded below:

{% file src="/files/kA4B51gR3jkSykvbxDsN" %}

{% file src="/files/RVbks3Xm1ai4RZWygXNX" %}

{% file src="/files/LpjN7GOWXK6oQfBhRdUF" %}


# Getting Started

This section covers everything you need to start building automation functions on Mimic Protocol. It is organized into two skills that you can work through in order.

***

### What you need

* [Node.js](https://nodejs.org/) 18 or later
* A package manager: `npm`, `yarn`, or `pnpm`
* A Mimic account and API key — get one from the [Mimic explorer](https://protocol.mimic.fi/) under account settings

***

### The two skills

| Skill                                              | What you will learn                                                                              |
| -------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| [CLI](/skills/skill-cli)                           | Install and use the Mimic CLI to scaffold, build, and deploy functions                           |
| [Writing a Mimic Function](/skills/skill-function) | Understand the function anatomy, library APIs, intents, queries, logging, and persistent storage |

***

### Development workflow at a glance

```
npx @mimicprotocol/cli init my-function   # scaffold project
cd my-function
yarn mimic codegen                         # generate types from manifest
# ... write your function logic ...
yarn mimic compile                         # compile to WASM
yarn mimic deploy                          # upload to IPFS registry
```

After deploying, open the [explorer](https://protocol.mimic.fi/), find your function, create a trigger, and sign it with your wallet. Relayers will pick it up and execute it automatically.

***

### Next steps

* [CLI skill](/skills/skill-cli) — start here if you are new to the toolchain
* [Function skill](/skills/skill-function) — learn how to write function logic using the library
* [Examples](/examples/build-a-simple-function) — end-to-end walkthroughs for common automation patterns


# Skill: CLI

The Mimic CLI (`@mimicprotocol/cli`) is the main tool for scaffolding, building, and deploying functions. You use it via `npx` without a global install, or as a local dev dependency invoked through `yarn mimic`.

## Recommended Agent Workflow

When an AI agent helps with Mimic projects, follow these defaults:

1. Always verify the CLI version first and prefer the latest release.
2. For new projects, always start with `init` instead of creating files manually.

### 1) Always use the latest CLI

Use the latest CLI when running ad-hoc commands:

```bash
npx @mimicprotocol/cli@latest <command>
```

If the project uses a local dev dependency, check and update it before continuing:

```bash
yarn mimic --version
npm view @mimicprotocol/cli version
yarn add -D @mimicprotocol/cli@latest
```

This avoids version drift across workspaces and prevents docs/code mismatches.

### 2) Start new projects with `init`

For new function projects, bootstrap with `init` first, even when working in multi-workspace setups:

```bash
npx @mimicprotocol/cli@latest init [directory]
```

`init` creates the correct baseline (`manifest.yaml`, TypeScript setup, starter function, dependencies, and codegen). Manual scaffolding should be the exception, not the default.

***

## Installation

No global install required. Run any command directly with `npx`:

```bash
npx @mimicprotocol/cli@latest <command>
```

Or add it as a local dev dependency and invoke it through yarn scripts:

```bash
yarn add -D @mimicprotocol/cli@latest
yarn mimic <command>
```

***

## Commands

### `init` — Scaffold a new project

Creates a minimal project structure with a manifest file, a starter function, and all dependencies.

```bash
npx @mimicprotocol/cli@latest init [directory] [--force]
```

| Option        | Description                                      | Default |
| ------------- | ------------------------------------------------ | ------- |
| `directory`   | Where to initialize the project                  | `./`    |
| `--force, -f` | Overwrite existing files (asks for confirmation) | `false` |

**Examples**

```bash
# New project in ./my-function
npx @mimicprotocol/cli@latest init ./my-function

# Reinitialize in an existing directory
npx @mimicprotocol/cli@latest init ./my-function --force
```

**Output structure**

```
my-function/
├── manifest.yaml      # Function metadata, inputs, and ABI references
├── package.json
├── tsconfig.json
└── src/
    └── function.ts    # Your AssemblyScript function
```

After scaffolding, the CLI automatically runs `yarn install` and `yarn codegen`.

***

### `codegen` — Generate types from the manifest

Reads `manifest.yaml` and generates typed AssemblyScript interfaces for declared inputs and ABIs into `src/types/`.

```bash
yarn mimic codegen [--manifest <path>] [--output <dir>] [--clean]
```

| Option           | Description                                                   | Default         |
| ---------------- | ------------------------------------------------------------- | --------------- |
| `--manifest, -m` | Path to manifest file                                         | `manifest.yaml` |
| `--output, -o`   | Output directory for generated types                          | `./src/types`   |
| `--clean, -c`    | Delete existing types before regenerating (asks confirmation) | `false`         |

**Examples**

```bash
yarn mimic codegen
yarn mimic codegen --manifest ./custom-manifest.yaml --output ./src/generated
yarn mimic codegen --clean
```

**Output**

* `src/types/index.ts` — Input parameter types
* `src/types/<ContractName>.ts` — One file per ABI, with read/write methods and event decoders

{% hint style="info" %}
Run `codegen` every time you change `manifest.yaml`. Generated files are meant to be committed — do not edit them manually.
{% endhint %}

***

### `compile` — Build to WebAssembly

Validates the manifest and compiles your AssemblyScript function into a WASM binary.

```bash
yarn mimic compile [--function <path>] [--manifest <path>] [--output <dir>]
```

| Option           | Description           | Default           |
| ---------------- | --------------------- | ----------------- |
| `--function, -f` | Path to entry file    | `src/function.ts` |
| `--manifest, -m` | Path to manifest file | `manifest.yaml`   |
| `--output, -o`   | Output directory      | `build`           |

**Examples**

```bash
yarn mimic compile
yarn mimic compile --function ./functions/myFunction.ts --output ./out
```

**Output**

```
build/
├── function.wasm     # Compiled WebAssembly binary
└── manifest.json     # Validated manifest
```

***

### `login` — Save your API key locally

Stores credentials in `~/.mimic/credentials` so you don't need to pass `--api-key` on every deploy.

```bash
mimic login [--profile <name>] [--api-key <key>] [--force-login]
```

| Option              | Description                                     | Default   |
| ------------------- | ----------------------------------------------- | --------- |
| `--profile, -p`     | Profile name                                    | `default` |
| `--api-key, -k`     | API key (skips interactive prompt)              | —         |
| `--force-login, -f` | Overwrite existing profile without confirmation | `false`   |

**Examples**

```bash
mimic login                                              # interactive
mimic login --profile staging --api-key YOUR_API_KEY    # non-interactive
```

{% hint style="info" %}
Retrieve your API key from the [Mimic explorer](https://protocol.mimic.fi/) under account settings. Profile names cannot contain `[`, `]`, or `=`.
{% endhint %}

***

### `logout` — Remove stored credentials

```bash
mimic logout [--profile <name>] [--force]
```

```bash
mimic logout                    # removes default profile, asks confirmation
mimic logout --profile staging
mimic logout --force            # skips confirmation
```

***

### `profiles` — List configured profiles

```bash
mimic profiles
```

```
Configured profiles (stored in ~/.mimic/credentials):

* default (default)
* staging
* production

Use mimic deploy --profile <name> to deploy with a specific profile.
```

***

### `deploy` — Upload to the Mimic Registry

Runs codegen + compile (unless skipped), uploads artifacts to IPFS, and registers the function in the Mimic Registry so relayers can discover it.

```bash
yarn mimic deploy [options]
```

| Option           | Description                       | Default                         |
| ---------------- | --------------------------------- | ------------------------------- |
| `--api-key, -k`  | API key                           | —                               |
| `--profile, -p`  | Credential profile to use         | `default`                       |
| `--input, -i`    | Directory with compiled artifacts | `build`                         |
| `--output, -o`   | Directory to write the CID file   | `build`                         |
| `--skip-compile` | Skip codegen and compile          | `false`                         |
| `--url, -u`      | Registry base URL                 | `https://api-protocol.mimic.fi` |

**Examples**

```bash
yarn mimic deploy                               # uses default profile
yarn mimic deploy --api-key my-key
yarn mimic deploy --profile production
yarn mimic deploy --input ./dist --skip-compile
```

**Before uploading**, the CLI validates that `build/` contains both `manifest.json` and `function.wasm`.

**Output**: `build/CID.json` — the IPFS Content Identifier for your deployed function.

***

### `test` — Run function tests

Runs `codegen` + `compile`, then executes `tests/**/*.spec.ts` with Mocha.

```bash
yarn mimic test [--directory <path>] [--skip-compile]
```

| Option            | Description                           | Default |
| ----------------- | ------------------------------------- | ------- |
| `--directory, -d` | Function directory to test            | `./`    |
| `--skip-compile`  | Skip codegen and compile before tests | `false` |

```bash
yarn mimic test
yarn mimic test --skip-compile    # if artifacts are already up to date
```

***

## Multi-function projects (`mimic.yaml`)

For projects with more than one function, create a `mimic.yaml` at the project root. All commands (`codegen`, `compile`, `test`, `deploy`) will iterate over every function defined in it.

```yaml
functions:
  - name: function-one
    manifest: ./function-one/manifest.yaml
    function: ./function-one/src/function.ts
    build-directory: ./function-one/build
    types-directory: ./function-one/src/types

  - name: function-two
    manifest: ./function-two/manifest.yaml
    function: ./function-two/src/function.ts
    build-directory: ./function-two/build
    types-directory: ./function-two/src/types
```

**Filtering**

```bash
# Only run for specific functions
yarn mimic compile --include function-one function-two

# Run for all except one
yarn mimic codegen --exclude function-two

# Override the config file location
yarn mimic compile --config-file ./config/functions.yaml

# Ignore mimic.yaml entirely
yarn mimic compile --no-config --function ./src/function.ts
```

{% hint style="info" %}
`mimic.yaml` is optional — single-function projects can continue using individual command flags without it.
{% endhint %}


# Skill: Writing a Function

A Mimic function is an AssemblyScript module compiled to WebAssembly. It runs inside a sandboxed environment on every trigger execution, receives typed inputs from the manifest, queries on-chain and off-chain data, and emits **intents** — declarations of what you want to happen on-chain.

***

## Project anatomy

```
my-function/
├── manifest.yaml          # Inputs, ABIs, and metadata
├── src/
│   ├── function.ts        # Your function logic (entry point)
│   └── types/             # Auto-generated by `mimic codegen`
│       ├── index.ts       # Typed inputs
│       └── ERC20.ts       # Generated ABI wrapper (one per ABI)
└── build/
    ├── function.wasm      # Compiled output
    └── manifest.json      # Validated manifest
```

***

## Manifest

The manifest describes your function's metadata, inputs, and contract ABIs. The CLI uses it to validate, generate types, compile, and deploy.

```yaml
version: 1.0.0
name: My Automation Function
description: Swaps USDC to ETH when balance exceeds a threshold.
inputs:
  - chainId: int32
  - smartAccount: address
  - tokenIn: address
  - tokenOut: address
  - threshold: string
  - feeAmount: string
abis:
  - ERC20: "./abis/ERC20.json"
```

Inputs can optionally include a description:

```yaml
inputs:
  - threshold:
      type: string
      description: Minimum balance in human-readable units, e.g. "100.5"
  - feeAmount:
      type: string
      description: Max fee in USD, e.g. "1.5"
```

**All token amounts should be declared as `string`** and converted in code with `fromStringDecimal`. This keeps the UI human-readable — a user types `1` for 1 USDC, not `1000000`.

```typescript
// In the manifest: threshold: string
// In the function:
const threshold = TokenAmount.fromStringDecimal(Tokens.USDC.on(inputs.chainId), inputs.threshold)
const fee       = TokenAmount.fromStringDecimal(DenominationToken.USD(), inputs.feeAmount)
```

**Input type mapping** — manifest types and the AssemblyScript types they produce:

| Manifest type        | AssemblyScript type |
| -------------------- | ------------------- |
| `int32`              | `i32`               |
| `int64`              | `i64`               |
| `uint8`              | `u8`                |
| `uint16`             | `u16`               |
| `uint32`             | `u32`               |
| `uint64`             | `u64`               |
| `uint256` / `int256` | `BigInt`            |
| `address`            | `Address`           |
| `bytes` / `bytesN`   | `Bytes`             |
| `string`             | `string`            |

* `inputs` and `abis` are merged into maps during validation — duplicate keys are rejected.
* ABI paths are resolved relative to the directory of your `manifest.yaml`.

***

## Function structure

Every function must export a `main` function. The inputs type is auto-generated from your manifest.

```typescript
import { environment, log, TokenAmount, TransferBuilder } from '@mimicprotocol/lib-ts'
import { inputs } from './types'

export default function main(): void {
  // 1. Read inputs
  const account = inputs.account
  const threshold = inputs.threshold

  // 2. Query on-chain or off-chain data
  const balanceResult = environment.relevantTokensQuery(account, [inputs.chainId])
  if (balanceResult.isError) {
    log.error('Failed to query balances: {}', [balanceResult.error])
    return
  }

  // 3. Apply logic and emit intents
  const balances = balanceResult.unwrap()
  // ... build and send an intent
}
```

***

## Library reference (`@mimicprotocol/lib-ts`)

### Primitives

```typescript
import { Address, BigInt, Bytes } from '@mimicprotocol/lib-ts'

// Address
const addr    = Address.fromString('0x...')
const zero    = Address.zero()

// BigInt — used for all token amounts and large numbers
const amount  = BigInt.fromString('1000000000000000000') // 1 ETH in wei
const doubled = amount.times(BigInt.fromI32(2))
const power   = BigInt.fromI32(10).pow(18)

// Bytes — arbitrary byte data
const data    = Bytes.fromHexString('0x095ea7b3...')
const empty   = Bytes.empty()
const utf8    = Bytes.fromUTF8('hello')
```

***

### Tokens and amounts

#### Pre-defined tokens

There are two ways to reference a known token depending on whether the chain is fixed or dynamic.

**Chain namespaces** — use when the chain is known at compile time:

```typescript
import { Ethereum, Arbitrum, Base, Optimism, Gnosis, Polygon, Avalanche, BNB, Sonic } from '@mimicprotocol/lib-ts'

const usdc = Ethereum.USDC   // ERC20Token with address, chainId, decimals and symbol pre-filled
const eth  = Ethereum.ETH
const wbtc = Arbitrum.WBTC
```

**`Tokens` class** — use when the chain comes from `inputs.chainId` at runtime:

```typescript
import { Tokens } from '@mimicprotocol/lib-ts'

// Resolves the correct USDC address for whatever chain the user configured
const usdc = Tokens.USDC.on(inputs.chainId)

// Check before resolving if the token might not be supported on all chains
if (Tokens.USDC.isSupported(inputs.chainId)) {
  const usdc = Tokens.USDC.on(inputs.chainId)
}
```

Available tokens in `Tokens`: `USDC`, `USDT`, `DAI`, `WBTC`, `WETH`, `ETH`, `AVAX`, `WAVAX`, `POL`, `WPOL`, `BNB`, `WBNB`, `XDAI`, `WXDAI`, `SONIC`, `WSONIC`.

**`ERC20Token.fromString`** — last resort for tokens not in the registry:

```typescript
import { ERC20Token } from '@mimicprotocol/lib-ts'

// Decimals and symbol are optional — if omitted they are fetched on-chain lazily when first accessed.
// Provide them when known to avoid the extra RPC calls.
const myToken    = ERC20Token.fromString('0x...', inputs.chainId)             // lazy on-chain fetch
const myTokenOpt = ERC20Token.fromString('0x...', inputs.chainId, 18, 'MYT') // no extra calls
```

#### DenominationToken

`DenominationToken.USD()` is the standard way to express max fees. It is **not** a real on-chain token — it deducts from the user's Mimic credits. It can **only** be used as the fee argument to `.send()` or `IntentBuilder.addMaxFee()`. You cannot transfer or swap it.

```typescript
import { DenominationToken, TokenAmount } from '@mimicprotocol/lib-ts'

const fee = TokenAmount.fromStringDecimal(DenominationToken.USD(), inputs.feeAmount)

// Only valid use — passing to .send() or IntentBuilder.addMaxFee()
intentBuilder.addMaxFee(fee)
builder.build().send(fee)
```

#### TokenAmount

```typescript
import { TokenAmount, USD } from '@mimicprotocol/lib-ts'

const amount   = TokenAmount.fromStringDecimal(usdc, '1000.50')              // 1000.5 USDC
const native   = TokenAmount.fromI32(eth, 5)                                 // 5 ETH
const raw      = TokenAmount.fromBigInt(usdc, BigInt.fromString('1000000'))  // 1 USDC (6 decimals)

// Price conversions
const usdValue = amount.toUsd().unwrap()                    // USD
const inWbtc   = amount.toTokenAmount(Ethereum.WBTC).unwrap() // TokenAmount

// USD
const usd    = USD.fromStringDecimal('1000')
const inUsdc = usd.toTokenAmount(Ethereum.USDC).unwrap()
```

***

### Result type

All queries (except `getContext`) return `Result<V, string>`. Always handle errors.

```typescript
import { Result } from '@mimicprotocol/lib-ts'

const result = environment.tokenPriceQuery(Ethereum.USDC)

// Check state
result.isOk    // true on success
result.isError // true on failure

// Unwrap
result.unwrap()              // throws if error
result.unwrapOr(USD.zero())  // fallback value
result.unwrapOrElse(() => {  // fallback function
  log.warning('Price unavailable, using zero')
  return USD.zero()
})

// Access error message
if (result.isError) log.error('Error: {}', [result.error])
```

***

### Environment queries

#### Token price

```typescript
import { environment, Ethereum } from '@mimicprotocol/lib-ts'

// Current USD price (median across sources)
const price = environment.tokenPriceQuery(Ethereum.USDC).unwrap()

// Historical price
const historical = environment.tokenPriceQuery(Ethereum.USDC, new Date(1640995200000)).unwrap()
```

#### Relevant token balances

Returns all token balances for an address, with optional chain, allow/deny list, and USD minimum filters.

```typescript
import { environment, Address, ChainId, ListType, USD } from '@mimicprotocol/lib-ts'

// All tokens on Ethereum and Polygon worth at least $100, excluding USDT
const tokens = environment.relevantTokensQuery(
  userAddress,
  [ChainId.ETHEREUM, ChainId.POLYGON],
  USD.fromStringDecimal('100'),
  [Ethereum.USDT],
  ListType.DenyList
).unwrap()  // TokenAmount[]
```

#### EVM contract read (raw)

Use generated ABI wrappers (see below) instead of raw calls where possible.

```typescript
const response = environment.evmCallQuery(
  Address.fromString('0xcontract'),
  ChainId.ETHEREUM,
  '0x70a08231' + encodedArgs,  // selector + ABI-encoded params
  null                          // optional timestamp
).unwrap()  // raw hex string
```

#### Native token balance

```typescript
const balance = environment.getNativeTokenBalance(ChainId.ETHEREUM, userAddress).unwrap() // BigInt in wei
```

#### Account code

```typescript
const code = environment.getCode(ChainId.ETHEREUM, contractAddress).unwrap() // Bytes
```

#### Subgraph query

```typescript
const result = environment.subgraphQuery(
  ChainId.ETHEREUM,
  'QmSubgraphId',
  '{ tokens(first: 5) { id symbol } }',
  null  // optional timestamp
).unwrap()  // SubgraphQueryResult
```

#### Execution context

`getContext()` does not return a `Result` — it cannot fail.

```typescript
import { environment, ChainId, TriggerType } from '@mimicprotocol/lib-ts'

const ctx = environment.getContext()

ctx.user               // Address — the user this trigger belongs to
ctx.timestamp          // u64 — current execution timestamp in milliseconds
ctx.consensusThreshold // u8 — minimum number of agreeing relayers required
ctx.triggerSig         // string — unique signature of the trigger

// Access trigger payload data
const payload = ctx.triggerPayload
if (payload.type == TriggerType.CRON) {
  const scheduleTimestamp = payload.getCronData()  // BigInt
}
if (payload.type == TriggerType.EVENT) {
  const eventData = payload.getEventData()
  // eventData.chainId, eventData.contract, eventData.topics, eventData.eventData
}
```

***

### Generated ABI wrappers

After running `mimic codegen`, each ABI declared in the manifest produces a file in `src/types/<ContractName>.ts` containing four things:

1. **The contract class** — instantiate with `(address, chainId, timestamp?)` to call methods
2. **A `<ContractName>Utils` static class** — raw encode/decode helpers (rarely needed directly)
3. **Struct/tuple classes** — one per Solidity struct or multi-output tuple
4. **Event classes** — one per event, with a `static decode(topics, data)` method

#### Contract class — read and write methods

```typescript
import { ChainId } from '@mimicprotocol/lib-ts'
import { ERC20 } from './types/ERC20'

const token = new ERC20(tokenAddress, ChainId.ETHEREUM)

// Read methods — call the contract and return Result<T, string>
const balanceResult = token.balanceOf(userAddress)  // Result<BigInt, string>
if (balanceResult.isError) return
const balance = balanceResult.unwrap()

// Write methods — return an EvmCallBuilder, do not call the chain directly
const approveBuilder = token.approve(spenderAddress, amount)  // EvmCallBuilder
approveBuilder.build().send(fee)

// Historical queries — pass a timestamp as third constructor arg
const historicalToken = new ERC20(tokenAddress, ChainId.ETHEREUM, new Date(1640995200000))
```

#### Struct classes

Solidity structs and multi-output tuples become generated classes with typed fields. You typically receive them as unwrapped return values from read methods — you don't construct them manually.

```typescript
// If a read method returns a struct, unwrap it and access its fields directly
const feeState = contract.getFeeState().unwrap()  // FeeState
const recipient = feeState.feeRecipient            // Address
const percentage = feeState.streamingFeePercentage // BigInt
```

#### Event classes

Each event gets a class with a `static decode(topics, data)` method, matching the shape of the `TriggerType.EVENT` payload:

```typescript
import { MyContract, MyContractTransferEvent } from './types/MyContract'

const eventData = ctx.triggerPayload.getEventData()
const event = MyContractTransferEvent.decode(eventData.topics, eventData.eventData)
const from   = event.from   // Address
const value  = event.value  // BigInt
```

#### Utils class

The `<ContractName>Utils` static class exposes `encodeX()` and `decodeX()` methods for raw ABI encoding. Use these only when you need the raw encoded bytes — for example to pass a call directly to `addCall()` without instantiating the contract class.

```typescript
import { ERC20Utils } from './types/ERC20'

const data = ERC20Utils.encodeTransfer(recipientAddress, amount)  // Bytes
builder.addCall(tokenAddress, data)
```

#### Solidity → AssemblyScript type mapping

| Solidity                           | AssemblyScript          |
| ---------------------------------- | ----------------------- |
| `address`                          | `Address`               |
| `bool`                             | `bool`                  |
| `string`                           | `string`                |
| `bytes` / `bytesN`                 | `Bytes`                 |
| `uint8`–`uint16`, `int8`–`int16`   | `u8`/`u16`/`i8`/`i16`   |
| `uint32`–`uint64`, `int32`–`int64` | `u32`/`u64`/`i32`/`i64` |
| `uint256` / `int256`               | `BigInt`                |
| `T[]`                              | `T[]`                   |
| `tuple` / `struct`                 | generated class         |

***

### Intent builders

Intents are declarations of what you want to happen. The protocol finds the best way to fulfill them.

#### Transfer — move tokens between addresses

```typescript
import { Address, ChainId, Ethereum, TokenAmount, TransferBuilder } from '@mimicprotocol/lib-ts'

const fee = TokenAmount.fromStringDecimal(Ethereum.USDC, '1')

TransferBuilder.forChain(ChainId.ETHEREUM)
  .addTransferFromStringDecimal(Ethereum.USDC, '500', recipientAddress)
  .addTransferFromStringDecimal(Ethereum.WBTC, '0.01', recipientAddress)
  .build()
  .send(fee)
```

#### Swap — exchange tokens

```typescript
import { Arbitrum, ChainId, Ethereum, SwapBuilder } from '@mimicprotocol/lib-ts'

const fee = TokenAmount.fromStringDecimal(Ethereum.USDC, '1')

// Same-chain swap
SwapBuilder.forChain(ChainId.ETHEREUM)
  .addTokenInFromStringDecimal(Ethereum.USDC, '1000')
  .addTokenOutFromStringDecimal(Ethereum.USDT, '990', recipientAddress)  // min amount out
  .build()
  .send(fee)

// Cross-chain swap
SwapBuilder.forChains(ChainId.ETHEREUM, ChainId.ARBITRUM)
  .addTokenInFromStringDecimal(Ethereum.USDC, '1000')
  .addTokenOutFromStringDecimal(Arbitrum.USDC, '990', recipientAddress)
  .build()
  .send(fee)
```

The `tokenOut` amount is a **minimum** — relayers may deliver more.

#### EVM Call — execute contract functions

```typescript
import { Address, ChainId, Ethereum, EvmCallBuilder, TokenAmount } from '@mimicprotocol/lib-ts'
import { MyContract } from './types/MyContract'

const contract = new MyContract(contractAddress, ChainId.ETHEREUM)
const fee = TokenAmount.fromStringDecimal(Ethereum.USDC, '1')

// Single call from a generated wrapper
contract.myFunction(arg1, arg2)  // returns EvmCallBuilder
  .build()
  .send(fee)

// Multiple calls in one intent — use addCallsFromBuilder to merge generated wrappers.
// This is preferred over extracting and re-encoding data manually with addCall.
EvmCallBuilder.forChain(ChainId.ETHEREUM)
  .addCallsFromBuilder(contract.functionA(arg1))
  .addCallsFromBuilder(contract.functionB(arg2))
  .addUser(inputs.smartAccount)
  .build()
  .send(fee)

// Or pass all builders at once
EvmCallBuilder.forChain(ChainId.ETHEREUM)
  .addCallsFromBuilders([contract.functionA(arg1), contract.functionB(arg2)])
  .addUser(inputs.smartAccount)
  .build()
  .send(fee)

// Use addCall directly only when you have raw encoded data (e.g. from a multicall response)
EvmCallBuilder.forChain(ChainId.ETHEREUM)
  .addCall(contractAddress, encodedData)           // value defaults to 0
  .addCall(contractAddress, encodedData2, BigInt.fromI32(1000)) // optional ETH value for payable calls
  .build()
  .send(fee)
```

#### Common builder options

All builders support these optional methods before `.build()`:

| Method                   | Purpose                                    |
| ------------------------ | ------------------------------------------ |
| `.addUser(address)`      | Override the user (defaults to `ctx.user`) |
| `.addEvent(topic, data)` | Attach an on-chain event to the operation  |
| `.addEvents(events[])`   | Attach multiple events                     |

The Intent builder supports these optional methods before `.build()`:

| Method                    | Purpose                                                |
| ------------------------- | ------------------------------------------------------ |
| `.addFeePayer(address)`   | Override the fee payer (defaults to `ctx.user`)        |
| `.addDeadline(timestamp)` | Override the deadline (defaults to 5 minutes from now) |
| `.addNonce(string)`       | Override the nonce (defaults to auto-generated)        |
| `.addMaxFee(TokenAmount)` | Sets max fee that can be paied for the intent          |

**When to use `.addUser()`:**

* **Transfer / Swap intents** — `ctx.user` is the default and is correct for most cases. `ctx.user` is the EOA that signed and triggered the function, so you normally do not need to call `.addUser()`.
* **EVM Call intents** — you must call `.addUser(inputs.smartAccount)`. EVM Call intents execute generic contract calls, which require a smart account. `ctx.user` is an EOA and cannot fulfill this role.

```typescript
// Transfer — ctx.user is the default, no .addUser() needed
TransferBuilder.forChain(inputs.chainId)
  .addTransferFromTokenAmount(tokenAmount, recipientAddress)
  .build()
  .send(fee)

// EVM Call — smart account required
EvmCallBuilder.forChain(inputs.chainId)
  .addCall(contractAddress, callData)
  .addUser(inputs.smartAccount)  // required for generic calls
  .build()
  .send(fee)
```

**Guarding against empty intents:**

Never send an intent with no transfers, calls, or swaps. If you are conditionally adding items (e.g. iterating over a list), check the builder before sending. If you are unconditionally adding at least one item, no guard is needed.

```typescript
// Guard needed — items are added conditionally inside a loop
const builder = TransferBuilder.forChain(inputs.chainId)
for (let i = 0; i < tokenBalances.length; i++) {
  if (tokenBalances[i].amount.gt(BigInt.zero())) {
    builder.addTransferFromTokenAmount(tokenBalances[i], inputs.recipient)
  }
}
if (builder.transfers.length > 0) {  // only send if something was added
  builder.build().send(fee)
}

// No guard needed — the call is always added
EvmCallBuilder.forChain(inputs.chainId)
  .addCall(contractAddress, callData)
  .addUser(inputs.smartAccount)
  .build()
  .send(fee)
```

**Batching large numbers of items:**

A single intent may not fit in one transaction if it contains too many calls, transfers, or swaps. If you are building a variable-length list, split it into batches of at most 20 items and send one intent per batch.

```typescript
const BATCH_SIZE = 20

for (let i = 0; i < calls.length; i += BATCH_SIZE) {
  const builder = EvmCallBuilder.forChain(inputs.chainId)
  const end = i + BATCH_SIZE < calls.length ? i + BATCH_SIZE : calls.length
  for (let j = i; j < end; j++) {
    builder.addCall(calls[j].address, calls[j].data)
  }
  builder.addUser(inputs.smartAccount).build().send(fee)
}
```

***

### Persistent storage

Use the `storage` namespace to read and write arbitrary bytes to the user's on-chain storage via the Mimic Helper contract. Useful for maintaining state between executions.

```typescript
import { environment, storage, Bytes, ChainId, TokenAmount, DenominationToken } from '@mimicprotocol/lib-ts'

const userAddress = environment.getContext().user
const fee = TokenAmount.fromStringDecimal(DenominationToken.USD(), '0.5')

// Write — emits an EvmCall intent that stores the data on-chain
storage.createSetDataCall(
  userAddress,
  fee,
  'last-execution',                    // storage key
  Bytes.fromUTF8('2024-01-01'),        // value (arbitrary bytes)
  ChainId.OPTIMISM                     // chain (defaults to Optimism)
).send()

// Read — synchronous on-chain call, returns Result<Bytes, string>
const dataResult = storage.getData(userAddress, 'last-execution', ChainId.OPTIMISM)
if (dataResult.isOk) {
  const value = dataResult.unwrap().toString()
}
```

***

### Logging

```typescript
import { log } from '@mimicprotocol/lib-ts'

// Format string style — {} placeholders replaced in order
log.debug('Processing account {}', [account.toHexString()])
log.info('Balance: {} USDC', [balance.toString()])
log.warning('Slippage is high: {}%', [slippage.toString()])
log.error('Token price query failed: {}', [result.error])

// Template literal style — equivalent and more readable for inline expressions
log.info(`Balance: ${balance.toString()} USDC`)
log.info(`Processing pool ${pool}, token ${token}, fees ${fees.toString()}`)

// CRITICAL terminates execution immediately
log.critical('Unexpected state, aborting')
```

Both styles work. Template literals are preferred for multi-variable messages; format strings are preferred when you need to call `.toString()` on custom types. Levels: `DEBUG < INFO < WARNING < ERROR < CRITICAL`.

***

### EVM utilities

```typescript
import { evm, EvmEncodeParam, EvmDecodeParam, Address, BigInt } from '@mimicprotocol/lib-ts'

// ABI-encode parameters
const encoded = evm.encode([
  EvmEncodeParam.fromValue('address', Address.zero()),
  EvmEncodeParam.fromValue('uint256', BigInt.fromI32(100)),
])

// ABI-decode a response
const decoded = evm.decode(new EvmDecodeParam('uint256', responseHex))

// Keccak-256 hash
const hash = evm.keccak('some data')
```

***

## Putting it together — annotated example

```typescript
import {
  Address, ChainId, DenominationToken, Ethereum, environment, log,
  SwapBuilder, TokenAmount,
} from '@mimicprotocol/lib-ts'
import { inputs } from './types'
import { ERC20 } from './types/ERC20'

export default function main(): void {
  const ctx     = environment.getContext()
  const account = ctx.user
  const token   = new ERC20(inputs.tokenIn, ChainId.ETHEREUM)

  // Read on-chain balance
  const balResult = token.balanceOf(account)
  if (balResult.isError) {
    log.error('balanceOf failed: {}', [balResult.error])
    return
  }
  const balance = balResult.unwrap()

  // Check threshold
  const threshold = inputs.threshold
  if (balance.lt(threshold)) {
    log.info(`Balance ${balance.toString()} below threshold ${threshold.toString()}, skipping`)
    return
  }

  // Swap to ETH
  const fee    = TokenAmount.fromStringDecimal(DenominationToken.USD(), inputs.feeAmount)
  const minOut = TokenAmount.fromBigInt(Ethereum.ETH, balance)
    .toTokenAmount(Ethereum.ETH).unwrap()

  SwapBuilder.forChain(ChainId.ETHEREUM)
    .addTokenInFromStringDecimal(Ethereum.USDC, balance.toString())
    .addTokenOutFromTokenAmount(minOut, account)
    .addUser(inputs.smartAccount)
    .build()
    .send(fee)

  log.info('Swap intent emitted')
}
```


# Architecture

Mimic protocol consists of three core layers: the **Planning Layer**, the **Execution Layer**, and the **Security Layer**. Each layer involves key actors and components working together to ensure deterministic function execution, reliable intent handling, and robust security for any kind of user operations. Below is a detailed breakdown of each layer and its responsibilities:

## **1. Planning Layer**

<figure><img src="https://216358192-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F2K6E4Us9xYRIC0Tt0SIZ%2Fuploads%2F2j5d4GbV9lEvl0Rla0YB%2Fplanning.svg?alt=media&amp;token=681fbe55-080a-47da-b11d-0f0ca6d07cd4" alt="" width="563"><figcaption><p>The Planning Layer</p></figcaption></figure>

The Planning Layer is the starting point of the protocol. It allows users to define **functions**—deterministic units of logic that evaluate predefined conditions. A function specifies the inputs it needs, the execution trigger, and the logic that processes those inputs to decide whether an intent should be generated. For instance, a user may create a function to monitor the price of a token and generate an intent to sell if its value exceeds a specific threshold.

Relayers are responsible for executing these functions. Acting as decentralized operators, they fetch the required inputs from oracles, execute the user-defined logic deterministically, and submit the results back to the system. If the function conditions are met, relayers generate intents, which are then sent to the Execution Layer for further processing.

The oracles play a vital role in ensuring that functions are based on reliable data. They provide cryptographically signed inputs, such as token prices, account balances, or other blockchain-related data. These inputs are validated to ensure they fall within acceptable ranges or consensus mechanisms, such as medians or averages. By integrating signed oracle data, the Planning Layer ensures that functions are deterministic and verifiable.

In essence, the Planning Layer connects the efforts of users, relayers, and oracles to generate intents—user-defined requests to execute specific operations in the protocol. These intents form the output of the Planning Layer and serve as the primary input for the Execution Layer.

## **2. Execution Layer**

<figure><img src="https://216358192-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F2K6E4Us9xYRIC0Tt0SIZ%2Fuploads%2FUSXlwdw5P7sABdioKqwn%2Fexecution.svg?alt=media&amp;token=1b2ed995-cfe8-4351-a64b-bb7fc8b0db7f" alt="" width="563"><figcaption><p>The Execution Layer</p></figcaption></figure>

The Execution Layer acts as the central coordinator for processing intents. Once an intent is generated in the Planning Layer, it is handed off to **Axia**, the protocol’s central engine. Axia is responsible for validating the intent to ensure it complies with user-defined constraints and broadcasting it to a network of solvers.

Solvers, competitive entities within the system, respond to intents with execution proposals. Each proposal details how the solver intends to fulfill the intent, including fees, execution parameters, and estimated outcomes. Axia evaluates these proposals based on predefined criteria—such as execution fees, solver reputation, and timeliness—and selects the most optimal proposal through an auction-like process. The winning solver then executes the intent on-chain and submits proof of execution back to Axia.

This layer ensures that user-defined operations are executed efficiently while maintaining flexibility and scalability. By enabling competition among solvers, the Execution Layer maximizes efficiency and minimizes costs for users.

## **3. Security Layer**

<figure><img src="https://216358192-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F2K6E4Us9xYRIC0Tt0SIZ%2Fuploads%2FRIPpkVZ14n1CbI6Zg7bf%2Fsecurity.svg?alt=media&amp;token=30d3d9ff-f47a-48b7-885e-2b6c49280b49" alt="" width="563"><figcaption><p>The Security Layer</p></figcaption></figure>

The Security Layer is the backbone of the protocol, ensuring that all operations are executed securely and reliably. At the heart of this layer is the **Settler**, a smart contract that validates the execution proofs submitted by solvers. The Settler ensures that the solver’s execution aligns with the original intent and user-defined constraints.

In addition to validation, the Settler facilitates the flow of tokens into and out of the system. It manages user deposits, withdrawals, and other token movements, ensuring that funds are only released when the conditions of the intent are fully satisfied.

Complementing the Settler is the **Safeguards Engine**, a protective mechanism that enforces additional conditions and prevents malicious or erroneous transactions. For example, it can ensure that a transaction does not exceed predefined slippage limits or violate other user-defined parameters.

Through this layer, the protocol provides strong guarantees of security and correctness, safeguarding user funds and maintaining trust in the system.


# CLI

The Mimic Protocol CLI is a command-line tool for building, managing, and deploying automated blockchain functions. Mimic Protocol is a blockchain automation protocol that allows developers to create programmable functions that execute automatically based on predefined conditions.

### 1. Initialize

Initializes a new Mimic-compatible project structure in the current directory. This command will create a minimal folder layout, a manifest file, and example AssemblyScript function.

#### 1.1. Usage

```bash
mimic init [directory] [options]
```

#### 1.2. Options

| Option        | Description                                                        | Default |
| ------------- | ------------------------------------------------------------------ | ------- |
| `directory`   | Directory to initialize project                                    | `./`    |
| `--force, -f` | Overwrite existing files if they already exist (asks confirmation) | `false` |

#### 1.3. Examples

```bash
# Initialize a fresh project using default settings
yarn mimic init

# Initialize in a specific directory
yarn mimic init ./my-function

# Force initialization, overwriting existing files (will ask for confirmation)
yarn mimic init ./my-function --force
```

#### 1.4. Output

```
my-function/
├── manifest.yaml      # Function configuration
├── package.json       # Node.js dependencies
├── tsconfig.json      # TypeScript configuration
└── src/
    └── function.ts        # Main function implementation
```

When `--force` is used in a non-empty directory, the CLI asks for confirmation before deleting contents.

After scaffolding, the CLI runs `yarn install` and then `yarn codegen` inside the initialized directory to set up dependencies and generate types.

The manifest describes metadata, inputs, and ABIs for your AssemblyScript function, so the CLI can validate, generate code, compile, and ultimately deploy your function. For example:

```yaml
version: 1.0.0
name: Balance Monitoring Function
description: Monitors an account's token balance and creates a swap intent if conditions are met.
inputs:
  - chainId: uint32
  - account: address
  - tokenIn: address
  - tokenOut: address
  - slippage: uint32
  - threshold: uint32
abis:
  - ERC20: "./abis/IERC20.json"
```

***

### 2. Codegen

Scans your `manifest.yaml` and generates typed interfaces for declared inputs and ABIs. This step is typically used to create or update TypeScript/AssemblyScript types for your project so you can safely reference them in your code.

#### 2.1. Usage

```bash
mimic codegen [options]
```

#### 2.2. Options

| Option                  | Description                                                                     | Default         |
| ----------------------- | ------------------------------------------------------------------------------- | --------------- |
| `--manifest, -m <path>` | Specify a custom manifest file path                                             | `manifest.yaml` |
| `--output, -o <dir>`    | Output directory for generated types                                            | `./src/types`   |
| `--clean, -c`           | Remove existing generated types before generating new files (asks confirmation) | `false`         |

#### 2.3. Examples

```bash
# Generate types in the default "src/types" directory
yarn mimic codegen

# Generate types from a custom manifest, output to a "generated" folder
yarn mimic codegen --manifest ./custom-manifest.yaml --output ./src/generated

# Clean previous outputs (will ask confirmation) and regenerate
yarn mimic codegen --clean
```

#### 2.4. Output

* `./src/types/index.ts` - Input parameter types
* `./src/types/[ContractName].ts` - Contract interface types (one per ABI)

{% hint style="info" %}
For details about how ABI wrappers are generated and how to use them (read/write functions, tuples, arrays, and events), see the [ABI wrappers guide](broken://pages/dk2qcGLGN3Lk3CdCqpVL).
{% endhint %}

***

### 3. Compile

Compiles your AssemblyScript function into a Wasm binary, along with validating your manifest and producing any required runtime artifacts (like `manifest.json`). This step ensures you have a complete, ready-to-deploy package of your function logic and metadata.

#### 3.1. Usage

```bash
mimic compile [options]
```

#### 3.2. Options

| Option                     | Description                             | Default           |
| -------------------------- | --------------------------------------- | ----------------- |
| `--function, -f <path>`    | Path to the AssemblyScript entry file   | `src/function.ts` |
| `--manifest, -m <path>`    | Path to the manifest file to validate   | `manifest.yaml`   |
| `--output, -o <directory>` | Output directory for compiled artifacts | `build`           |

#### 3.3. Examples

```bash
# Compile using the default function and manifest
yarn mimic compile

# Compile a specific file, output to a custom directory
yarn mimic compile --function ./functions/myFunction.ts --output ./out
```

#### 3.4. Outputs

* `build/function.wasm` - Compiled WebAssembly binary
* `build/manifest.json` - Processed manifest configuration

The CLI validates the manifest before compiling. If the compilation fails, it reports an error and suggestions.

***

### 4. Login

Authenticates with Mimic by storing your API key locally. This allows you to deploy functions without having to provide your API key every time. Credentials are stored securely in `~/.mimic/credentials`.

{% hint style="info" %}
You can retrieve your API key from the [Mimic explorer](https://protocol.mimic.fi/) under your account settings.
{% endhint %}

#### 4.1. Usage

```bash
mimic login [options]
```

#### 4.2. Options

| Option                 | Description                             | Default   |
| ---------------------- | --------------------------------------- | --------- |
| `--profile, -p <name>` | Profile name to use for this credential | `default` |
| `--api-key, -k <key>`  | API key (non-interactive mode)          | -         |
| `--force-login, -f`    | Force login even if profile exists      | `false`   |

#### 4.3. Examples

```bash
# Interactive login (prompts for API key)
mimic login

# Login with a specific profile
mimic login --profile staging

# Non-interactive login with API key provided directly
mimic login --profile production --api-key YOUR_API_KEY

# Force overwrite existing profile without confirmation
mimic login --profile production --force-login
```

#### 4.4. Behavior

In interactive mode, the CLI prompts you to:

1. Enter your API key (masked input)
2. Enter a profile name (defaults to "default")

If a profile already exists, you'll be asked to confirm before overwriting it (unless `--force-login` is used).

{% hint style="info" %}
Profile names cannot contain `[`, `]`, or `=` characters.
{% endhint %}

***

### 5. Logout

Removes stored credentials for a specific profile. This is useful when you want to revoke local access or clean up old credentials.

#### 5.1. Usage

```bash
mimic logout [options]
```

#### 5.2. Options

| Option                 | Description              | Default   |
| ---------------------- | ------------------------ | --------- |
| `--profile, -p <name>` | Profile name to remove   | `default` |
| `--force, -f`          | Skip confirmation prompt | `false`   |

#### 5.3. Examples

```bash
# Remove credentials for the default profile (asks for confirmation)
mimic logout

# Remove credentials for a specific profile
mimic logout --profile staging

# Force removal without confirmation
mimic logout --force
```

***

### 6. Profiles

Lists all configured authentication profiles stored in `~/.mimic/credentials`. This is useful for checking which profiles are available and which one is set as default.

#### 6.1. Usage

```bash
mimic profiles
```

#### 6.2. Options

No options available for this command.

#### 6.3. Examples

```bash
# List all configured profiles
mimic profiles
```

#### 6.4. Output

```
Configured profiles (stored in ~/.mimic/credentials):

* default (default)
* staging
* production

Use mimic deploy --profile <name> to deploy with a specific profile.
```

***

### 7. Deploy

Uploads your compiled function artifacts to IPFS and registers it into the Mimic Registry so others can discover it. This step pins the result under a CID so relayers can discover and execute it.

{% hint style="info" %}
You must retrieve your deployment key from the [Mimic explorer](https://protocol.mimic.fi/) under your account settings. If you don’t have one, create or copy it from there before running `deploy`.
{% endhint %}

#### 7.1. Usage

```bash
mimic deploy [options]
```

#### 7.2. Options

| Option                     | Description                                     | Default                         |
| -------------------------- | ----------------------------------------------- | ------------------------------- |
| `--api-key, -k <api-key>`  | Your account api key                            | -                               |
| `--input, -i <directory>`  | Directory containing the compiled artifacts     | `build`                         |
| `--output, -o <directory>` | Output directory for deployment CID             | `build`                         |
| `--url, -u <url>`          | Mimic Registry base URL                         | `https://api-protocol.mimic.fi` |
| `--skip-compile`           | Skip codegen and compile steps before uploading | `false`                         |
| `--profile, -p <name>`     | Profile name to use for the deployment.         | -                               |

{% hint style="info" %}
If neither an API key nor a profile is specified, the default profile will be used
{% endhint %}

#### 7.3. Examples

<pre class="language-bash"><code class="lang-bash"># Deploy from the default build directory, using your pre-configured key
<strong>yarn mimic deploy --api-key my-key
</strong>
# Deploy from the default build directory, using your pre-configured key
mimic deploy --api-key my-key

# Deploy from the default build directory, using the default profile
mimic deploy

# Deploy from the default build directory, using a specify profile
mimic deploy -p profile

# Deploy from a custom folder
mimic deploy --input ./dist

# Specify a different output path
mimic deploy --input ./dist --output ./dist

# Use a custom registry URL and skip local build steps
mimic deploy --url https://custom.registry --skip-compile
</code></pre>

#### 7.4. Validation and Outputs

Before uploading, the CLI validates that the input directory exists and includes:

* `manifest.json`
* `function.wasm`

On success:

* `build/CID.json` - Contains the IPFS Content Identifier for your deployed function

***

### 8. Configuration File (mimic.yaml)

For advanced use cases where you have multiple functions in a single project, you can use a `mimic.yaml` configuration file to define all functions and their build settings. This allows you to run CLI commands on multiple functions at once with optional filtering.

#### 8.1. File Format

Create a `mimic.yaml` file in your project root with the following structure:

```yaml
functions:
  - name: function-one
    manifest: ./function-one/manifest.yaml
    function: ./function-one/src/function.ts
    build-directory: ./function-one/build
    types-directory: ./function-one/src/types

  - name: function-two
    manifest: ./function-two/manifest.yaml
    function: ./function-two/src/function.ts
    build-directory: ./function-two/build
    types-directory: ./function-two/src/types
```

Each function entry requires:

| Field             | Description                             | Example                          |
| ----------------- | --------------------------------------- | -------------------------------- |
| `name`            | Unique identifier for the function      | `function-one`                   |
| `manifest`        | Path to the manifest.yaml file          | `./function-one/manifest.yaml`   |
| `function`        | Path to the AssemblyScript entry file   | `./function-one/src/function.ts` |
| `build-directory` | Output directory for compiled artifacts | `./function-one/build`           |
| `types-directory` | Output directory for generated types    | `./function-one/src/types`       |

#### 8.2. Usage with Commands

All CLI commands that support the `mimic.yaml` configuration (`codegen`, `compile`, `test`, `build` and `deploy`) will automatically use this file if it exists. When a `mimic.yaml` is present, the CLI will execute the command for each function defined in it.

{% hint style="info" %}
The `mimic test` command only uses the `--exclude` and `--include` filters for building, not for testing.
{% endhint %}

#### 8.3. Filtering Functions

You can selectively run commands on specific functions using include and exclude flags:

```bash
# Run codegen, compile, test, or deploy only for specific functions
yarn mimic compile --include function-one function-two

# Run commands for all functions except specific ones
yarn mimic codegen --exclude function-three

# These flags work with any command that supports mimic.yaml
yarn mimic deploy --include function-one --profile production
```

#### 8.4. Overriding Configuration

If you need to override the configuration file location or disable the configuration file entirely:

```bash
# Use a custom config file location
yarn mimic compile --config-file ./config/functions.yaml

# Ignore mimic.yaml and use defaults with explicit flags
yarn mimic compile --no-config --function ./src/function.ts
```

#### 8.5. Examples

**Example 1: Building Multiple Functions**

```bash
# Build all functions defined in mimic.yaml
yarn mimic build

# Build only specific functions
yarn mimic build --include function-one
```

**Example 2: Deploying Multiple Functions**

```bash
# Deploy all functions
yarn mimic deploy

# Deploy specific functions to production
yarn mimic deploy --include function-one function-two --profile production

# Deploy all except function-three to staging
yarn mimic deploy --exclude function-three
```

{% hint style="info" %}
The `mimic.yaml` file is optional and intended for advanced multi-function projects. Single-function projects can continue using individual command flags without creating a configuration file.
{% endhint %}

***

### 9. Test

Runs function tests using mocha. By default, it performs `codegen` and `compile` first, then executes `tests/**/*.spec.ts`.

#### 9.1. Usage

```bash
mimic test [options]
```

#### 9.2. Options

| Option                   | Description                                 | Default |
| ------------------------ | ------------------------------------------- | ------- |
| `--directory, -d <path>` | Function directory to run tests from        | `./`    |
| `--skip-compile`         | Skip codegen and compile steps before tests | `false` |

#### 9.3. Behavior

* If not skipped, runs `yarn mimic codegen` and `yarn mimic compile` in the target directory.
* Executes tests using mocha via tsx: `yarn tsx ./node_modules/mocha/bin/mocha.js tests/**/*.spec.ts`.


# Library

The Mimic Protocol Library (`@mimicprotocol/lib-ts`) is a lightweight standard library for building blockchain automation functions. It provides typed primitives and safe bindings to create deterministic functions to interact with multiple blockchain networks.

**Why AssemblyScript?**

Functions are written in AssemblyScript (which compiles to WebAssembly) to ensure:

* **Deterministic execution**: Same inputs always produce same outputs
* **Portability**: Runs consistently across different environments
* **Security**: Sandboxed execution with no system access
* **Performance**: Near-native execution speed

{% hint style="info" %}
We're planning to expand language support beyond AssemblyScript to include other WebAssembly-compatible languages like Rust. This will bring more flexibility in how functions can be written while maintaining all the security and deterministic execution benefits of WebAssembly.
{% endhint %}

***

### 1. Core Concepts

#### 1.1. Intents and Operations

Intents are declarations of what you want to happen. Instead of executing transactions directly, you create intents that describe your desired outcome. The protocol then finds the best way to fulfill them.

An intent is composed of one or more **operations** — the atomic actions to be executed. Three operation types are available:

* **Call**: Execute smart contract functions
* **Swap**: Exchange tokens across DEXs
* **Transfer**: Move tokens between addresses

Grouping multiple operations into a single intent lets the protocol execute them together (all operations in an intent must share the same source chain). A cross-chain swap must always be the sole operation in its intent.

#### 1.2. Environment

The Environment provides access to external data and execution capabilities:

* Price feeds and oracles
* Token information
* Contract interactions
* Intent execution

***

### 2. Getting Started

#### 2.1. Project setup

Create a basic function project:

```bash
# Initialize a new Mimic project
npx @mimicprotocol/cli init my-automation-function && cd my-automation-function

# Generate types from ABIs (if using custom contracts or external inputs)
yarn mimic codegen

# Compile your function
yarn mimic compile
```

#### 2.2. Basic function structure

Every function follows this structure:

```tsx
import { /* required imports */ } from '@mimicprotocol/lib-ts'

export default function main(): void {
  // 1. Setup: Define tokens, addresses, parameters
  // 2. Logic: Query data, make decisions
  // 3. Action: Create and send intents
}
```

***

### 3. Core Types & Queries

#### 3.1. Core types

**3.1.1. Primitives**

```tsx
// Addresses
const userAddress = Address.fromString('0x...')
const zeroAddress = Address.zero()

// Big integers for precise arithmetic
const value = BigInt.fromString('1000000000000000000') // 1 ETH in wei
// or...
const value2 = BigInt.fromI32(1).pow(18) // Also 1 ETH in wei
const calculated = value.times(BigInt.fromI32(2))

// Bytes for contract data
const data = Bytes.fromHexString('0x095ea7b3...')
const emptyData = Bytes.empty()
```

**3.1.2. Tokens and Amounts**

```tsx
// Create a token reference
const USDC = Ethereum.USDC
const ETH = Ethereum.ETH
const customToken = ERC20Token.fromString('0xCustomTokenAddress', Ethereum.CHAIN_ID, 18, 'CSTM')

// Work with token amounts
const amount = TokenAmount.fromStringDecimal(USDC, '1000.50') // 1000.5 USDC
const nativeAmount = TokenAmount.fromI32(ETH, 5) // 5 ETH

// Convert TokenAmount to USD
const usdValue = amount.toUsd().unwrap()

// Convert TokenAmount to another token
const wbtcAmount = amount.toTokenAmount(Ethereum.WBTC).unwrap()

// Convert USD to TokenAmount
const usdAmount = USD.fromStringDecimal('1000')
const tokenAmount = usdAmount.toTokenAmount(Ethereum.USDC).unwrap()
```

#### 3.2. Queries

**3.2.1. Result**

All queries (except `getContext`) return a `Result<V, E>` type that encapsulates either a successful value or an error. This pattern ensures safe error handling without exceptions.

The `Result` type provides the following methods:

```tsx
import { Result } from '@mimicprotocol/lib-ts'

const result: Result<V, string> = /* environment.query() */

// Check state
result.isOk      // true if operation succeeded
result.isError   // true if operation failed

// Get value
result.unwrap()           // Returns value or throws if error
result.unwrapOr(default)  // Returns value or default if error
result.unwrapOrElse(fn)   // Returns value or calls fn() if error

// Get error
result.error              // Returns error message (only if isError is true)
```

Common patterns for handling results:

```tsx
import { environment, Ethereum, log, USD } from '@mimicprotocol/lib-ts'

const priceResult = environment.tokenPriceQuery(Ethereum.USDC)

// Pattern 1: Explicit error checking
if (priceResult.isError) {
  log.error('Failed to get price: ' + priceResult.error)
  return
}
const price = priceResult.unwrap()

// Pattern 2: Using default values
const price = priceResult.unwrapOr(USD.zero())

// Pattern 3: Using default behavior
const price = priceResult.unwrapOrElse(() => {
  log.error('Failed to get price')
  // Custom logic to handle the error
  return USD.zero()
})

// Pattern 4: Error propagation
const price = priceResult.unwrap()

```

**3.2.2. Price queries**

Price queries allow you to retrieve token prices in USD. Results are represented with 18 decimals:

```tsx
import { environment, Ethereum, USD } from '@mimicprotocol/lib-ts'

// Get current token price in USD
const price = environment.tokenPriceQuery(Ethereum.USDC).unwrap()

// Get historical price
const historicalPrice = environment.tokenPriceQuery(Ethereum.USDC, new Date(1640995200000)).unwrap()

// Get raw price samples from multiple sources
const rawPrices = environment.rawTokenPriceQuery(Ethereum.USDC).unwrap()

// Convert between USD and tokens
const usdAmount = USD.fromStringDecimal('1000')
const tokenEquivalent = usdAmount.toTokenAmount(Ethereum.WBTC).unwrap()

```

**3.2.3. Relevant tokens**

The relevant tokens query allows you to find all the token balances for a specific account. Handful filters are provided to restrict chains, tokens allow or deny lists, or minimum USD value:

```tsx
import { environment, Address, ChainId, ListType, USD } from '@mimicprotocol/lib-ts'

const userTokens = environment.relevantTokensQuery(
  userAddress,
  [ChainId.ETHEREUM, ChainId.POLYGON], // chains to check
  USD.fromStringDecimal('100'),        // minimum USD value
  [unwantedToken],                     // excluded tokens
  ListType.DenyList                    // list type
).unwrap()
```

**3.2.4. Contract calls**

Contract calls allow you to read contract information from the chain:

```tsx
import { environment, Address, ChainId } from '@mimicprotocol/lib-ts'

const response = environment.evmCallQuery(
  Address.fromString('0xContractAddress'),
  ChainId.ETHEREUM,
  '0x70a08231',  // encoded function call data
  null           // optional timestamp
).unwrap()  // raw hex string response
```

Note: there is an easier way to read contract information. See 4.5. Read calls.

**3.2.5. Subgraph queries**

Subgraph queries allow you to read information from subgraphs:

```tsx
import { environment, ChainId } from '@mimicprotocol/lib-ts'

const response = environment.subgraphQuery(
  ChainId.ETHEREUM,
  'QmSubgraphId',
  '{ tokens { id symbol } }',
  null  // optional timestamp
).unwrap()
```

**3.2.6. Context**

The context query tells the current execution context for the function. This includes user, settler, timestamp, consensusThreshold and triggerPayload:

```tsx
import { environment, ChainId } from '@mimicprotocol/lib-ts'

const ctx = environment.getContext()
const user = ctx.user
const settlerForEth = ctx.findSettler(ChainId.ETHEREUM)
const timestampMs = ctx.timestamp
```

Note: `getContext()` does not return a `Result` type as it cannot fail.

#### 3.3. Operation builders

Each operation type has its own builder. Builders produce operations, which are then wrapped into an intent when sent. Every builder exposes a `.send()` shortcut that creates a single-operation intent automatically.

**3.3.1. Transfer**

Move tokens between addresses:

```tsx
import { Address, ChainId, Ethereum, TokenAmount, TransferBuilder } from '@mimicprotocol/lib-ts'

const fee = TokenAmount.fromStringDecimal(Ethereum.USDC, '1')

const transfer = TransferBuilder.forChain(ChainId.ETHEREUM)
  .addTransferFromStringDecimal(Ethereum.USDC, '1000', Address.fromString('0xrecipientAddress'))
  .addTransferFromStringDecimal(Ethereum.WBTC, '0.5', Address.fromString('0xrecipientAddress'))
  .addTransferFromStringDecimal(Ethereum.USDT, '500', Address.fromString('0xotherRecipientAddress'))
  .build()

transfer.send(fee)
```

**3.3.2. Swap**

Exchange tokens across DEXs:

```tsx
import { Address, ChainId, Ethereum, Optimism, SwapBuilder, TokenAmount } from '@mimicprotocol/lib-ts'

const fee = TokenAmount.fromStringDecimal(Ethereum.USDC, '1')

const swap = SwapBuilder.forChains(ChainId.ETHEREUM, ChainId.ETHEREUM) // same chain swap
  .addTokenInFromStringDecimal(Ethereum.USDC, '1')
  .addTokenOutFromStringDecimal(Ethereum.USDT, '0.99', Address.fromString('0xrecipientAddress')) // 1% slippage
  .build()

const cross = SwapBuilder.forChains(ChainId.ETHEREUM, ChainId.OPTIMISM) // cross chain swap
  .addTokenInFromStringDecimal(Ethereum.USDC, '1000')
  .addTokenOutFromStringDecimal(Optimism.USDC, '990', Address.fromString('0xrecipientAddress'))
  .build()

// Two separate intents are created
swap.send(fee)
cross.send(fee)
```

**3.3.3. Call**

Execute smart contract functions:

```tsx
import { Address, BigInt, Bytes, ChainId, evm, EvmCallBuilder, EvmEncodeParam, Ethereum, TokenAmount } from '@mimicprotocol/lib-ts'
import { MyContractUtils } from './types/'

// MyContract implements myFunction(address,uint256)
const encodedData = MyContractUtils.encodeMyFunction(Address.zero(), BigInt.zero())

// Alternative:
// const encodedData = Bytes.fromHexString(
//   '0xselector' +
//   evm.encode([
//     EvmEncodeParam.fromValue('address', Address.zero()),
//     EvmEncodeParam.fromValue('uint256', BigInt.zero()),
//   ])
// )

const fee = TokenAmount.fromStringDecimal(Ethereum.USDC, '1')

const call = EvmCallBuilder.forChain(ChainId.ETHEREUM)
  .addCall(Address.fromString('0xContractAddress'), encodedData)
  .build()

call.send(fee)
```

#### 3.4. IntentBuilder — composing multiple operations

`IntentBuilder` lets you group multiple operations into a single intent. All operations must share the same source chain. Intent-level settings like `feePayer`, `settler`, `deadline`, and `nonce` are configured here.

```tsx
import { Address, ChainId, Ethereum, EvmCallBuilder, IntentBuilder, SwapBuilder, TokenAmount, TransferBuilder } from '@mimicprotocol/lib-ts'

const fee = TokenAmount.fromStringDecimal(Ethereum.USDC, '1')
const recipient = Address.fromString('0xrecipientAddress')

const evmCall = EvmCallBuilder.forChain(ChainId.ETHEREUM)
  .addCall(Address.fromString('0xContractAddress'), encodedData)

const swap = SwapBuilder.forChains(ChainId.ETHEREUM, ChainId.ETHEREUM)
  .addTokenInFromStringDecimal(Ethereum.USDC, '500')
  .addTokenOutFromStringDecimal(Ethereum.USDT, '495', recipient)

const transfer = TransferBuilder.forChain(ChainId.ETHEREUM)
  .addTransferFromStringDecimal(Ethereum.USDC, '100', recipient)

// All three operations execute within a single intent
new IntentBuilder()
  .addOperationsBuilders([evmCall, swap, transfer])
  .addMaxFee(fee)
  .send()
```

You can also set a custom fee payer (defaults to the context user), or override the settler and deadline:

```tsx
new IntentBuilder()
  .addOperationBuilder(evmCall)
  .addMaxFee(fee)
  .addFeePayerAsString('0xfeePayerAddress')
  .addSettlerAsString('0xsettlerAddress')
  .addDeadline(BigInt.fromString('1800000000'))
  .send()
```

The `IntentBuilder` also provides convenience methods if you prefer to avoid instantiating builders directly:

```tsx
new IntentBuilder()
  .addEvmCallOperation(ChainId.ETHEREUM, Address.fromString('0xcontract'), encodedData)
  .addTransferOperation(Ethereum.USDC, BigInt.fromString('1000000'), recipient)
  .addMaxFee(fee)
  .send()
```

#### 3.5. EVM Utilities

```tsx
import { Address, BigInt, evm, EvmDecodeParam, EvmEncodeParam } from '@mimicprotocol/lib-ts'

// Encode function parameters
const encoded = evm.encode([
  EvmEncodeParam.fromValue('address', Address.zero()),
  EvmEncodeParam.fromValue('uint256', BigInt.zero()),
])

// Decode contract responses
const decoded = evm.decode(new EvmDecodeParam('string', response))

// Generate hashes
const hash = evm.keccak('some data')
```

***

### 4. Using generated ABI wrappers

If you are using `mimic codegen` to generate contract wrappers, refer to the ABI wrappers guide for how read/write methods, tuple classes, arrays, and events are produced and used:

`mimic codegen` generates strongly-typed AssemblyScript wrappers for your contract ABIs. For every ABI declared in your `manifest.yaml`, it emits a file `src/types/<ContractName>.ts` that includes:

* A `ContractName` class: ergonomic read/write methods that encode calls and decode responses
* A `ContractNameUtils` helper class: static `encodeX`/`decodeX` helpers per function
* Tuple classes for `tuple`/`struct` params and returns
* Event classes `<EventName>Event` with a static `decode(topics, data)`

The generated code targets `@mimicprotocol/lib-ts` primitives and utilities: `Address`, `BigInt`, `Bytes`, `environment`, `evm`, `EvmCallBuilder`, `EvmEncodeParam`, `EvmDecodeParam`.

#### 4.1. When it runs

* `mimic codegen` reads `manifest.yaml`
  * `inputs` → `src/types/index.ts`
  * `abis` → `src/types/<ContractName>.ts`

Example manifest excerpt:

```yaml
abis:
  ERC20: './abis/ERC20.json'
```

#### 4.2. Generated class layout

Every contract file exports `export class <ContractName>` with:

* Constructor: `(address: Address, chainId: ChainId, timestamp: Date | null = null)`
* Getters: `address`, `chainId`, `timestamp`
* One method per ABI function. Read methods call `environment.evmCallQuery`; write methods return an `EvmCallBuilder` and never call the environment directly.

Additionally, `export class <ContractName>Utils` exposes `encode<Fn>` and `decode<Fn>` helpers used by the main class.

```ts
export class ERC20 {
  private _address: Address
  private _chainId: ChainId
  private _timestamp: Date | null

  constructor(address: Address, chainId: ChainId, timestamp: Date | null = null) { /* ... */ }
  get address(): Address { /* ... */ }
  get chainId(): ChainId { /* ... */ }
  get timestamp(): Date | null { /* ... */ }

  // ...
}

export class ERC20Utils {
  // static encode<Name>(...): Bytes
  // static decode<Name>(response: string): <MappedType>
}
```

#### 4.3. Type mapping rules

* address → `Address`
* bool → `bool`
* string → `string`
* bytes / bytesN → `Bytes`
* intN/uintN → `BigInt` for N ≥ 24; `i8/u8/i16/u16/i32/u32/i64/u64` for smaller widths
* Arrays preserve depth: `address[][]` → `Address[][]`
* Tuples generate classes; arrays of tuples become arrays of those classes

Unknown or unextracted tuple types are conservatively mapped to `unknown` (and a warning may be emitted during generation).

#### 4.4. Method naming and overloading

* Functions keep their ABI `name`; reserved words are suffixed with `_` (e.g., `constructor_`).
* Overloads are suffixed incrementally: `_1`, `_2`, ...
* Capitalized names are used in helpers: `encodeGetBalance`, `decodeGetBalance`.

**4.5. Read calls**

Read methods perform: encode → `environment.evmCallQuery` → decode. All read methods return `Result<T, string>` where `T` is the return type.

```ts
// ABI: function balanceOf(address owner) view returns (uint256)
const erc20 = new ERC20(token, ChainId.ETHEREUM)
const balanceResult = erc20.balanceOf(Address.fromString('0x...')) // Result<BigInt, string>

if (balanceResult.isError) {
  // Handle error
  return
}
const balance: BigInt = balanceResult.unwrap()

// Under the hood (simplified):
// const encoded = ERC20Utils.encodeBalanceOf(owner)
// const resp = environment.evmCallQuery(this._address, this._chainId, encoded.toHexString(), this._timestamp)
// if (resp.isError) return Result.err<BigInt, string>(resp.error)
// return Result.ok<BigInt, string>(ERC20Utils.decodeBalanceOf(resp.unwrap()))
```

Void-returning reads return `Result<Void, string>` and just perform the call without decoding.

#### 4.6. Write calls

Write methods return an `EvmCallBuilder` so you can compose multiple calls and send them via intents later.

```ts
// ABI: function approve(address spender, uint256 amount) nonpayable
const approve = erc20.approve(spender, amount) // EvmCallBuilder
// approve.build().send(maxFee) // typical flow
```

Encoding converts primitives as needed:

```ts
// bool → Bytes.fromBool
// u8 → BigInt.fromU8, etc.
// tuples → EvmEncodeParam.fromValues('()', tuple.toEvmEncodeParams())
// arrays → nested EvmEncodeParam.fromValues with map
```

#### 4.7. Tuples and structs

The generator extracts tuple/struct definitions from inputs, outputs, and multi-return functions.

* If `internalType` includes a struct name (e.g., `struct UserContract.UserInfo`), that name is used
* Otherwise it falls back to `Tuple<N>`
* For functions with multiple outputs, a synthetic `<FunctionName>Outputs` class is created

Tuple classes provide:

* `static parse(data: string): <Class>` to parse decoded strings
* `toEvmEncodeParams(): EvmEncodeParam[]` for encoding

```ts
// Example return tuple
const info: UserInfo = erc20.getUserInfo()

// Example tuple param
const created = contract.createUser(new UserInfo(id, name, active)) // EvmCallBuilder
```

#### 4.8. Arrays and nested arrays

Arrays are supported at any depth for both params and returns. Encoding/decoding uses JSON strings under the hood for nested structures and handles empty arrays.

```ts
// ABI: function getHolders() view returns (address[])
const holders: Address[] = contract.getHolders()

// ABI: function batchTransfer(address[][] recipients, uint256[][] amounts)
const cb = contract.batchTransfer(addressMatrix, valueMatrix)
```

#### 4.9. Events

For each event, `<EventName>Event` is generated with a static `decode(topics: string[], data: string)`.

```ts
// ABI: event Transfer(address indexed from, address indexed to, uint256 amount, bool confirmed)
const evt = TransferEvent.decode(topics, data)
// evt.from: Address, evt.to: Address, evt.amount: BigInt, evt.confirmed: bool
```

Indexed parameters are decoded from `topics[1..]`; non-indexed parameters are decoded from `data`. For multiple non-indexed params, the data is treated as an encoded tuple.

#### 4.10. Imports and dependencies

Imports are automatically deduplicated and sorted based on what your ABI requires. Typical imports include:

```ts
import { Address, BigInt, Bytes, ChainId, EvmCallBuilder, EvmDecodeParam, EvmEncodeParam, JSON, environment, evm } from '@mimicprotocol/lib-ts'
```

You do not need to manage these imports manually; they are generated with the file.

#### 4.11. Example

Given this ABI excerpt:

```json
[
  { "type": "function", "name": "balanceOf", "stateMutability": "view", "inputs": [{ "name": "owner", "type": "address" }], "outputs": [{ "name": "balance", "type": "uint256" }] },
  { "type": "function", "name": "transfer", "stateMutability": "nonpayable", "inputs": [{ "name": "to", "type": "address" }, { "name": "amount", "type": "uint256" }], "outputs": [] },
  { "type": "event", "name": "Transfer", "inputs": [ {"name": "from", "type": "address", "indexed": true}, {"name": "to", "type": "address", "indexed": true}, {"name": "amount", "type": "uint256"} ] }
]
```

You can write:

```ts
const token = new ERC20(Address.fromString('0x...'), ChainId.ETHEREUM)

const balResult = token.balanceOf(Address.fromString('0xuser'))
if (balResult.isError) {
  // Handle error
  return
}
const bal = balResult.unwrap()

// Write method returns EvmCallBuilder
const call = token.transfer(Address.fromString('0xrecipient'), BigInt.fromString('1000000000000000000')) // EvmCallBuilder
// call.build().send(maxFee)

// Event decoding
const decoded = TransferEvent.decode(topics, data)
```

#### 4.12. Notes and limitations

* Only `function` and `event` ABI items are processed; others are ignored
* Overloads are supported via numeric suffixes in method names
* If a tuple class name cannot be inferred, a warning is emitted and `unknown` may appear in mapped types
* Generated files are meant to be committed; do not edit manually (they include a notice)

{% content-ref url="/pages/dk2qcGLGN3Lk3CdCqpVL" %}
[Broken mention](broken://pages/dk2qcGLGN3Lk3CdCqpVL)
{% endcontent-ref %}


# SDK

The Mimic Protocol SDK provides a TypeScript client to interact with the Mimic Protocol blockchain automation platform. It offers a developer-friendly interface for managing functions, triggers, executions, and intents.

## Getting Started

You can install Mimic Protocol's SDK by running the following command line:

```bash
yarn add @mimicprotocol/sdk
```

### **Basic Client Initialization**

```typescript
import { Client } from '@mimicprotocol/sdk'

// Basic client with default configuration
const client = new Client()

// Client with custom base URL
const client = new Client({
  baseUrl: 'https://api-protocol.mimic.fi'
})
```

### **Client with Authentication**

```typescript
import { Client, ApiKeyAuth, BearerAuth } from '@mimicprotocol/sdk'

// Using API key authentication
const client = new Client({
  auth: new ApiKeyAuth('your-api-key')
})

// Using Bearer token authentication
const client = new Client({
  auth: new BearerAuth('your-bearer-token')
})
```

### **Client with Signer**

```typescript
import { Client, EthersSigner } from '@mimicprotocol/sdk'
import { ethers } from 'ethers'

// Using private key
const signer = EthersSigner.fromPrivateKey('0x...')
const client = new Client({
  signer
})

// Using JSON-RPC signer (e.g., MetaMask)
const provider = new ethers.BrowserProvider(window.ethereum)
const jsonRpcSigner = await provider.getSigner()
const signer = EthersSigner.fromJsonRpcSigner(jsonRpcSigner)
const client = new Client({
  signer
})

// Using browser wallet directly
import { WindowEthereumSigner } from '@mimicprotocol/sdk'

const signer = new WindowEthereumSigner('0x...') // wallet address
const client = new Client({
  signer
})
```

## Domain Clients

The SDK is organized into domain-specific clients, each handling a specific aspect of the protocol.

### **Balances**

Query balance entries and compute totals.

```typescript
import type { Balances, BalanceTotal } from '@mimicprotocol/sdk'

// List balances (optionally filter by address)
const balances: Balances = await client.balances.get({
  address: '0x...',
  limit: 20,
  offset: 0,
})

// Get total balance for a specific address
const total: BalanceTotal = await client.balances.getTotal('0x...')
console.log(total.address, total.balance)

// Pagination
const nextPage: Balances = await client.balances.get({ offset: 20, limit: 20 })
```

### **Functions**

Manage WASM functions and their manifests.

```typescript
import type { Function, Functions, Manifest } from '@mimicprotocol/sdk'

// List all functions
const functions: Functions = await client.functions.get()

// List functions with filters
const functionsFiltered: Functions = await client.functions.get({
  creator: '0x...',
  limit: 10,
  offset: 0
})

// Get specific function by CID
const function: Function = await client.functions.getByCid('Qm...')

// Get function manifest
const manifest: Manifest = await client.functions.getManifest('Qm...')

// Download WASM binary
const wasmBlob: Blob = await client.functions.getWasm('Qm...')

// Create new function (requires API key authentication)
const newFunction: Function = await client.functions.create({
  manifestFile: new File([manifestJson], 'manifest.json', { type: 'application/json' }),
  wasmFile: new File([wasmBytes], 'function.wasm', { type: 'application/wasm' })
})
```

### **Triggers**

Manage function triggers and their lifecycle. Triggers define how and when functions should be executed.

```typescript
import { Trigger, TriggerType } from '@mimicprotocol/sdk'

// List all triggers
const triggers: Trigger[] = await client.triggers.get()

// List triggers with filters
const triggers = await client.triggers.get({
  sigs: ['0x...', '0x...'],           // specific signatures
  functionCid: 'Qm...',               // filter by function
  signer: '0x...',                    // filter by creator
  active: true,                       // filter by status
  createdAfter: Date.parse('2024-01-01'),
  createdBefore: Date.parse('2024-12-31'),
  offset: 0,
  limit: 20,
})

// Get specific trigger by signature
const trigger: Trigger = await client.triggers.getBySignature('0x...')

// Create and sign a new trigger (requires signer)
const newTrigger: Trigger = await client.triggers.signAndCreate({
  description: 'Daily DCA automation',
  functionCid: 'Qm...',
  version: '1.0.0',
  manifest: { /* function manifest with inputs definition */ },
  config: {
    type: TriggerType.Cron,           // or TriggerType.Event or TriggerType.Once
    schedule: '0 0 * * *',            // cron expression (daily at midnight)
    delta: '1h',                      // execution window
    endDate: 0                        // 0 = no end date
  },
  input: { 
    token: '0x...', 
    amount: '1000000000000000000'     // must match manifest inputs
  },
  executionFeeLimit: '1000000000000000000',  // max fee in wei
  minValidations: 1                   // minimum validations required
})

// Deactivate one or more triggers (requires signer)
await client.triggers.signAndDeactivate(['0x...'])
await client.triggers.signAndDeactivate(['0x...', '0x...'])

// Check if trigger is expired
const isExpired: boolean = client.triggers.isExpired(trigger)

// Get next execution timestamp for cron triggers
const nextExecution: number = client.triggers.getNextExecutionTimestamp('0 0 * * *', Date.now())
```

Trigger deactivation supports batching. A single signature can deactivate multiple triggers as long as they belong to the same signer.

### **Trigger Config Types**

#### **Cron Trigger Config**

```typescript
{
  type: TriggerType.Cron,
  schedule: '0 0 * * *',    // cron expression
  delta: '1h',              // execution window (e.g., '30m', '2h', '1d')
  endDate: 0                // timestamp or 0 for no end
}
```

#### **Event Trigger Config**

```typescript
{
  type: TriggerType.Event,
  chainId: 1,               // blockchain chain ID
  contract: '0x...',        // contract address to monitor
  topics: [['0x...']],      // event topics by indexed position (1-4 topic arrays)
  delta: '1h',              // execution window
  endDate: 0                // timestamp or 0 for no end
}
```

For example, if you want to track:

```typescript
topic0: '0x1'
topic1: any
topic2: '0x2' OR '0x3'
```

you should set `topics` to:

```typescript
[
  ['0x1'],
  [],
  ['0x2', '0x3'],
]
```

#### **Once Trigger Config**

```typescript
{
  type: TriggerType.Once,
  startDate: 1769615762929, // timestamp
  delta: '10m',             // execution window
  endDate: 1769616362929    // start date + delta
}
```

You can also use `createExecuteOnceTriggerConfig()` to create an execute once trigger config.

### **Executions**

Query function execution history and results. The list and detail endpoints return execution metadata, fee breakdown, and validations. Inputs, outputs, and logs are fetched separately through dedicated methods.

```typescript
import type { ExecutionInput, ExecutionOutput, ExecutionResponse } from '@mimicprotocol/sdk'

// List executions (with optional filters)
const executions: ExecutionResponse[] = await client.executions.get({
  triggerSig: '0x...',                 // by trigger signature
  createdAfter: Date.parse('2024-01-01'),
  createdBefore: Date.parse('2024-12-31'),
  offset: 0,
  limit: 50,
})

// Inspect an execution
for (const ex of executions) {
  console.log(ex.hash, ex.timestamp, ex.status)
  console.log('Result:', ex.result)             // succeeded | failed
  console.log('Relayer:', ex.relayer)
  console.log('Fuel used:', ex.fuelUsed)

  // Optional fee breakdown
  if (ex.fee) {
    console.log('Fee total:', ex.fee.total)
  }

  // Inputs (oracle responses)
  const inputs: ExecutionInput[] = await client.executions.getInputs(ex.hash)
  for (const input of inputs) {
    console.log('Oracle input:', input)
  }

  // Outputs (intents emitted)
  const outputs: ExecutionOutput[] = await client.executions.getOutputs(ex.hash)
  for (const out of outputs) {
    console.log('Intent hash:', out.hash)
  }

  // Logs
  const logs: string[] = await client.executions.getLogs(ex.hash)
  for (const log of logs) {
    console.log('Log: ', log)
  }

  // Optional validations
  if (ex.validations) {
    for (const v of ex.validations) {
      console.log('Validation:', v.succeeded, v.signature)
    }
  }
}

// Get specific execution by hash
const execution: ExecutionResponse = await client.executions.getByHash('0x...')
```

### **Intents**

Query, encode, and decode intents and their operations. An intent contains one or more operations (`intent.operations`); each operation has an `opType` that identifies what it does.

```typescript
import { isEvmCall, isSwap, isTransfer, OpType } from '@mimicprotocol/sdk'
import type {
  AxiaIntent,
  EvmCallOperation,
  EvmDynamicCallOperation,
  Operation,
  SwapOperation,
  SwapProposal,
  TransferOperation,
} from '@mimicprotocol/sdk'

// List intents (filters are optional)
const intents: AxiaIntent[] = await client.intents.get({
  feePayer: '0x...',             // fee payer address
  settler: '0x...',              // settler address
  deadlineAfter: BigInt(1714600000),
  deadlineBefore: BigInt(1735600000),
  offset: 0,
  limit: 20,
})

// Get a specific intent by hash
const intent: AxiaIntent = await client.intents.getByHash('0x...')

// Type guards and decoders
for (const op of intent.operations) {
  if (isSwap(op)) {
    const swap: SwapOperation = client.intents.decodeSwapOperation(op)
    console.log(swap.sourceChain, swap.destinationChain, swap.tokensIn, swap.tokensOut)
  } else if (isTransfer(op)) {
    const transfer: TransferOperation = client.intents.decodeTransferOperation(op)
    console.log(transfer.chainId, transfer.transfers)
  } else if (isEvmCall(op)) {
    const call: EvmCallOperation = client.intents.decodeEvmCallOperation(op)
    console.log(call.chainId, call.calls)
  } else if (op.opType === OpType.EvmDynamicCall) { // Alternative to `isEvmDynamicCall(op)`
    const dynamicCall: EvmDynamicCallOperation = client.intents.decodeEvmDynamicCallOperation(op)
    console.log(dynamicCall.chainId, dynamicCall.calls)
  }
}

// ChainId helper — reads chainId from a single operation
const chainId: number = client.intents.getChainId(intent.operations[0])

// Proposal decoder — pass the proposal and the index of the operation it belongs to
const decoded: SwapProposal = client.intents.decodeProposal(intent.proposals[0], 0)

// Encoders
const encodedIntent = client.intents.encodeIntent({ /* Intent fields */ })
const encodedProposal = client.intents.encodeProposal({ /* Proposal fields */ }, intent)
const swapDataHex = client.intents.encodeSwapOperationData({ /* SwapOperationData */ })
const transferDataHex = client.intents.encodeTransferOperationData({ /* TransferOperationData */ })
const callDataHex = client.intents.encodeEvmCallOperationData({ /* EvmCallOperationData */ })
```

### Error Handling

The SDK uses structured error handling with the `ApiError` class.

```typescript
import { ApiError } from '@mimicprotocol/sdk'

try {
  const trigger = await client.triggers.getBySignature('invalid-signature')
} catch (error) {
  if (error instanceof ApiError) {
    console.error('API Error:', error.message)
    console.error('Status:', error.status)
    console.error('Code:', error.code)
    console.error('Details:', error.details)
  } else {
    console.error('Unexpected error:', error)
  }
}
```

### TypeScript Types

The SDK exports comprehensive TypeScript types for all data structures:

```typescript
import type {
  // Core types
  Client,
  InitOptions,

  // Domain types
  Trigger,
  Function,
  Execution,
  Intent,
  Operation,
  Balance,

  // Operation subtypes
  SwapOperation,
  TransferOperation,
  EvmCallOperation,
  EvmDynamicCallOperation,
  SwapProposal,

  // Authentication types
  Signer,
  EthersSigner,
  WindowEthereumSigner,
  ApiKeyAuth,
  BearerAuth,

  // Utility types
  Address,
  Signature,
  ChainId,
  Hash
} from '@mimicprotocol/sdk'
```

### Configuration Options

#### **Client Configuration**

```typescript
interface InitOptions {
  domains?: Partial<CoreConfig>  // Per-domain configuration
  baseUrl?: string              // Global base URL
  auth?: AuthStrategy           // Global authentication
  signer?: Signer              // Global signer
}
```

#### **Per-Domain Configuration**

```typescript
const client = new Client({
  domains: {
    triggers: {
      baseUrl: 'https://...',
      auth: new ApiKeyAuth('configs-key'),
      timeoutMs: 30000
    },
    functions: {
      baseUrl: 'https://...',
      auth: new BearerAuth('functions-token')
    }
  }
})
```

## Best Practices

1. **Error Handling**: Always wrap SDK calls in try-catch blocks and handle `ApiError` instances appropriately.
2. **Type Safety**: Leverage TypeScript types for better development experience and compile-time error checking.
3. **Configuration Management**: Use environment variables for sensitive data like API keys and private keys.
4. **Signer Management**: In production, use secure signer implementations and never expose private keys in client-side code.


# API


# Users

User authentication and profile management

## Request an authentication nonce

> Returns a nonce for the given address. The caller must sign this nonce and submit it to \`POST /users/authenticate\` to obtain a JWT.<br>

```json
{"openapi":"3.0.3","info":{"title":"Mimic Protocol API","version":"1.0.1"},"tags":[{"name":"Users","description":"User authentication and profile management"}],"servers":[{"url":"https://api-protocol.mimic.fi"}],"paths":{"/users/nonce":{"post":{"summary":"Request an authentication nonce","description":"Returns a nonce for the given address. The caller must sign this nonce and submit it to `POST /users/authenticate` to obtain a JWT.\n","operationId":"getUserNonce","tags":["Users"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserNonceRequest"}}}},"responses":{"200":{"description":"Nonce generated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserNonceResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"}}}}},"components":{"schemas":{"UserNonceRequest":{"type":"object","required":["address"],"properties":{"address":{"$ref":"#/components/schemas/Address"}}},"Address":{"type":"string","description":"A valid EVM (0x-prefixed hex) address."},"UserNonceResponse":{"type":"object","required":["address","nonce"],"properties":{"address":{"$ref":"#/components/schemas/Address"},"nonce":{"$ref":"#/components/schemas/HexString"}}},"HexString":{"type":"string","description":"An arbitrary 0x-prefixed hex string."},"Error":{"type":"object","properties":{"message":{"type":"string"}}}},"responses":{"BadRequest":{"description":"Bad request — invalid parameters or body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}
```

## Authenticate with a signed nonce

> Verifies the EIP-191 signature of the nonce returned by \`POST /users/nonce\` and returns a JWT token.<br>

```json
{"openapi":"3.0.3","info":{"title":"Mimic Protocol API","version":"1.0.1"},"tags":[{"name":"Users","description":"User authentication and profile management"}],"servers":[{"url":"https://api-protocol.mimic.fi"}],"paths":{"/users/authenticate":{"post":{"summary":"Authenticate with a signed nonce","description":"Verifies the EIP-191 signature of the nonce returned by `POST /users/nonce` and returns a JWT token.\n","operationId":"authenticateUser","tags":["Users"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserAuthenticationRequest"}}}},"responses":{"200":{"description":"Authentication successful","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserAuthenticationResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}}},"components":{"schemas":{"UserAuthenticationRequest":{"type":"object","required":["address","signature"],"properties":{"address":{"$ref":"#/components/schemas/Address"},"signature":{"allOf":[{"$ref":"#/components/schemas/Signature"}],"description":"Signature of the nonce obtained from `POST /users/nonce`"}}},"Address":{"type":"string","description":"A valid EVM (0x-prefixed hex) address."},"Signature":{"type":"string","description":"A 65-byte hex-encoded ECDSA signature (130 hex chars + 0x prefix)."},"UserAuthenticationResponse":{"type":"object","required":["address","token"],"properties":{"address":{"$ref":"#/components/schemas/Address"},"token":{"type":"string","description":"JWT to pass in `x-auth-token` on subsequent requests"},"email":{"type":"string","format":"email"}}},"Error":{"type":"object","properties":{"message":{"type":"string"}}}},"responses":{"Unauthorized":{"description":"Unauthorized — missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}
```

## GET /users/api-key

> Get the authenticated user's API key

```json
{"openapi":"3.0.3","info":{"title":"Mimic Protocol API","version":"1.0.1"},"tags":[{"name":"Users","description":"User authentication and profile management"}],"servers":[{"url":"https://api-protocol.mimic.fi"}],"security":[{"jwtAuth":[]}],"components":{"securitySchemes":{"jwtAuth":{"type":"apiKey","in":"header","name":"x-auth-token","description":"JWT token obtained from `POST /users/authenticate`"}},"schemas":{"UserApiKeyResponse":{"type":"object","required":["address","apiKey"],"properties":{"address":{"$ref":"#/components/schemas/Address"},"apiKey":{"type":"string"}}},"Address":{"type":"string","description":"A valid EVM (0x-prefixed hex) address."},"Error":{"type":"object","properties":{"message":{"type":"string"}}}},"responses":{"Unauthorized":{"description":"Unauthorized — missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/users/api-key":{"get":{"summary":"Get the authenticated user's API key","operationId":"getUserApiKey","tags":["Users"],"responses":{"200":{"description":"API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserApiKeyResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}}}}
```

## GET /users/tokens

> Get token balances for the authenticated user

```json
{"openapi":"3.0.3","info":{"title":"Mimic Protocol API","version":"1.0.1"},"tags":[{"name":"Users","description":"User authentication and profile management"}],"servers":[{"url":"https://api-protocol.mimic.fi"}],"security":[{"jwtAuth":[]}],"components":{"securitySchemes":{"jwtAuth":{"type":"apiKey","in":"header","name":"x-auth-token","description":"JWT token obtained from `POST /users/authenticate`"}},"schemas":{"UserToken":{"type":"object","required":["chainId","address","symbol","decimals","balance","allowance","price","logo"],"properties":{"chainId":{"$ref":"#/components/schemas/ChainId"},"address":{"$ref":"#/components/schemas/Address"},"symbol":{"type":"string"},"decimals":{"type":"integer","minimum":0},"balance":{"$ref":"#/components/schemas/BigInteger"},"allowance":{"$ref":"#/components/schemas/BigInteger"},"price":{"type":"number"},"logo":{"type":"string","format":"uri"}}},"ChainId":{"type":"integer","description":"A supported chain ID."},"Address":{"type":"string","description":"A valid EVM (0x-prefixed hex) address."},"BigInteger":{"type":"string","description":"A non-negative integer represented as a decimal string."},"Error":{"type":"object","properties":{"message":{"type":"string"}}}},"responses":{"Unauthorized":{"description":"Unauthorized — missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/users/tokens":{"get":{"summary":"Get token balances for the authenticated user","operationId":"getUserTokens","tags":["Users"],"responses":{"200":{"description":"List of token balances across chains","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UserToken"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}}}}
```

## Get user profile data

> Only the authenticated user may read their own profile.

```json
{"openapi":"3.0.3","info":{"title":"Mimic Protocol API","version":"1.0.1"},"tags":[{"name":"Users","description":"User authentication and profile management"}],"servers":[{"url":"https://api-protocol.mimic.fi"}],"security":[{"jwtAuth":[]}],"components":{"securitySchemes":{"jwtAuth":{"type":"apiKey","in":"header","name":"x-auth-token","description":"JWT token obtained from `POST /users/authenticate`"}},"parameters":{"AddressParam":{"name":"address","in":"path","required":true,"schema":{"$ref":"#/components/schemas/Address"}}},"schemas":{"Address":{"type":"string","description":"A valid EVM (0x-prefixed hex) address."},"UserData":{"type":"object","required":["userAddress","name","intendedUse"],"properties":{"userAddress":{"$ref":"#/components/schemas/EvmAddress"},"name":{"type":"string"},"intendedUse":{"type":"string","maxLength":255},"email":{"type":"string","format":"email","nullable":true}}},"EvmAddress":{"type":"string","description":"A valid EVM address (0x-prefixed, 20 bytes)."},"Error":{"type":"object","properties":{"message":{"type":"string"}}}},"responses":{"Unauthorized":{"description":"Unauthorized — missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"Forbidden — caller is not allowed to access this resource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/users/{address}/data":{"get":{"summary":"Get user profile data","description":"Only the authenticated user may read their own profile.","operationId":"getUserData","tags":["Users"],"parameters":[{"$ref":"#/components/parameters/AddressParam"}],"responses":{"200":{"description":"User profile data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserData"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}}}}
```

## Update user profile data

> Only the authenticated user may update their own profile.

```json
{"openapi":"3.0.3","info":{"title":"Mimic Protocol API","version":"1.0.1"},"tags":[{"name":"Users","description":"User authentication and profile management"}],"servers":[{"url":"https://api-protocol.mimic.fi"}],"security":[{"jwtAuth":[]}],"components":{"securitySchemes":{"jwtAuth":{"type":"apiKey","in":"header","name":"x-auth-token","description":"JWT token obtained from `POST /users/authenticate`"}},"parameters":{"AddressParam":{"name":"address","in":"path","required":true,"schema":{"$ref":"#/components/schemas/Address"}}},"schemas":{"Address":{"type":"string","description":"A valid EVM (0x-prefixed hex) address."},"UserDataUpdateRequest":{"type":"object","properties":{"name":{"type":"string"},"intendedUse":{"type":"string","maxLength":255}}},"UserData":{"type":"object","required":["userAddress","name","intendedUse"],"properties":{"userAddress":{"$ref":"#/components/schemas/EvmAddress"},"name":{"type":"string"},"intendedUse":{"type":"string","maxLength":255},"email":{"type":"string","format":"email","nullable":true}}},"EvmAddress":{"type":"string","description":"A valid EVM address (0x-prefixed, 20 bytes)."},"Error":{"type":"object","properties":{"message":{"type":"string"}}}},"responses":{"Unauthorized":{"description":"Unauthorized — missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"Forbidden — caller is not allowed to access this resource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/users/{address}/data":{"post":{"summary":"Update user profile data","description":"Only the authenticated user may update their own profile.","operationId":"updateUserData","tags":["Users"],"parameters":[{"$ref":"#/components/parameters/AddressParam"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserDataUpdateRequest"}}}},"responses":{"200":{"description":"Updated user profile data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserData"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}}}}
```


# Functions

Function registry

## GET /functions

> List registered functions

```json
{"openapi":"3.0.3","info":{"title":"Mimic Protocol API","version":"1.0.1"},"tags":[{"name":"Functions","description":"Function registry"}],"servers":[{"url":"https://api-protocol.mimic.fi"}],"paths":{"/functions":{"get":{"summary":"List registered functions","operationId":"getFunctions","tags":["Functions"],"parameters":[{"name":"cids","in":"query","description":"Comma-separated list of CIDs to filter by","schema":{"type":"string"}},{"name":"creator","in":"query","description":"Filter by creator EVM address","schema":{"$ref":"#/components/schemas/Address"}},{"$ref":"#/components/parameters/OffsetParam"},{"$ref":"#/components/parameters/LimitParam"}],"responses":{"200":{"description":"List of functions","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Function"}}}}}}}}},"components":{"schemas":{"Address":{"type":"string","description":"A valid EVM (0x-prefixed hex) address."},"Function":{"type":"object","required":["CID","name","version","description","createdAt"],"properties":{"CID":{"$ref":"#/components/schemas/CID"},"name":{"type":"string"},"version":{"type":"string"},"description":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}}},"CID":{"type":"string","description":"An IPFS content identifier (CIDv0 or CIDv1 base32)."}},"parameters":{"OffsetParam":{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0}},"LimitParam":{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":10}}}}}
```

## Upload a new function

> Uploads a function bundle. The request must be \`multipart/form-data\` containing exactly two files using the same multipart field name \`file\`. The filenames must be \`manifest.json\` and \`function.wasm\`.<br>

```json
{"openapi":"3.0.3","info":{"title":"Mimic Protocol API","version":"1.0.1"},"tags":[{"name":"Functions","description":"Function registry"}],"servers":[{"url":"https://api-protocol.mimic.fi"}],"security":[{"apiKeyAuth":[]}],"components":{"securitySchemes":{"apiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key obtained from `GET /users/api-key`"}},"schemas":{"Function":{"type":"object","required":["CID","name","version","description","createdAt"],"properties":{"CID":{"$ref":"#/components/schemas/CID"},"name":{"type":"string"},"version":{"type":"string"},"description":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}}},"CID":{"type":"string","description":"An IPFS content identifier (CIDv0 or CIDv1 base32)."},"Error":{"type":"object","properties":{"message":{"type":"string"}}}},"responses":{"BadRequest":{"description":"Bad request — invalid parameters or body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unauthorized":{"description":"Unauthorized — missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/functions":{"post":{"summary":"Upload a new function","description":"Uploads a function bundle. The request must be `multipart/form-data` containing exactly two files using the same multipart field name `file`. The filenames must be `manifest.json` and `function.wasm`.\n","operationId":"createFunction","tags":["Functions"],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"array","minItems":2,"maxItems":2,"items":{"type":"string","format":"binary"},"description":"Exactly two uploaded files using the same multipart field name `file`. The filenames must be `manifest.json` and `function.wasm`.\n"}}}}}},"responses":{"200":{"description":"Function registered","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Function"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}}}}}}
```

## GET /functions/{cid}

> Get a function by CID

```json
{"openapi":"3.0.3","info":{"title":"Mimic Protocol API","version":"1.0.1"},"tags":[{"name":"Functions","description":"Function registry"}],"servers":[{"url":"https://api-protocol.mimic.fi"}],"paths":{"/functions/{cid}":{"get":{"summary":"Get a function by CID","operationId":"getFunction","tags":["Functions"],"parameters":[{"$ref":"#/components/parameters/CidParam"}],"responses":{"200":{"description":"Function details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Function"}}}},"404":{"$ref":"#/components/responses/NotFound"}}}}},"components":{"parameters":{"CidParam":{"name":"cid","in":"path","required":true,"schema":{"$ref":"#/components/schemas/CID"}}},"schemas":{"CID":{"type":"string","description":"An IPFS content identifier (CIDv0 or CIDv1 base32)."},"Function":{"type":"object","required":["CID","name","version","description","createdAt"],"properties":{"CID":{"$ref":"#/components/schemas/CID"},"name":{"type":"string"},"version":{"type":"string"},"description":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}}},"Error":{"type":"object","properties":{"message":{"type":"string"}}}},"responses":{"NotFound":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}
```


# Triggers

Trigger lifecycle management

## GET /triggers

> List triggers

```json
{"openapi":"3.0.3","info":{"title":"Mimic Protocol API","version":"1.0.1"},"tags":[{"name":"Triggers","description":"Trigger lifecycle management"}],"servers":[{"url":"https://api-protocol.mimic.fi"}],"paths":{"/triggers":{"get":{"summary":"List triggers","operationId":"getTriggers","tags":["Triggers"],"parameters":[{"name":"sigs","in":"query","description":"Comma-separated list of trigger signatures to filter by","schema":{"type":"string"}},{"name":"functionCid","in":"query","schema":{"$ref":"#/components/schemas/CID"}},{"name":"signer","in":"query","schema":{"$ref":"#/components/schemas/Address"}},{"name":"active","in":"query","description":"Filter by active state","schema":{"type":"boolean"}},{"name":"createdAfter","in":"query","schema":{"$ref":"#/components/schemas/Timestamp"}},{"name":"createdBefore","in":"query","schema":{"$ref":"#/components/schemas/Timestamp"}},{"$ref":"#/components/parameters/OffsetParam"},{"$ref":"#/components/parameters/LimitParam"},{"$ref":"#/components/parameters/SortParam"}],"responses":{"200":{"description":"List of triggers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Trigger"}}}}}}}}},"components":{"schemas":{"CID":{"type":"string","description":"An IPFS content identifier (CIDv0 or CIDv1 base32)."},"Address":{"type":"string","description":"A valid EVM (0x-prefixed hex) address."},"Timestamp":{"type":"integer","description":"Unix timestamp in milliseconds."},"Trigger":{"type":"object","required":["sig","functionCid","signer","version","description","createdAt","input","config","executionFeeLimit","minValidations","types","endDate"],"properties":{"sig":{"$ref":"#/components/schemas/Signature"},"functionCid":{"$ref":"#/components/schemas/CID"},"signer":{"$ref":"#/components/schemas/Address"},"version":{"$ref":"#/components/schemas/SemVer"},"description":{"type":"string"},"deactivateSig":{"$ref":"#/components/schemas/Signature"},"createdAt":{"type":"string","format":"date-time"},"input":{"type":"object","additionalProperties":true},"config":{"$ref":"#/components/schemas/TriggerConfig"},"executionFeeLimit":{"$ref":"#/components/schemas/BigInteger"},"minValidations":{"type":"integer","minimum":0},"types":{"$ref":"#/components/schemas/TriggerTypes"},"endDate":{"$ref":"#/components/schemas/Timestamp"}}},"Signature":{"type":"string","description":"A 65-byte hex-encoded ECDSA signature (130 hex chars + 0x prefix)."},"SemVer":{"type":"string","description":"A semantic version string."},"TriggerConfig":{"description":"Trigger schedule configuration. Discriminated by the integer `type` field: `0` → CronTriggerConfig, `1` → EventTriggerConfig, `2` → OnceTriggerConfig.\n","oneOf":[{"$ref":"#/components/schemas/CronTriggerConfig"},{"$ref":"#/components/schemas/EventTriggerConfig"},{"$ref":"#/components/schemas/OnceTriggerConfig"}]},"CronTriggerConfig":{"type":"object","required":["type","schedule","delta","endDate"],"properties":{"type":{"type":"integer","enum":[0]},"schedule":{"type":"string","description":"A valid cron expression (e.g. `\"0 * * * *\"`)"},"delta":{"type":"string","description":"A time delta string (e.g. `\"1d\"`, `\"30m\"`)"},"endDate":{"$ref":"#/components/schemas/Timestamp"}}},"EventTriggerConfig":{"type":"object","required":["type","chainId","contract","topics","delta","endDate"],"properties":{"type":{"type":"integer","enum":[1]},"chainId":{"$ref":"#/components/schemas/ChainId"},"contract":{"description":"Contract address to filter events from, or `\"any\"` for any contract","oneOf":[{"$ref":"#/components/schemas/Address"},{"type":"string","enum":["any"]}]},"topics":{"type":"array","description":"Array of 1–4 topic groups. Each group is an OR filter; groups are AND-combined.\n","minItems":1,"maxItems":4,"items":{"type":"array","items":{"$ref":"#/components/schemas/HexString"}}},"delta":{"type":"string","description":"Time delta after the event before execution fires"},"endDate":{"$ref":"#/components/schemas/Timestamp"}}},"ChainId":{"type":"integer","description":"A supported chain ID."},"HexString":{"type":"string","description":"An arbitrary 0x-prefixed hex string."},"OnceTriggerConfig":{"type":"object","required":["type","startDate","delta","endDate"],"properties":{"type":{"type":"integer","enum":[2]},"startDate":{"$ref":"#/components/schemas/Timestamp"},"delta":{"type":"string","description":"Duration window; `endDate` must equal `startDate + delta`"},"endDate":{"$ref":"#/components/schemas/Timestamp"}}},"BigInteger":{"type":"string","description":"A non-negative integer represented as a decimal string."},"TriggerTypes":{"type":"object","required":["Input","Config","Trigger"],"description":"EIP-712 type definitions for the trigger's typed data","additionalProperties":{"type":"array","items":{"$ref":"#/components/schemas/TypedDataField"}},"properties":{"Input":{"type":"array","items":{"$ref":"#/components/schemas/TypedDataField"}},"Config":{"type":"array","items":{"$ref":"#/components/schemas/TypedDataField"}},"Trigger":{"type":"array","items":{"$ref":"#/components/schemas/TypedDataField"}}}},"TypedDataField":{"type":"object","required":["name","type"],"properties":{"name":{"type":"string"},"type":{"type":"string","description":"Solidity type or a custom type (`Token`, `TokenAmount`)"}}}},"parameters":{"OffsetParam":{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0}},"LimitParam":{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":10}},"SortParam":{"name":"sort","in":"query","description":"Sort order: `1` for ascending, `-1` for descending","schema":{"type":"integer","enum":[1,-1],"default":-1}}}}}
```

## Create a new trigger

> Registers a new trigger. The \`typedData\` is an EIP-712 typed data structure signed by \`signer\`. The signature is recovered on-chain to verify ownership.<br>

```json
{"openapi":"3.0.3","info":{"title":"Mimic Protocol API","version":"1.0.1"},"tags":[{"name":"Triggers","description":"Trigger lifecycle management"}],"servers":[{"url":"https://api-protocol.mimic.fi"}],"paths":{"/triggers":{"post":{"summary":"Create a new trigger","description":"Registers a new trigger. The `typedData` is an EIP-712 typed data structure signed by `signer`. The signature is recovered on-chain to verify ownership.\n","operationId":"createTrigger","tags":["Triggers"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerCreateRequest"}}}},"responses":{"200":{"description":"Trigger created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Trigger"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}}},"components":{"schemas":{"TriggerCreateRequest":{"type":"object","required":["description","typedData","sig","signer"],"properties":{"description":{"type":"string"},"typedData":{"$ref":"#/components/schemas/TriggerTypedData"},"sig":{"allOf":[{"$ref":"#/components/schemas/Signature"}],"description":"EIP-712 signature over `typedData` by `signer`"},"signer":{"$ref":"#/components/schemas/EvmAddress"}}},"TriggerTypedData":{"type":"object","required":["types","values"],"properties":{"types":{"$ref":"#/components/schemas/TriggerTypes"},"values":{"$ref":"#/components/schemas/TriggerTypedDataValues"}}},"TriggerTypes":{"type":"object","required":["Input","Config","Trigger"],"description":"EIP-712 type definitions for the trigger's typed data","additionalProperties":{"type":"array","items":{"$ref":"#/components/schemas/TypedDataField"}},"properties":{"Input":{"type":"array","items":{"$ref":"#/components/schemas/TypedDataField"}},"Config":{"type":"array","items":{"$ref":"#/components/schemas/TypedDataField"}},"Trigger":{"type":"array","items":{"$ref":"#/components/schemas/TypedDataField"}}}},"TypedDataField":{"type":"object","required":["name","type"],"properties":{"name":{"type":"string"},"type":{"type":"string","description":"Solidity type or a custom type (`Token`, `TokenAmount`)"}}},"TriggerTypedDataValues":{"type":"object","required":["functionCid","version","input","config","executionFeeLimit","minValidations"],"properties":{"functionCid":{"$ref":"#/components/schemas/CID"},"version":{"$ref":"#/components/schemas/SemVer"},"input":{"type":"object","additionalProperties":true,"description":"Key-value map matching the function's manifest input schema"},"config":{"$ref":"#/components/schemas/TriggerConfig"},"executionFeeLimit":{"allOf":[{"$ref":"#/components/schemas/BigInteger"}],"description":"Maximum fee (in protocol units) the signer accepts per execution"},"minValidations":{"type":"integer","minimum":0,"description":"Minimum number of validator confirmations required"}}},"CID":{"type":"string","description":"An IPFS content identifier (CIDv0 or CIDv1 base32)."},"SemVer":{"type":"string","description":"A semantic version string."},"TriggerConfig":{"description":"Trigger schedule configuration. Discriminated by the integer `type` field: `0` → CronTriggerConfig, `1` → EventTriggerConfig, `2` → OnceTriggerConfig.\n","oneOf":[{"$ref":"#/components/schemas/CronTriggerConfig"},{"$ref":"#/components/schemas/EventTriggerConfig"},{"$ref":"#/components/schemas/OnceTriggerConfig"}]},"CronTriggerConfig":{"type":"object","required":["type","schedule","delta","endDate"],"properties":{"type":{"type":"integer","enum":[0]},"schedule":{"type":"string","description":"A valid cron expression (e.g. `\"0 * * * *\"`)"},"delta":{"type":"string","description":"A time delta string (e.g. `\"1d\"`, `\"30m\"`)"},"endDate":{"$ref":"#/components/schemas/Timestamp"}}},"Timestamp":{"type":"integer","description":"Unix timestamp in milliseconds."},"EventTriggerConfig":{"type":"object","required":["type","chainId","contract","topics","delta","endDate"],"properties":{"type":{"type":"integer","enum":[1]},"chainId":{"$ref":"#/components/schemas/ChainId"},"contract":{"description":"Contract address to filter events from, or `\"any\"` for any contract","oneOf":[{"$ref":"#/components/schemas/Address"},{"type":"string","enum":["any"]}]},"topics":{"type":"array","description":"Array of 1–4 topic groups. Each group is an OR filter; groups are AND-combined.\n","minItems":1,"maxItems":4,"items":{"type":"array","items":{"$ref":"#/components/schemas/HexString"}}},"delta":{"type":"string","description":"Time delta after the event before execution fires"},"endDate":{"$ref":"#/components/schemas/Timestamp"}}},"ChainId":{"type":"integer","description":"A supported chain ID."},"Address":{"type":"string","description":"A valid EVM (0x-prefixed hex) address."},"HexString":{"type":"string","description":"An arbitrary 0x-prefixed hex string."},"OnceTriggerConfig":{"type":"object","required":["type","startDate","delta","endDate"],"properties":{"type":{"type":"integer","enum":[2]},"startDate":{"$ref":"#/components/schemas/Timestamp"},"delta":{"type":"string","description":"Duration window; `endDate` must equal `startDate + delta`"},"endDate":{"$ref":"#/components/schemas/Timestamp"}}},"BigInteger":{"type":"string","description":"A non-negative integer represented as a decimal string."},"Signature":{"type":"string","description":"A 65-byte hex-encoded ECDSA signature (130 hex chars + 0x prefix)."},"EvmAddress":{"type":"string","description":"A valid EVM address (0x-prefixed, 20 bytes)."},"Trigger":{"type":"object","required":["sig","functionCid","signer","version","description","createdAt","input","config","executionFeeLimit","minValidations","types","endDate"],"properties":{"sig":{"$ref":"#/components/schemas/Signature"},"functionCid":{"$ref":"#/components/schemas/CID"},"signer":{"$ref":"#/components/schemas/Address"},"version":{"$ref":"#/components/schemas/SemVer"},"description":{"type":"string"},"deactivateSig":{"$ref":"#/components/schemas/Signature"},"createdAt":{"type":"string","format":"date-time"},"input":{"type":"object","additionalProperties":true},"config":{"$ref":"#/components/schemas/TriggerConfig"},"executionFeeLimit":{"$ref":"#/components/schemas/BigInteger"},"minValidations":{"type":"integer","minimum":0},"types":{"$ref":"#/components/schemas/TriggerTypes"},"endDate":{"$ref":"#/components/schemas/Timestamp"}}},"Error":{"type":"object","properties":{"message":{"type":"string"}}}},"responses":{"BadRequest":{"description":"Bad request — invalid parameters or body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unauthorized":{"description":"Unauthorized — missing or invalid credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}
```

## Compute EIP-712 sign parameters for a trigger

> Returns the EIP-712 typed data structure (domain, primaryType, types, and message) needed to sign a new trigger. The caller must sign the returned \`message\` and submit it with the signature to \`POST /triggers\`.<br>

```json
{"openapi":"3.0.3","info":{"title":"Mimic Protocol API","version":"1.0.1"},"tags":[{"name":"Triggers","description":"Trigger lifecycle management"}],"servers":[{"url":"https://api-protocol.mimic.fi"}],"paths":{"/triggers/sign-params":{"post":{"summary":"Compute EIP-712 sign parameters for a trigger","description":"Returns the EIP-712 typed data structure (domain, primaryType, types, and message) needed to sign a new trigger. The caller must sign the returned `message` and submit it with the signature to `POST /triggers`.\n","operationId":"getTriggerSignParams","tags":["Triggers"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerSignParamsRequest"}}}},"responses":{"200":{"description":"EIP-712 sign parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerSignParams"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"}}}}},"components":{"schemas":{"TriggerSignParamsRequest":{"type":"object","required":["functionCid","version","input","config"],"properties":{"functionCid":{"$ref":"#/components/schemas/CID"},"version":{"$ref":"#/components/schemas/SemVer"},"input":{"type":"object","additionalProperties":true,"description":"Key-value map matching the function's manifest input schema"},"config":{"$ref":"#/components/schemas/TriggerConfig"}}},"CID":{"type":"string","description":"An IPFS content identifier (CIDv0 or CIDv1 base32)."},"SemVer":{"type":"string","description":"A semantic version string."},"TriggerConfig":{"description":"Trigger schedule configuration. Discriminated by the integer `type` field: `0` → CronTriggerConfig, `1` → EventTriggerConfig, `2` → OnceTriggerConfig.\n","oneOf":[{"$ref":"#/components/schemas/CronTriggerConfig"},{"$ref":"#/components/schemas/EventTriggerConfig"},{"$ref":"#/components/schemas/OnceTriggerConfig"}]},"CronTriggerConfig":{"type":"object","required":["type","schedule","delta","endDate"],"properties":{"type":{"type":"integer","enum":[0]},"schedule":{"type":"string","description":"A valid cron expression (e.g. `\"0 * * * *\"`)"},"delta":{"type":"string","description":"A time delta string (e.g. `\"1d\"`, `\"30m\"`)"},"endDate":{"$ref":"#/components/schemas/Timestamp"}}},"Timestamp":{"type":"integer","description":"Unix timestamp in milliseconds."},"EventTriggerConfig":{"type":"object","required":["type","chainId","contract","topics","delta","endDate"],"properties":{"type":{"type":"integer","enum":[1]},"chainId":{"$ref":"#/components/schemas/ChainId"},"contract":{"description":"Contract address to filter events from, or `\"any\"` for any contract","oneOf":[{"$ref":"#/components/schemas/Address"},{"type":"string","enum":["any"]}]},"topics":{"type":"array","description":"Array of 1–4 topic groups. Each group is an OR filter; groups are AND-combined.\n","minItems":1,"maxItems":4,"items":{"type":"array","items":{"$ref":"#/components/schemas/HexString"}}},"delta":{"type":"string","description":"Time delta after the event before execution fires"},"endDate":{"$ref":"#/components/schemas/Timestamp"}}},"ChainId":{"type":"integer","description":"A supported chain ID."},"Address":{"type":"string","description":"A valid EVM (0x-prefixed hex) address."},"HexString":{"type":"string","description":"An arbitrary 0x-prefixed hex string."},"OnceTriggerConfig":{"type":"object","required":["type","startDate","delta","endDate"],"properties":{"type":{"type":"integer","enum":[2]},"startDate":{"$ref":"#/components/schemas/Timestamp"},"delta":{"type":"string","description":"Duration window; `endDate` must equal `startDate + delta`"},"endDate":{"$ref":"#/components/schemas/Timestamp"}}},"TriggerSignParams":{"type":"object","description":"EIP-712 typed data structure ready to be signed by the caller","required":["domain","primaryType","types","message"],"properties":{"domain":{"type":"object","required":["name","version"],"properties":{"name":{"type":"string"},"version":{"type":"string"}}},"primaryType":{"type":"string"},"types":{"$ref":"#/components/schemas/TriggerTypes"},"message":{"$ref":"#/components/schemas/TriggerTypedDataValues"}}},"TriggerTypes":{"type":"object","required":["Input","Config","Trigger"],"description":"EIP-712 type definitions for the trigger's typed data","additionalProperties":{"type":"array","items":{"$ref":"#/components/schemas/TypedDataField"}},"properties":{"Input":{"type":"array","items":{"$ref":"#/components/schemas/TypedDataField"}},"Config":{"type":"array","items":{"$ref":"#/components/schemas/TypedDataField"}},"Trigger":{"type":"array","items":{"$ref":"#/components/schemas/TypedDataField"}}}},"TypedDataField":{"type":"object","required":["name","type"],"properties":{"name":{"type":"string"},"type":{"type":"string","description":"Solidity type or a custom type (`Token`, `TokenAmount`)"}}},"TriggerTypedDataValues":{"type":"object","required":["functionCid","version","input","config","executionFeeLimit","minValidations"],"properties":{"functionCid":{"$ref":"#/components/schemas/CID"},"version":{"$ref":"#/components/schemas/SemVer"},"input":{"type":"object","additionalProperties":true,"description":"Key-value map matching the function's manifest input schema"},"config":{"$ref":"#/components/schemas/TriggerConfig"},"executionFeeLimit":{"allOf":[{"$ref":"#/components/schemas/BigInteger"}],"description":"Maximum fee (in protocol units) the signer accepts per execution"},"minValidations":{"type":"integer","minimum":0,"description":"Minimum number of validator confirmations required"}}},"BigInteger":{"type":"string","description":"A non-negative integer represented as a decimal string."},"Error":{"type":"object","properties":{"message":{"type":"string"}}}},"responses":{"BadRequest":{"description":"Bad request — invalid parameters or body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}
```

## GET /triggers/{sig}

> Get a trigger by its signature

```json
{"openapi":"3.0.3","info":{"title":"Mimic Protocol API","version":"1.0.1"},"tags":[{"name":"Triggers","description":"Trigger lifecycle management"}],"servers":[{"url":"https://api-protocol.mimic.fi"}],"paths":{"/triggers/{sig}":{"get":{"summary":"Get a trigger by its signature","operationId":"getTrigger","tags":["Triggers"],"parameters":[{"name":"sig","in":"path","required":true,"schema":{"$ref":"#/components/schemas/Signature"}}],"responses":{"200":{"description":"Trigger details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Trigger"}}}},"404":{"$ref":"#/components/responses/NotFound"}}}}},"components":{"schemas":{"Signature":{"type":"string","description":"A 65-byte hex-encoded ECDSA signature (130 hex chars + 0x prefix)."},"Trigger":{"type":"object","required":["sig","functionCid","signer","version","description","createdAt","input","config","executionFeeLimit","minValidations","types","endDate"],"properties":{"sig":{"$ref":"#/components/schemas/Signature"},"functionCid":{"$ref":"#/components/schemas/CID"},"signer":{"$ref":"#/components/schemas/Address"},"version":{"$ref":"#/components/schemas/SemVer"},"description":{"type":"string"},"deactivateSig":{"$ref":"#/components/schemas/Signature"},"createdAt":{"type":"string","format":"date-time"},"input":{"type":"object","additionalProperties":true},"config":{"$ref":"#/components/schemas/TriggerConfig"},"executionFeeLimit":{"$ref":"#/components/schemas/BigInteger"},"minValidations":{"type":"integer","minimum":0},"types":{"$ref":"#/components/schemas/TriggerTypes"},"endDate":{"$ref":"#/components/schemas/Timestamp"}}},"CID":{"type":"string","description":"An IPFS content identifier (CIDv0 or CIDv1 base32)."},"Address":{"type":"string","description":"A valid EVM (0x-prefixed hex) address."},"SemVer":{"type":"string","description":"A semantic version string."},"TriggerConfig":{"description":"Trigger schedule configuration. Discriminated by the integer `type` field: `0` → CronTriggerConfig, `1` → EventTriggerConfig, `2` → OnceTriggerConfig.\n","oneOf":[{"$ref":"#/components/schemas/CronTriggerConfig"},{"$ref":"#/components/schemas/EventTriggerConfig"},{"$ref":"#/components/schemas/OnceTriggerConfig"}]},"CronTriggerConfig":{"type":"object","required":["type","schedule","delta","endDate"],"properties":{"type":{"type":"integer","enum":[0]},"schedule":{"type":"string","description":"A valid cron expression (e.g. `\"0 * * * *\"`)"},"delta":{"type":"string","description":"A time delta string (e.g. `\"1d\"`, `\"30m\"`)"},"endDate":{"$ref":"#/components/schemas/Timestamp"}}},"Timestamp":{"type":"integer","description":"Unix timestamp in milliseconds."},"EventTriggerConfig":{"type":"object","required":["type","chainId","contract","topics","delta","endDate"],"properties":{"type":{"type":"integer","enum":[1]},"chainId":{"$ref":"#/components/schemas/ChainId"},"contract":{"description":"Contract address to filter events from, or `\"any\"` for any contract","oneOf":[{"$ref":"#/components/schemas/Address"},{"type":"string","enum":["any"]}]},"topics":{"type":"array","description":"Array of 1–4 topic groups. Each group is an OR filter; groups are AND-combined.\n","minItems":1,"maxItems":4,"items":{"type":"array","items":{"$ref":"#/components/schemas/HexString"}}},"delta":{"type":"string","description":"Time delta after the event before execution fires"},"endDate":{"$ref":"#/components/schemas/Timestamp"}}},"ChainId":{"type":"integer","description":"A supported chain ID."},"HexString":{"type":"string","description":"An arbitrary 0x-prefixed hex string."},"OnceTriggerConfig":{"type":"object","required":["type","startDate","delta","endDate"],"properties":{"type":{"type":"integer","enum":[2]},"startDate":{"$ref":"#/components/schemas/Timestamp"},"delta":{"type":"string","description":"Duration window; `endDate` must equal `startDate + delta`"},"endDate":{"$ref":"#/components/schemas/Timestamp"}}},"BigInteger":{"type":"string","description":"A non-negative integer represented as a decimal string."},"TriggerTypes":{"type":"object","required":["Input","Config","Trigger"],"description":"EIP-712 type definitions for the trigger's typed data","additionalProperties":{"type":"array","items":{"$ref":"#/components/schemas/TypedDataField"}},"properties":{"Input":{"type":"array","items":{"$ref":"#/components/schemas/TypedDataField"}},"Config":{"type":"array","items":{"$ref":"#/components/schemas/TypedDataField"}},"Trigger":{"type":"array","items":{"$ref":"#/components/schemas/TypedDataField"}}}},"TypedDataField":{"type":"object","required":["name","type"],"properties":{"name":{"type":"string"},"type":{"type":"string","description":"Solidity type or a custom type (`Token`, `TokenAmount`)"}}},"Error":{"type":"object","properties":{"message":{"type":"string"}}}},"responses":{"NotFound":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}
```

## Deactivate one or more triggers

> Permanently deactivates one or more triggers. The \`signature\` must be signed by the original trigger signer, and all provided \`triggerSigs\` must belong to that same signer.<br>

```json
{"openapi":"3.0.3","info":{"title":"Mimic Protocol API","version":"1.0.1"},"tags":[{"name":"Triggers","description":"Trigger lifecycle management"}],"servers":[{"url":"https://api-protocol.mimic.fi"}],"paths":{"/triggers/deactivate":{"post":{"summary":"Deactivate one or more triggers","description":"Permanently deactivates one or more triggers. The `signature` must be signed by the original trigger signer, and all provided `triggerSigs` must belong to that same signer.\n","operationId":"deactivateTriggers","tags":["Triggers"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriggerDeactivateRequest"}}}},"responses":{"204":{"description":"Triggers deactivated"},"400":{"$ref":"#/components/responses/BadRequest"}}}}},"components":{"schemas":{"TriggerDeactivateRequest":{"type":"object","required":["triggerSigs","signature"],"properties":{"triggerSigs":{"type":"array","minItems":1,"uniqueItems":true,"items":{"$ref":"#/components/schemas/Signature"},"description":"Trigger signatures to deactivate"},"signature":{"allOf":[{"$ref":"#/components/schemas/Signature"}],"description":"Signature authorizing the deactivation of all provided triggers"}}},"Signature":{"type":"string","description":"A 65-byte hex-encoded ECDSA signature (130 hex chars + 0x prefix)."},"Error":{"type":"object","properties":{"message":{"type":"string"}}}},"responses":{"BadRequest":{"description":"Bad request — invalid parameters or body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}
```


# Settlers

Active settler contracts

## GET /settlers

> List active settlers

```json
{"openapi":"3.0.3","info":{"title":"Mimic Protocol API","version":"1.0.1"},"tags":[{"name":"Settlers","description":"Active settler contracts"}],"servers":[{"url":"https://api-protocol.mimic.fi"}],"paths":{"/settlers":{"get":{"summary":"List active settlers","operationId":"getSettlers","tags":["Settlers"],"responses":{"200":{"description":"List of active settlers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Settler"}}}}}}}}},"components":{"schemas":{"Settler":{"type":"object","required":["address","chainId","createdAt"],"properties":{"address":{"$ref":"#/components/schemas/Address"},"chainId":{"$ref":"#/components/schemas/ChainId"},"createdAt":{"type":"string","format":"date-time"}}},"Address":{"type":"string","description":"A valid EVM (0x-prefixed hex) address."},"ChainId":{"type":"integer","description":"A supported chain ID."}}}}
```


# Intents

Intent lifecycle

## GET /intents

> List intents

```json
{"openapi":"3.0.3","info":{"title":"Mimic Protocol API","version":"1.0.1"},"tags":[{"name":"Intents","description":"Intent lifecycle"}],"servers":[{"url":"https://api-protocol.mimic.fi"}],"paths":{"/intents":{"get":{"summary":"List intents","operationId":"getIntents","tags":["Intents"],"parameters":[{"name":"user","in":"query","description":"Filter by user address","schema":{"$ref":"#/components/schemas/Address"}},{"name":"deadlineAfter","in":"query","description":"Filter intents with deadline > this value (Unix epoch seconds)","schema":{"$ref":"#/components/schemas/BigInteger"}},{"name":"deadlineBefore","in":"query","description":"Filter intents with deadline ≤ this value (Unix epoch seconds)","schema":{"$ref":"#/components/schemas/BigInteger"}},{"name":"settler","in":"query","description":"Filter by settler address","schema":{"$ref":"#/components/schemas/Address"}},{"$ref":"#/components/parameters/OffsetParam"},{"$ref":"#/components/parameters/LimitParam"}],"responses":{"200":{"description":"List of intents","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AxiaIntent"}}}}}}}}},"components":{"schemas":{"Address":{"type":"string","description":"A valid EVM (0x-prefixed hex) address."},"BigInteger":{"type":"string","description":"A non-negative integer represented as a decimal string."},"AxiaIntent":{"description":"An intent enriched with lifecycle state, proposals, and logs","allOf":[{"$ref":"#/components/schemas/Intent"},{"type":"object","required":["hash","executionHash","status","proposals","logs"],"properties":{"hash":{"$ref":"#/components/schemas/HexString"},"executionHash":{"$ref":"#/components/schemas/HexString"},"status":{"type":"string","enum":["created","enqueued","discarded","submitted","succeeded","failed","expired"]},"proposals":{"type":"array","items":{"$ref":"#/components/schemas/Proposal"}},"logs":{"type":"array","items":{"$ref":"#/components/schemas/IntentLog"}}}}]},"Intent":{"type":"object","required":["op","user","settler","nonce","deadline","data","maxFees","events","configSig","minValidations"],"properties":{"op":{"$ref":"#/components/schemas/OpType"},"user":{"$ref":"#/components/schemas/Address"},"settler":{"allOf":[{"$ref":"#/components/schemas/Address"}],"description":"Address of the settler contract that will settle this intent"},"nonce":{"$ref":"#/components/schemas/HexString"},"deadline":{"allOf":[{"$ref":"#/components/schemas/BigInteger"}],"description":"Unix epoch in seconds after which the intent expires"},"data":{"allOf":[{"$ref":"#/components/schemas/HexString"}],"description":"ABI-encoded operation-specific data"},"maxFees":{"type":"array","items":{"$ref":"#/components/schemas/MaxFee"}},"events":{"type":"array","items":{"$ref":"#/components/schemas/IntentEvent"}},"configSig":{"$ref":"#/components/schemas/Signature"},"minValidations":{"type":"number","minimum":0}}},"OpType":{"type":"integer","enum":[0,1,2,3],"description":"Intent operation type:\n- `0` — Swap\n- `1` — Transfer\n- `2` — EvmCall\n- `3` — SvmCall\n"},"HexString":{"type":"string","description":"An arbitrary 0x-prefixed hex string."},"MaxFee":{"type":"object","required":["token","amount"],"properties":{"token":{"$ref":"#/components/schemas/Address"},"amount":{"$ref":"#/components/schemas/BigInteger"}}},"IntentEvent":{"type":"object","required":["topic","data"],"properties":{"topic":{"$ref":"#/components/schemas/HexString"},"data":{"$ref":"#/components/schemas/HexString"}}},"Signature":{"type":"string","description":"A 65-byte hex-encoded ECDSA signature (130 hex chars + 0x prefix)."},"Proposal":{"type":"object","required":["solver","data","deadline","fees","feeUsd","status","signatures"],"properties":{"solver":{"$ref":"#/components/schemas/Address"},"data":{"$ref":"#/components/schemas/HexString"},"deadline":{"$ref":"#/components/schemas/BigInteger"},"fees":{"type":"array","items":{"$ref":"#/components/schemas/BigInteger"}},"feeUsd":{"allOf":[{"$ref":"#/components/schemas/BigInteger"}],"description":"Total fee expressed in USD (scaled integer)"},"status":{"type":"string","enum":["received","discarded","submitted","succeeded","failed","expired"]},"description":{"type":"string"},"signatures":{"type":"array","items":{"$ref":"#/components/schemas/Signature"}},"transactionHash":{"$ref":"#/components/schemas/HexString"},"destTransactionHash":{"$ref":"#/components/schemas/HexString"}}},"IntentLog":{"type":"object","required":["level","data","createdAt"],"properties":{"level":{"type":"string","enum":["info","success","error"]},"data":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}}}},"parameters":{"OffsetParam":{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0}},"LimitParam":{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":10}}}}}
```

## GET /intents/{hash}

> Get an intent by hash

```json
{"openapi":"3.0.3","info":{"title":"Mimic Protocol API","version":"1.0.1"},"tags":[{"name":"Intents","description":"Intent lifecycle"}],"servers":[{"url":"https://api-protocol.mimic.fi"}],"paths":{"/intents/{hash}":{"get":{"summary":"Get an intent by hash","operationId":"getIntent","tags":["Intents"],"parameters":[{"name":"hash","in":"path","required":true,"schema":{"$ref":"#/components/schemas/HexString"}}],"responses":{"200":{"description":"Intent details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AxiaIntent"}}}},"404":{"$ref":"#/components/responses/NotFound"}}}}},"components":{"schemas":{"HexString":{"type":"string","description":"An arbitrary 0x-prefixed hex string."},"AxiaIntent":{"description":"An intent enriched with lifecycle state, proposals, and logs","allOf":[{"$ref":"#/components/schemas/Intent"},{"type":"object","required":["hash","executionHash","status","proposals","logs"],"properties":{"hash":{"$ref":"#/components/schemas/HexString"},"executionHash":{"$ref":"#/components/schemas/HexString"},"status":{"type":"string","enum":["created","enqueued","discarded","submitted","succeeded","failed","expired"]},"proposals":{"type":"array","items":{"$ref":"#/components/schemas/Proposal"}},"logs":{"type":"array","items":{"$ref":"#/components/schemas/IntentLog"}}}}]},"Intent":{"type":"object","required":["op","user","settler","nonce","deadline","data","maxFees","events","configSig","minValidations"],"properties":{"op":{"$ref":"#/components/schemas/OpType"},"user":{"$ref":"#/components/schemas/Address"},"settler":{"allOf":[{"$ref":"#/components/schemas/Address"}],"description":"Address of the settler contract that will settle this intent"},"nonce":{"$ref":"#/components/schemas/HexString"},"deadline":{"allOf":[{"$ref":"#/components/schemas/BigInteger"}],"description":"Unix epoch in seconds after which the intent expires"},"data":{"allOf":[{"$ref":"#/components/schemas/HexString"}],"description":"ABI-encoded operation-specific data"},"maxFees":{"type":"array","items":{"$ref":"#/components/schemas/MaxFee"}},"events":{"type":"array","items":{"$ref":"#/components/schemas/IntentEvent"}},"configSig":{"$ref":"#/components/schemas/Signature"},"minValidations":{"type":"number","minimum":0}}},"OpType":{"type":"integer","enum":[0,1,2,3],"description":"Intent operation type:\n- `0` — Swap\n- `1` — Transfer\n- `2` — EvmCall\n- `3` — SvmCall\n"},"Address":{"type":"string","description":"A valid EVM (0x-prefixed hex) address."},"BigInteger":{"type":"string","description":"A non-negative integer represented as a decimal string."},"MaxFee":{"type":"object","required":["token","amount"],"properties":{"token":{"$ref":"#/components/schemas/Address"},"amount":{"$ref":"#/components/schemas/BigInteger"}}},"IntentEvent":{"type":"object","required":["topic","data"],"properties":{"topic":{"$ref":"#/components/schemas/HexString"},"data":{"$ref":"#/components/schemas/HexString"}}},"Signature":{"type":"string","description":"A 65-byte hex-encoded ECDSA signature (130 hex chars + 0x prefix)."},"Proposal":{"type":"object","required":["solver","data","deadline","fees","feeUsd","status","signatures"],"properties":{"solver":{"$ref":"#/components/schemas/Address"},"data":{"$ref":"#/components/schemas/HexString"},"deadline":{"$ref":"#/components/schemas/BigInteger"},"fees":{"type":"array","items":{"$ref":"#/components/schemas/BigInteger"}},"feeUsd":{"allOf":[{"$ref":"#/components/schemas/BigInteger"}],"description":"Total fee expressed in USD (scaled integer)"},"status":{"type":"string","enum":["received","discarded","submitted","succeeded","failed","expired"]},"description":{"type":"string"},"signatures":{"type":"array","items":{"$ref":"#/components/schemas/Signature"}},"transactionHash":{"$ref":"#/components/schemas/HexString"},"destTransactionHash":{"$ref":"#/components/schemas/HexString"}}},"IntentLog":{"type":"object","required":["level","data","createdAt"],"properties":{"level":{"type":"string","enum":["info","success","error"]},"data":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}}},"Error":{"type":"object","properties":{"message":{"type":"string"}}}},"responses":{"NotFound":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}
```


# Executions

Trigger execution records

## GET /executions

> List executions

```json
{"openapi":"3.0.3","info":{"title":"Mimic Protocol API","version":"1.0.1"},"tags":[{"name":"Executions","description":"Trigger execution records"}],"servers":[{"url":"https://api-protocol.mimic.fi"}],"paths":{"/executions":{"get":{"summary":"List executions","operationId":"getExecutions","tags":["Executions"],"parameters":[{"name":"triggerSig","in":"query","description":"Filter by trigger signature","schema":{"type":"string"}},{"name":"createdAfter","in":"query","schema":{"$ref":"#/components/schemas/Timestamp"}},{"name":"createdBefore","in":"query","schema":{"$ref":"#/components/schemas/Timestamp"}},{"$ref":"#/components/parameters/OffsetParam"},{"$ref":"#/components/parameters/LimitParam"},{"$ref":"#/components/parameters/SortParam"}],"responses":{"200":{"description":"List of executions","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ExecutionResponse"}}}}}}}}},"components":{"schemas":{"Timestamp":{"type":"integer","description":"Unix timestamp in milliseconds."},"ExecutionResponse":{"description":"An execution record with relayer, status, fee, and validation details","allOf":[{"$ref":"#/components/schemas/ExecutionCreateRequest"},{"type":"object","required":["relayer","status","createdAt"],"properties":{"relayer":{"$ref":"#/components/schemas/Address"},"status":{"type":"string","enum":["pending","valid","invalid"]},"createdAt":{"type":"string","format":"date-time"},"logs":{"type":"array","items":{"type":"string"}},"fee":{"$ref":"#/components/schemas/ExecutionFee"},"solverFees":{"type":"array","items":{"$ref":"#/components/schemas/SolverFee"}},"validations":{"type":"array","items":{"$ref":"#/components/schemas/ExecutionValidation"}}}}]},"ExecutionCreateRequest":{"type":"object","required":["triggerSig","triggerType","triggerData","hash","timestamp","fuelUsed","logs","inputs","outputs","signature","result"],"properties":{"triggerSig":{"$ref":"#/components/schemas/Signature"},"triggerType":{"$ref":"#/components/schemas/TriggerType"},"triggerData":{"allOf":[{"$ref":"#/components/schemas/HexString"}],"description":"ABI-encoded trigger-specific execution data"},"hash":{"$ref":"#/components/schemas/HexString"},"timestamp":{"$ref":"#/components/schemas/Timestamp"},"fuelUsed":{"type":"integer","minimum":0},"logs":{"type":"array","items":{"type":"string"}},"inputs":{"type":"array","items":{"$ref":"#/components/schemas/OracleResponse"}},"outputs":{"type":"array","items":{"$ref":"#/components/schemas/ExecutionIntent"}},"signature":{"allOf":[{"$ref":"#/components/schemas/Signature"}],"description":"Relayer signature over the execution"},"result":{"type":"string","enum":["succeeded","failed"]}}},"Signature":{"type":"string","description":"A 65-byte hex-encoded ECDSA signature (130 hex chars + 0x prefix)."},"TriggerType":{"type":"integer","enum":[0,1,2],"description":"Trigger execution mode:\n- `0` — Cron: fires on a recurring cron schedule\n- `1` — Event: fires on an on-chain event\n- `2` — Once: fires exactly once at a specific time\n"},"HexString":{"type":"string","description":"An arbitrary 0x-prefixed hex string."},"OracleResponse":{"type":"object","description":"An oracle-signed query response. The shape of `query.params` and `result.value` depends on `query.name` (TokenPriceQuery, EvmCallQuery, SvmAccountsInfoQuery, RelevantTokensQuery, SubgraphQuery).\n","required":["signature","query","result"],"properties":{"signature":{"$ref":"#/components/schemas/Signature"},"query":{"type":"object","required":["name","hash","params"],"properties":{"name":{"type":"string","enum":["TokenPriceQuery","EvmCallQuery","SvmAccountsInfoQuery","RelevantTokensQuery","SubgraphQuery"]},"hash":{"$ref":"#/components/schemas/HexString"},"params":{"type":"object","additionalProperties":true}}},"result":{"type":"object","required":["value"],"properties":{"value":{}}}}},"ExecutionIntent":{"description":"An intent output produced by an execution","allOf":[{"$ref":"#/components/schemas/Intent"},{"type":"object","required":["hash"],"properties":{"hash":{"$ref":"#/components/schemas/HexString"}}}]},"Intent":{"type":"object","required":["op","user","settler","nonce","deadline","data","maxFees","events","configSig","minValidations"],"properties":{"op":{"$ref":"#/components/schemas/OpType"},"user":{"$ref":"#/components/schemas/Address"},"settler":{"allOf":[{"$ref":"#/components/schemas/Address"}],"description":"Address of the settler contract that will settle this intent"},"nonce":{"$ref":"#/components/schemas/HexString"},"deadline":{"allOf":[{"$ref":"#/components/schemas/BigInteger"}],"description":"Unix epoch in seconds after which the intent expires"},"data":{"allOf":[{"$ref":"#/components/schemas/HexString"}],"description":"ABI-encoded operation-specific data"},"maxFees":{"type":"array","items":{"$ref":"#/components/schemas/MaxFee"}},"events":{"type":"array","items":{"$ref":"#/components/schemas/IntentEvent"}},"configSig":{"$ref":"#/components/schemas/Signature"},"minValidations":{"type":"number","minimum":0}}},"OpType":{"type":"integer","enum":[0,1,2,3],"description":"Intent operation type:\n- `0` — Swap\n- `1` — Transfer\n- `2` — EvmCall\n- `3` — SvmCall\n"},"Address":{"type":"string","description":"A valid EVM (0x-prefixed hex) address."},"BigInteger":{"type":"string","description":"A non-negative integer represented as a decimal string."},"MaxFee":{"type":"object","required":["token","amount"],"properties":{"token":{"$ref":"#/components/schemas/Address"},"amount":{"$ref":"#/components/schemas/BigInteger"}}},"IntentEvent":{"type":"object","required":["topic","data"],"properties":{"topic":{"$ref":"#/components/schemas/HexString"},"data":{"$ref":"#/components/schemas/HexString"}}},"ExecutionFee":{"type":"object","required":["trigger","relayer","oracles","validators","intents","protocol","total"],"properties":{"trigger":{"$ref":"#/components/schemas/BigInteger"},"relayer":{"$ref":"#/components/schemas/BigInteger"},"oracles":{"$ref":"#/components/schemas/BigInteger"},"validators":{"$ref":"#/components/schemas/BigInteger"},"intents":{"$ref":"#/components/schemas/BigInteger"},"protocol":{"$ref":"#/components/schemas/BigInteger"},"total":{"$ref":"#/components/schemas/BigInteger"}}},"SolverFee":{"type":"object","required":["address","amount"],"properties":{"address":{"$ref":"#/components/schemas/Address"},"amount":{"$ref":"#/components/schemas/BigInteger"}}},"ExecutionValidation":{"type":"object","required":["signature","succeeded"],"properties":{"signature":{"$ref":"#/components/schemas/Signature"},"succeeded":{"type":"boolean"},"description":{"type":"string"}}}},"parameters":{"OffsetParam":{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0}},"LimitParam":{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":10}},"SortParam":{"name":"sort","in":"query","description":"Sort order: `1` for ascending, `-1` for descending","schema":{"type":"integer","enum":[1,-1],"default":-1}}}}}
```

## GET /executions/{hash}

> Get an execution by hash

```json
{"openapi":"3.0.3","info":{"title":"Mimic Protocol API","version":"1.0.1"},"tags":[{"name":"Executions","description":"Trigger execution records"}],"servers":[{"url":"https://api-protocol.mimic.fi"}],"paths":{"/executions/{hash}":{"get":{"summary":"Get an execution by hash","operationId":"getExecution","tags":["Executions"],"parameters":[{"name":"hash","in":"path","required":true,"schema":{"$ref":"#/components/schemas/HexString"}}],"responses":{"200":{"description":"Execution details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecutionResponse"}}}},"404":{"$ref":"#/components/responses/NotFound"}}}}},"components":{"schemas":{"HexString":{"type":"string","description":"An arbitrary 0x-prefixed hex string."},"ExecutionResponse":{"description":"An execution record with relayer, status, fee, and validation details","allOf":[{"$ref":"#/components/schemas/ExecutionCreateRequest"},{"type":"object","required":["relayer","status","createdAt"],"properties":{"relayer":{"$ref":"#/components/schemas/Address"},"status":{"type":"string","enum":["pending","valid","invalid"]},"createdAt":{"type":"string","format":"date-time"},"logs":{"type":"array","items":{"type":"string"}},"fee":{"$ref":"#/components/schemas/ExecutionFee"},"solverFees":{"type":"array","items":{"$ref":"#/components/schemas/SolverFee"}},"validations":{"type":"array","items":{"$ref":"#/components/schemas/ExecutionValidation"}}}}]},"ExecutionCreateRequest":{"type":"object","required":["triggerSig","triggerType","triggerData","hash","timestamp","fuelUsed","logs","inputs","outputs","signature","result"],"properties":{"triggerSig":{"$ref":"#/components/schemas/Signature"},"triggerType":{"$ref":"#/components/schemas/TriggerType"},"triggerData":{"allOf":[{"$ref":"#/components/schemas/HexString"}],"description":"ABI-encoded trigger-specific execution data"},"hash":{"$ref":"#/components/schemas/HexString"},"timestamp":{"$ref":"#/components/schemas/Timestamp"},"fuelUsed":{"type":"integer","minimum":0},"logs":{"type":"array","items":{"type":"string"}},"inputs":{"type":"array","items":{"$ref":"#/components/schemas/OracleResponse"}},"outputs":{"type":"array","items":{"$ref":"#/components/schemas/ExecutionIntent"}},"signature":{"allOf":[{"$ref":"#/components/schemas/Signature"}],"description":"Relayer signature over the execution"},"result":{"type":"string","enum":["succeeded","failed"]}}},"Signature":{"type":"string","description":"A 65-byte hex-encoded ECDSA signature (130 hex chars + 0x prefix)."},"TriggerType":{"type":"integer","enum":[0,1,2],"description":"Trigger execution mode:\n- `0` — Cron: fires on a recurring cron schedule\n- `1` — Event: fires on an on-chain event\n- `2` — Once: fires exactly once at a specific time\n"},"Timestamp":{"type":"integer","description":"Unix timestamp in milliseconds."},"OracleResponse":{"type":"object","description":"An oracle-signed query response. The shape of `query.params` and `result.value` depends on `query.name` (TokenPriceQuery, EvmCallQuery, SvmAccountsInfoQuery, RelevantTokensQuery, SubgraphQuery).\n","required":["signature","query","result"],"properties":{"signature":{"$ref":"#/components/schemas/Signature"},"query":{"type":"object","required":["name","hash","params"],"properties":{"name":{"type":"string","enum":["TokenPriceQuery","EvmCallQuery","SvmAccountsInfoQuery","RelevantTokensQuery","SubgraphQuery"]},"hash":{"$ref":"#/components/schemas/HexString"},"params":{"type":"object","additionalProperties":true}}},"result":{"type":"object","required":["value"],"properties":{"value":{}}}}},"ExecutionIntent":{"description":"An intent output produced by an execution","allOf":[{"$ref":"#/components/schemas/Intent"},{"type":"object","required":["hash"],"properties":{"hash":{"$ref":"#/components/schemas/HexString"}}}]},"Intent":{"type":"object","required":["op","user","settler","nonce","deadline","data","maxFees","events","configSig","minValidations"],"properties":{"op":{"$ref":"#/components/schemas/OpType"},"user":{"$ref":"#/components/schemas/Address"},"settler":{"allOf":[{"$ref":"#/components/schemas/Address"}],"description":"Address of the settler contract that will settle this intent"},"nonce":{"$ref":"#/components/schemas/HexString"},"deadline":{"allOf":[{"$ref":"#/components/schemas/BigInteger"}],"description":"Unix epoch in seconds after which the intent expires"},"data":{"allOf":[{"$ref":"#/components/schemas/HexString"}],"description":"ABI-encoded operation-specific data"},"maxFees":{"type":"array","items":{"$ref":"#/components/schemas/MaxFee"}},"events":{"type":"array","items":{"$ref":"#/components/schemas/IntentEvent"}},"configSig":{"$ref":"#/components/schemas/Signature"},"minValidations":{"type":"number","minimum":0}}},"OpType":{"type":"integer","enum":[0,1,2,3],"description":"Intent operation type:\n- `0` — Swap\n- `1` — Transfer\n- `2` — EvmCall\n- `3` — SvmCall\n"},"Address":{"type":"string","description":"A valid EVM (0x-prefixed hex) address."},"BigInteger":{"type":"string","description":"A non-negative integer represented as a decimal string."},"MaxFee":{"type":"object","required":["token","amount"],"properties":{"token":{"$ref":"#/components/schemas/Address"},"amount":{"$ref":"#/components/schemas/BigInteger"}}},"IntentEvent":{"type":"object","required":["topic","data"],"properties":{"topic":{"$ref":"#/components/schemas/HexString"},"data":{"$ref":"#/components/schemas/HexString"}}},"ExecutionFee":{"type":"object","required":["trigger","relayer","oracles","validators","intents","protocol","total"],"properties":{"trigger":{"$ref":"#/components/schemas/BigInteger"},"relayer":{"$ref":"#/components/schemas/BigInteger"},"oracles":{"$ref":"#/components/schemas/BigInteger"},"validators":{"$ref":"#/components/schemas/BigInteger"},"intents":{"$ref":"#/components/schemas/BigInteger"},"protocol":{"$ref":"#/components/schemas/BigInteger"},"total":{"$ref":"#/components/schemas/BigInteger"}}},"SolverFee":{"type":"object","required":["address","amount"],"properties":{"address":{"$ref":"#/components/schemas/Address"},"amount":{"$ref":"#/components/schemas/BigInteger"}}},"ExecutionValidation":{"type":"object","required":["signature","succeeded"],"properties":{"signature":{"$ref":"#/components/schemas/Signature"},"succeeded":{"type":"boolean"},"description":{"type":"string"}}},"Error":{"type":"object","properties":{"message":{"type":"string"}}}},"responses":{"NotFound":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}
```


# Tests

The Mimic Protocol Test Library (`@mimicprotocol/test-ts`) provides tools for simulating function execution to validate expected function behavior under different scenarios.

***

### 1. Getting Started

#### 1.1. Basic test structure

Every test follows this structure:

```tsx
import { runFunction /* types */ } from "@mimicprotocol/test-ts";

describe("Function", () => {
  // 1. Define context, inputs, mocks
  const functionDir = "./build";
  const context = {
    /* required fields */
  };
  const inputs = {
    /* manifest inputs */
  };

  it("produces the expected intents", async () => {
    // 2. Execute the function
    const result = await runFunction(functionDir, context, {
      inputs /* needed mocks */,
    });

    // 3. Check the function outputs
    expect(result.success).to.be.true;
    expect(result.intents).to.have.lengthOf(N);
  });
});
```

#### 1.2. Project setup

Create a basic function project:

```bash
# Initialize a new Mimic project
npx @mimicprotocol/cli init my-automation-function && cd my-automation-function

# Test your function
yarn mimic test
```

***

### 2. Function Runner Reference

This section describes the parameters and outputs of the `runFunction` function.

#### 2.1. Parameters

**2.1.1. Function directory**

The directory where the compiled function `.wasm` is located.

```tsx
const functionDir = "./build";
```

**2.1.2. Context**

The context includes the fields needed during function execution.

```tsx
import { Context } from "@mimicprotocol/test-ts";

const context: Context = {
  user: "0xAddress",
  settlers: [{ address: "0xAddress", chainId: 10 }], // One per chain used in the function
  timestamp: Date.now(), // number (in milliseconds)
};
```

**2.1.3. Inputs**

The values for the inputs defined in the manifest. For example, if the manifest declares:

```yaml
inputs:
  - chainId: uint32
  - token: address
  - amount: string
  - feeAmount: uint256
```

Then, the inputs may be:

```tsx
const inputs = {
  chainId: 10,
  token: "0xAddress",
  amount: "1.5", // 1.5 tokens
  feeAmount: "100000", // 0.1 tokens (6 decimals)
};
```

**2.1.4. Prices mock**

The responses for the price queries made in the function.

For example, if the function does:

```tsx
import { environment } from "@mimicprotocol/lib-ts";

const price = environment.tokenPriceQuery(dai).unwrap();
// or
const amountInUsd = amountInDai.toUsd().unwrap();
// or
const wethAmount = usdcAmount.toTokenAmount(weth).unwrap();
```

Then, the prices mock may be:

```tsx
import { TokenPriceQueryMock } from "@mimicprotocol/test-ts";
import { fp } from "@mimicprotocol/sdk";

const prices: TokenPriceQueryMock[] = [
  // Mock for `tokenPriceQuery` and `toUsd`
  {
    request: { token: "0xDAI", chainId: 10 },
    response: [fp(1).toString()], // 1 DAI = 1 USD
  },
  // Mocks for `toTokenAmount`
  {
    request: { token: "0xUSDC", chainId: 10 },
    response: [fp(0.99).toString()], // 1 USDC = 0.99 USD
  },
  {
    request: { token: "0xWETH", chainId: 10 },
    response: [fp(4200).toString()], // 1 WETH = 4200 USD
  },
];
```

**2.1.5. Relevant tokens mock**

The responses for the relevant tokens queries made in the function.

For example, if the function does:

```tsx
import { ChainId, environment } from "@mimicprotocol/lib-ts";

const userTokens = environment
  .relevantTokensQuery(
    context.user,
    [ChainId.OPTIMISM],
    USD.zero(),
    [USDC, USDT],
    ListType.AllowList,
  )
  .unwrap();
```

Then, the relevant tokens mock may be:

```tsx
import { RelevantTokensQueryMock } from "@mimicprotocol/test-ts";

const relevantTokens: RelevantTokensQueryMock[] = [
  {
    request: {
      owner: "0xAddress",
      chainIds: [10],
      usdMinAmount: "0",
      tokenFilter: 0, // AllowList = 0, DenyList = 1
      tokens: [
        { address: "0xUSDC", chainId: 10 },
        { address: "0xUSDT", chainId: 10 },
      ],
    },
    response: [
      {
        timestamp: context.timestamp,
        balances: [
          { token: { address: "0xUSDC", chainId: 10 }, balance: "10000000" }, // 10 USDC
          { token: { address: "0xUSDT", chainId: 10 }, balance: "10000" }, // 0.01 USDT
        ],
      },
    ],
  },
];
```

**2.1.6. Contract calls mock**

The responses for the contract calls made in the function. Only for read functions, i.e., those that are not intended to generate intents.\
Note: Token `decimals` and `symbol` are sometimes queried behind the scenes and need mocks in those cases.

For example, if the function does:

```tsx
// `TokenAmount#fromStringDecimal` calls `decimals`
const tokenAmount = TokenAmount.fromStringDecimal(USDC, "10.5");

// `TokenAmount#toString` calls `symbol`
log.info(`Transfer amount: ${tokenAmount}`);

// `balanceOf` needs a mock
const tokenContract = new ERC20(USDC, ChainId.OPTIMISM);
const balance = tokenContract.balanceOf(recipient).unwrap();

// `mint` does not need a mock
tokenContract.mint(recipient, amount).build().send();
```

Then, the calls mock may be:

```tsx
import { EvmCallQueryMock } from "@mimicprotocol/test-ts";
import { Interface } from "ethers";

import ERC20Abi from "../abis/ERC20.json";

const ERC20Interface = new Interface(ERC20Abi);

const calls: EvmCallQueryMock[] = [
  {
    request: {
      chainId: 10,
      to: "0xUSDC",
      fnSelector: ERC20Interface.getFunction("decimals").selector,
    },
    response: { value: "6", abiType: "uint8" },
  },
  {
    request: {
      chainId: 10,
      to: "0xUSDC",
      fnSelector: ERC20Interface.getFunction("symbol").selector,
    },
    response: { value: "USDC", abiType: "string" },
  },
  {
    request: {
      chainId: 10,
      to: "0xUSDC",
      fnSelector: ERC20Interface.getFunction("balanceOf").selector,
      params: [{ value: "0xAddress", abiType: "address" }],
    },
    response: { value: "10000000", abiType: "uint256" }, // 10 USDC
  },
];
```

**2.1.7. Subgraph queries mock**

The responses for the subgraph queries made in the function.

For example, if the function does:

```tsx
import { ChainId, environment } from "@mimicprotocol/lib-ts";

const response = environment
  .subgraphQuery(
    ChainId.OPTIMISM,
    "QmSubgraphId",
    "{ tokens { symbol holders } }",
  )
  .unwrap();
```

Then, the subgraph queries mock may be:

```tsx
import { SubgraphQueryMock } from "@mimicprotocol/test-ts";

const subgraphQueries: SubgraphQueryMock[] = [
  {
    request: {
      timestamp: context.timestamp,
      chainId: 10,
      subgraphId: "QmSubgraphId",
      query: "{ tokens { id symbol } }",
    },
    response: {
      blockNumber: 1,
      data: '{ "tokens": [{ "symbol": "WETH", "holders": "1857" }] }',
    },
  },
];
```

#### 2.2. Output

The `runFunction` function returns an object containing the following fields:

* `success` - Boolean. True if the execution ended properly, or false if it had an error.
* `timestamp` - Number. Execution timestamp in milliseconds.
* `fuelUsed` - Number. Amount of fuel used during the execution.
* `intents` - Array of intents produced by the execution.
* `logs` - Array of logs produced by the execution. It may include error logs.

**2.2.1. Intents**

Each intent in `result.intents` contains intent-level metadata (`settler`, `feePayer`, `maxFees`) and an `operations` array. The shape of each operation depends on its type.

**Transfer**

If the function creates a transfer intent:

```typescript
const USDC = ERC20Token.fromString("0xUSDC", ChainId.OPTIMISM);
const recipient = Address.fromString("0xRecipient");
const amount = BigInt.fromStringDecimal("1", USDC.decimals);
const maxFee = TokenAmount.fromStringDecimal(USDC, "0.1");

TransferBuilder.forChain(ChainId.OPTIMISM)
  .addTransferFromTokenAmount(TokenAmount.fromBigInt(USDC, amount), recipient)
  .build()
  .send(maxFee);
```

Then, the test should be:

```typescript
import { Chains, OpType } from "@mimicprotocol/sdk";
import { runFunction, TransferOperation } from "@mimicprotocol/test-ts";

it("produces the expected intent", async () => {
  const result = await runFunction(/* parameters */);
  expect(result.success).to.be.true;

  expect(result.intents).to.have.lengthOf(1);
  const intent = result.intents[0];
  const op = intent.operations[0] as TransferOperation;

  expect(op.opType).to.be.equal(OpType.Transfer);
  expect(intent.settler).to.be.equal(context.settlers[0].address);
  expect(op.user).to.be.equal(context.user);
  expect(op.chainId).to.be.equal(Chains.Optimism);

  expect(op.transfers).to.have.lengthOf(1);
  expect(op.transfers[0].token).to.be.equal("0xUSDC");
  expect(op.transfers[0].amount).to.be.equal("1000000"); // 1 USDC
  expect(op.transfers[0].recipient).to.be.equal("0xRecipient");

  expect(intent.feePayer).to.be.equal(context.user);
  expect(intent.maxFees).to.have.lengthOf(1);
  expect(intent.maxFees[0].token).to.be.equal("0xUSDC");
  expect(intent.maxFees[0].amount).to.be.equal("100000"); // 0.1 USDC
});
```

**Swap**

If the function creates a swap intent:

```typescript
const USDC = ERC20Token.fromString("0xUSDC", ChainId.OPTIMISM);
const amountIn = BigInt.fromStringDecimal("1", USDC.decimals);

const WETH = ERC20Token.fromString("0xWETH", ChainId.OPTIMISM);
const minAmountOut = BigInt.fromStringDecimal("0.001", WETH.decimals);

const recipient = environment.getContext().user;

SwapBuilder.forChains(ChainId.OPTIMISM, ChainId.OPTIMISM)
  .addTokenInFromTokenAmount(TokenAmount.fromBigInt(USDC, amountIn))
  .addTokenOutFromTokenAmount(
    TokenAmount.fromBigInt(WETH, minAmountOut),
    recipient,
  )
  .build()
  .send();
```

Then, the test should be:

```typescript
import { Chains, OpType } from "@mimicprotocol/sdk";
import { runFunction, SwapOperation } from "@mimicprotocol/test-ts";

it("produces the expected intent", async () => {
  const result = await runFunction(/* parameters */);
  expect(result.success).to.be.true;

  expect(result.intents).to.have.lengthOf(1);
  const intent = result.intents[0];
  const op = intent.operations[0] as SwapOperation;

  expect(op.opType).to.be.equal(OpType.Swap);
  expect(intent.settler).to.be.equal(context.settlers[0].address);
  expect(op.user).to.be.equal(context.user);
  expect(op.sourceChain).to.be.equal(Chains.Optimism);
  expect(op.destinationChain).to.be.equal(Chains.Optimism);

  expect(op.tokensIn).to.have.lengthOf(1);
  expect(op.tokensIn[0].token).to.be.equal("0xUSDC");
  expect(op.tokensIn[0].amount).to.be.equal("1000000"); // 1 USDC

  expect(op.tokensOut).to.have.lengthOf(1);
  expect(op.tokensOut[0].token).to.be.equal("0xWETH");
  expect(op.tokensOut[0].minAmount).to.be.equal("1" + "0".repeat(15)); // 0.001 WETH
  expect(op.tokensOut[0].recipient).to.be.equal(context.user);

  expect(intent.feePayer).to.be.equal(context.user);
  expect(intent.maxFees).to.have.lengthOf(0);
});
```

**Call**

If the function creates a call intent:

```typescript
const USDC = ERC20Token.fromString("0xUSDC", ChainId.OPTIMISM);
const amount = BigInt.fromStringDecimal("1", USDC.decimals);
const maxFee = TokenAmount.fromStringDecimal(USDC, "0.1");
const data = ERC20Utils.encodeApprove(spender, amount);

EvmCallBuilder.forChain(ChainId.OPTIMISM)
  .addCall(USDC, data)
  .addUser(smartAccount)
  .build()
  .send(maxFee);
```

Then, the test should be:

```typescript
import { Chains, OpType } from "@mimicprotocol/sdk";
import { EvmCallOperation, runFunction } from "@mimicprotocol/test-ts";
import { Interface } from "ethers";

import ERC20Abi from "../abis/ERC20.json";

const ERC20Interface = new Interface(ERC20Abi);

it("produces the expected intent", async () => {
  const result = await runFunction(/* parameters */);
  expect(result.success).to.be.true;

  expect(result.intents).to.have.lengthOf(1);
  const intent = result.intents[0];
  const op = intent.operations[0] as EvmCallOperation;

  expect(op.opType).to.be.equal(OpType.EvmCall);
  expect(intent.settler).to.be.equal(context.settlers[0].address);
  expect(op.user).to.be.equal("0xSmartAccount");
  expect(op.chainId).to.be.equal(Chains.Optimism);

  expect(op.calls).to.have.lengthOf(1);
  expect(op.calls[0].target).to.be.equal(USDC);
  expect(op.calls[0].value).to.be.equal("0");
  const data = ERC20Interface.encodeFunctionData("approve", [
    "0xSpender",
    "1000000",
  ]);
  expect(op.calls[0].data).to.be.equal(data);

  expect(intent.feePayer).to.be.equal(context.user);
  expect(intent.maxFees).to.have.lengthOf(1);
  expect(intent.maxFees[0].token).to.be.equal("0xUSDC");
  expect(intent.maxFees[0].amount).to.be.equal("100000"); // 0.1 USDC
});
```

**2.2.2. Logs**

For example, if the function does:

```typescript
import { log } from "@mimicprotocol/lib-ts";

if (inputs.token == USDC) log.info("Function started");
else throw new Error("Token not supported");
```

Then, the test should be:

```typescript
import { runFunction } from "@mimicprotocol/test-ts";

describe("when the token is USDC", () => {
  it("executes properly", async () => {
    const result = await runFunction(/* 0xUSDC */);
    expect(result.success).to.be.true;

    expect(result.logs).to.have.lengthOf(1);
    expect(result.logs[0]).to.include("Function started");
  });
});

describe("when the token is not USDC", () => {
  it("throws an error", async () => {
    const result = await runFunction(/* 0xWETH */);
    expect(result.success).to.be.false;

    expect(result.logs).to.have.lengthOf(1);
    expect(result.logs[0]).to.include("Token not supported");
  });
});
```


# Fees

## Execution Fees

When you execute a function in Mimic, several automated services work behind the scenes — fetching data, validating results, and submitting transactions. Each of these steps has a small cost, combined into what we call the **execution fee**.

All fees are settled **off-chain** using Mimic USD Credits, our internal payment system. It can funded anytime with any token from any supported chain.

The exact composition of the total charge for your execution includes:

<table><thead><tr><th width="123.9296875">Concept</th><th width="424.234375">Description</th><th>Formula</th></tr></thead><tbody><tr><td><strong>Trigger</strong></td><td>Cost of initiating the execution. Cron-based executions pay a small fixed trigger fee; event-based triggers can vary depending on on-chain monitoring.</td><td><p>Cron: 0.00004</p><p>Event: 0.1</p></td></tr><tr><td><strong>Relayers</strong></td><td>The relayer runs the off-chain function, executes its logic, and confirms the resulting output (intents). Each function is compiled to WASM and executed deterministically by relayers. To ensure fairness Mimic tracks the amount of fuel used during the execution — similar to how <strong>gas</strong> works on Ethereum.</td><td><p>Base: 0.00004</p><p>Fuel: 0.7257 Gwei × unit</p></td></tr><tr><td><strong>Oracles</strong></td><td>When the execution needs off-chain data, Mimic’s oracle network provides it. Each data query (e.g., price, subgraph, token list) adds a small cost.</td><td><p>RPC: 0.00000235</p><p>Price: 0.0004</p><p>Tokens: 0.012</p><p>Subgraph: 0.00004235</p></td></tr><tr><td><strong>Validators</strong></td><td>Validators verify that the execution results are correct and compliant. Each signature in the validation process incurs a small fee.</td><td><p>Base: 0.00004235</p><p>Fuel: 0.7257 Gwei × unit</p></td></tr><tr><td><strong>Intents</strong></td><td>If your execution produces multiple output intents (transfers, swaps, or calls), each one adds a minimal per-intent fee.</td><td>Per intent: 0.000801</td></tr><tr><td><strong>Protocol</strong></td><td>A small percentage of the subtotal is added as a protocol fee, which supports the maintenance and operation of Mimic Protocol.</td><td>0%</td></tr></tbody></table>

## Solver Fees

In addition to the execution fee, solver fees apply when an intent must be fulfilled by an external solver.

Developers can specify how these are paid when creating an intent, through the intent's `maxFee` property on their function code. Solver fees are separate from execution fees and are negotiated between the protocol and the solver fulfilling the intent.

If preferred, solvers can also be paid using Mimic USD Credits, letting you cover both execution and solver costs from the same off-chain balance. Below is a simplified example showing how to pay solver fees directly with credits:

```ts
import { DenominationToken, TokenAmount, TransferBuilder } from '@mimicprotocol/lib-ts'

export default function main(): void {
  const builder = TransferBuilder.forChain(1) // Ethereum mainnet

  // Add any transfers your function requires here...

  // Set the solver's maximum fee, paid in Mimic Credits (denominated in USD)
  // Pay up to 0.5 USD worth of credits
  const fee = TokenAmount.fromStringDecimal(DenominationToken.USD(), '0.5')
  builder
    .build()
    .send(fee)
}
```

This tells the protocol that the solver can be compensated with up to 0.5 USD worth of Mimic Credits. The credits are automatically deducted from your balance when the solver fulfills the intent.

## FAQs

**Q: Do I need to hold tokens to pay these fees?**\
No. All payments are off-chain using Mimic Credits. You can fund credits from any token or chain at any time.

**Q: Can solver fees exceed the execution fee?**\
Yes — solver fees are independent, and their amount depends on the complexity or competitiveness of the intent.

**Q: Are protocol fees always 0%?**\
Currently yes, but this may change as the network scales.


# Supported Chains

{% hint style="warning" %}
The current version of Mimic Protocol is an alpha release being tested. Please note this version has **not been audited yet**.

*The protocol is likely to change moving forward.*
{% endhint %}

At this stage, Mimic Protocol is integrated with the following networks:

* **Ethereum**
* **Arbitrum**
* **Base**
* **Base Sepolia**
* **Sonic**
* **Optimism**
* **Gnosis Chain**
* **Polygon**
* **BNB Binance Smart chain**
* **Avalanche**

These are the only networks currently supported for interaction with the protocol.

The addresses for the deployed contracts can be found here:

{% embed url="<https://github.com/mimic-protocol/contracts/tree/main/packages/evm/ignition/deployments>" %}


# Troubleshooting

## Deployment

#### **I deployed a function, but the template doesn't appear on the explorer UI**

Check that you are connected with the wallet associated with the API key used to deploy the function.

***

## Execution

#### **My function should have executed, but I don’t see any execution on the explorer UI**

First, make sure you haven’t run out of credits.

If you have enough credits, review your function code as there might be an error in it. To verify that your function works as expected, test it under different scenarios using the [Mimic Protocol test library](/developers/tests).

#### **My function execution failed or didn’t produce the expected outputs**

If you’re using a smart account, ensure that the signer of the function configuration is the owner of that smart account.

If your function queries expect responses that are too large, or if the function produces too many intents, try batching them.

#### **My function execution succeeded and produced the expected outputs, but they were discarded**

There can be multiple reasons for this:

1. Check that the intent amount is the expected one, and ensure the user has enough balance.
2. If the user is an EOA, ensure the settler has sufficient token allowance.
3. If the user is a smart account, ensure the settler set in the smart account is the correct one.
4. Check that the smart contract addresses used in the function are correct for the current chain.
5. Try increasing the maximum fee. If the intent is a swap, try decreasing the expected minimum amount out.
6. If the intent is a call, the target contract might be reverting. Simulate the smart contract call using the target, data, and value shown in the intent detail on the explorer UI. You can use tools like [Tenderly](https://dashboard.tenderly.co/) to run the simulation.

{% hint style="info" %}
If you haven't found what you needed, you can contact us [here](/resources/contact).
{% endhint %}


# Whitepaper

To explore the Mimic Protocol whitepaper and gain a deeper understanding of how it works, click the link below:

{% file src="/files/NKFM8lqcWv8G3f45kVBI" %}


# Glossary

## User

The entity that defines and submits functions to the network. A user specifies the function logic, required input data, and execution trigger. Users are the primary initiators of network activity and are responsible for setting up functions securely.

## Function

A function is the fundamental unit of execution defined by a user within the protocol. Each function consists of three components:

1. **Inputs:** Data required for execution, typically fetched from oracles. Inputs are validated by relayers using cryptographic signatures provided by oracles.
2. **Logic:** A deterministic function specified by the user that processes the inputs and evaluates conditions to decide whether an intent should be generated.
3. **Trigger:** A configuration defining when the function should be executed (e.g., based on time intervals, specific events, or user-defined conditions).

Functions act as the bridge between Relayers, who execute the function logic, Oracles, who provide the necessary inputs, and a central coordinator called Axia in charge of receiving the generated intents if the function conditions are met. By combining these components, functions enable automation and precise evaluation of user-defined criteria within the protocol.

## Registry

The Registry is the on-chain component of Mimic Protocol responsible for storing, managing, and validating all registered functions and their associated triggers. By anchoring these details on-chain, the Registry guarantees transparency, immutability, and trustless coordination between users and relayers.

## **Intents**

An intent is a structured request that specifies one or more **operations** to be executed, subject to predefined conditions and constraints cryptographically signed. Intents serve as the core units of work within the protocol, enabling decentralized systems to process, validate, and execute user-defined operations.

An intent carries intent-level metadata (settler address, fee payer, max fees, deadline, nonce) that applies to all its operations. Each operation within the intent specifies what action to perform (swap, transfer, or call) and who the user is for that action. Grouping multiple operations into one intent lets them be settled atomically in a single on-chain transaction.

## Relayers

Relayers are decentralized network participants responsible for executing functions on behalf of users. They fetch oracle-signed data, evaluate the function logic deterministically, and submit proofs of execution to the protocol. Relayers ensure that functions are executed faithfully, adhering to the user-defined conditions and inputs.

Relayers are incentivized through rewards for valid executions and are penalized for invalid or malicious activity. They play a crucial role in maintaining the integrity and reliability of the network.

## Oracles

Oracles are decentralized data providers responsible for supplying accurate, cryptographically signed inputs required for function execution. Oracles respond to queries from relayers with verified data, including values, timestamps, and cryptographic proofs. This ensures that all function executions are based on trusted and reproducible inputs.

Oracles are rewarded for providing valid responses within the expected range and are penalized for outliers or inconsistent data. They serve as the backbone of the protocol’s data integrity, enabling deterministic function execution.

## Validators

Validators are independent agents responsible for verifying the correctness and determinism of relayer function executions. When a relayer submits an execution of a function — including the inputs and outputs — validators check that this execution complies with the deterministic behavior specified by the function trigger.

Validators essentially act as impartial referees, ensuring that relayer executions cannot be manipulated or produce inconsistent results. Their signature or attestation may be required before the function is finalized on-chain, providing a layer of trust and integrity for automation workflows.

## **Axia**

Axia is the central coordinator within the protocol responsible for managing the lifecycle of intents execution. It validates intents, broadcasts them to eligible solvers, evaluates solver proposals, and ensures robust execution by prioritizing the best proposals. Axia also tracks solver performance and enforces penalties or rewards to maintain reliability and efficiency in the system.

## **Solvers**

Solvers are entities that compete to fulfill intents. They respond to intent broadcasts with proposals detailing execution parameters, including fees, output amounts, and estimated completion times. Solvers are evaluated based on reputation, execution fees, and timeliness. Reliable solvers are rewarded, while those that fail to execute valid proposals are penalized.

## Safeguards

Safeguards are cryptographically signed constraints defined by the user to impose strict controls over the behavior and execution of an intent. Safeguards ensure that intents are executed within specific, user-defined boundaries, preventing misuse, unauthorized actions, or undesired outcomes.

## Settler

The Settler is the protocol component responsible for executing validated intents on-chain, ensuring that user-defined safeguards are respected and finalizing the outcome based on the winning proposal selected through the solvers network. It acts as the final step in the lifecycle of an intent, transforming it from a validated request into a concrete action.


# Security

Please be aware that Mimic Protocol is currently **experimental**. While we are committed to ensuring its security and reliability, it may still contain vulnerabilities or unforeseen issues.

{% hint style="warning" %}
If you discover any security vulnerabilities or have concerns regarding the security of our protocol, we encourage you to report them promptly. Please contact us at <security@mimic.fi>.
{% endhint %}

We appreciate your assistance in helping us maintain and improve the security of our platform.


# Press kit

## Main Logo

This is the primary visual representation of Mimic.

The Mimic symbol takes inspiration from the octopus silhouette, depicting a head and tentacles. The knot-style of shape also resembles a blockchain node.

{% tabs %}
{% tab title="Main V+W" %}

<figure><img src="https://216358192-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F2K6E4Us9xYRIC0Tt0SIZ%2Fuploads%2FBa9E9vhjvIR90DIO8KJj%2FWhite.png?alt=media&amp;token=89c83aaa-78e2-4848-92c0-524d07e6c111" alt=""><figcaption></figcaption></figure>
{% endtab %}

{% tab title="Main V+V" %}

<figure><img src="https://216358192-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F2K6E4Us9xYRIC0Tt0SIZ%2Fuploads%2FXxgSiLVmW9nJeDahUhaH%2FPurple.png?alt=media&amp;token=493bbf99-3936-4039-840b-290004503d94" alt=""><figcaption></figcaption></figure>
{% endtab %}

{% tab title="Main V+G" %}

<figure><img src="https://216358192-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F2K6E4Us9xYRIC0Tt0SIZ%2Fuploads%2FLoe47BUQV5WGTBNe5eht%2FLogo.png?alt=media&amp;token=df5ac8f3-2b78-45ca-9da4-9a4a4b18b52d" alt=""><figcaption></figcaption></figure>
{% endtab %}

{% tab title="Main V+W" %}

<figure><img src="https://216358192-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F2K6E4Us9xYRIC0Tt0SIZ%2Fuploads%2FPGIOWlDWFqswTlOQXUgw%2FSnow%20White.png?alt=media&amp;token=b6b11b93-729b-4e27-bc85-489bef70bc8a" alt=""><figcaption></figcaption></figure>
{% endtab %}
{% endtabs %}

## Mark Logo

The mark logo can be used as a standalone representation of the Mimic brand. It’s designed to serve as a simplified visual identifier. This logo also serves as our main icon and favicon.

The violet mark logo is used as primary across Mimic placements. The B\&W version is used when the accent should be spotlighted in light and dark mode.

{% tabs %}
{% tab title="Mark V" %}

<figure><img src="https://216358192-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F2K6E4Us9xYRIC0Tt0SIZ%2Fuploads%2FO6Ip4fMibCVpop07BrR8%2FLogo%20copy.png?alt=media&amp;token=35ebfeae-9fde-42d6-bc00-8afebf3e3361" alt=""><figcaption></figcaption></figure>
{% endtab %}
{% endtabs %}

## Text Logo

The typographic logo is a standalone representation of the brand.

{% tabs %}
{% tab title="Text V" %}

<figure><img src="https://216358192-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F2K6E4Us9xYRIC0Tt0SIZ%2Fuploads%2FkE94c70RnWsX10zR0wbU%2FPurple%20copy.png?alt=media&amp;token=824be8bf-7354-41c8-9503-39be1af08a84" alt=""><figcaption></figcaption></figure>
{% endtab %}

{% tab title="Text W" %}

<figure><img src="https://216358192-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F2K6E4Us9xYRIC0Tt0SIZ%2Fuploads%2FwaXjPlW9hK3dzCFPIQze%2FWhite%20copy%202.png?alt=media&amp;token=00a502ce-8418-4ac6-8c9d-a264d182e567" alt=""><figcaption></figcaption></figure>
{% endtab %}

{% tab title="Text B" %}

<figure><img src="https://216358192-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F2K6E4Us9xYRIC0Tt0SIZ%2Fuploads%2F8e5GHKSGO76UwNWyL935%2FLogo%20copy%202.png?alt=media&amp;token=9a5b585e-7aaf-4a5c-9769-4e864429de57" alt=""><figcaption></figcaption></figure>
{% endtab %}

{% tab title="Text S" %}

<figure><img src="https://216358192-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F2K6E4Us9xYRIC0Tt0SIZ%2Fuploads%2FvrLQHLmXW4cZwu1uZ2Eo%2FSnow%20White%20copy.png?alt=media&amp;token=e7745c35-5242-40d3-8d09-db1dffc8cbe5" alt=""><figcaption></figcaption></figure>
{% endtab %}
{% endtabs %}


# Contact

If you have any concerns security-wise, please follow the steps described in the [security](/resources/security) section.

Otherwise, you can find below the different places where you can contact us, feel free to use the one that suits you better :)

* [Twitter](https://twitter.com/mimicfi)
* [Github](https://github.com/mimic-protocol)
* [Discord](https://discord.mimic.fi)
* [Website](https://mimic.fi/)
* [Telegram](https://t.me/+cBCtvvZuGpplNmY8)


