# 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 %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.mimic.fi/developers/library.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
