Typed wrappers from Solidity ABIs
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 responsesA
ContractNameUtils
helper class: staticencodeX
/decodeX
helpers per functionTuple classes for
tuple
/struct
params and returnsEvent classes
<EventName>Event
with a staticdecode(topics, data)
The generated code targets @mimicprotocol/lib-ts
primitives and utilities: Address
, BigInt
, Bytes
, environment
, evm
, EvmEncodeParam
, EvmDecodeParam
, CallBuilder
.
1. When it runs
mimic codegen
readsmanifest.yaml
inputs
→src/types/index.ts
abis
→src/types/<ContractName>.ts
Example manifest excerpt:
abis:
ERC20: './abis/IERC20.json'
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.contractCall
; write methods return aCallBuilder
and never call the environment directly.
Additionally, export class <ContractName>Utils
exposes encode<Fn>
and decode<Fn>
helpers used by the main class.
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>
}
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 widthsArrays 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. 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
.
5. Read calls
Read methods perform: encode → environment.contractCall
→ decode.
// ABI: function balanceOf(address owner) view returns (uint256)
const erc20 = new ERC20(token, ChainId.ETHEREUM)
const balance: BigInt = erc20.balanceOf(Address.fromString('0x...'))
// Under the hood (simplified):
// const encoded = ERC20Utils.encodeBalanceOf(owner)
// const resp = environment.contractCall(this._address, this._chainId, this._timestamp, encoded.toHexString())
// return ERC20Utils.decodeBalanceOf(resp)
Void-returning reads just perform the call without decoding.
6. Write calls
Write methods return a CallBuilder
so you can compose multiple calls and send them via intents later.
// ABI: function approve(address spender, uint256 amount) nonpayable
const approve = erc20.approve(spender, amount) // CallBuilder
// approve.addMaxFee(...).build().send() // typical flow
Encoding converts primitives as needed:
// bool → Bytes.fromBool
// u8 → BigInt.fromU8, etc.
// tuples → EvmEncodeParam.fromValues('()', tuple.toEvmEncodeParams())
// arrays → nested EvmEncodeParam.fromValues with map
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 usedOtherwise 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 stringstoEvmEncodeParams(): EvmEncodeParam[]
for encoding
// Example return tuple
const info: UserInfo = erc20.getUserInfo()
// Example tuple param
const created = contract.createUser(new UserInfo(id, name, active)) // CallBuilder
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.
// ABI: function getHolders() view returns (address[])
const holders: Address[] = contract.getHolders()
// ABI: function batchTransfer(address[][] recipients, uint256[][] amounts)
const cb = contract.batchTransfer(addressMatrix, valueMatrix)
9. Events
For each event, <EventName>Event
is generated with a static decode(topics: string[], data: string)
.
// 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.
10. Imports and dependencies
Imports are automatically deduplicated and sorted based on what your ABI requires. Typical imports include:
import { Address, BigInt, Bytes, CallBuilder, ChainId, EvmDecodeParam, EvmEncodeParam, JSON, environment, evm } from '@mimicprotocol/lib-ts'
You do not need to manage these imports manually; they are generated with the file.
11. Example
Given this ABI excerpt:
[
{ "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:
const token = new ERC20(Address.fromString('0x...'), ChainId.ETHEREUM)
const bal = token.balanceOf(Address.fromString('0xuser')) // BigInt
const call = token.transfer(Address.fromString('0xrecipient'), BigInt.fromString('1000000000000000000')) // CallBuilder
// call.addMaxFee(...).build().send()
const decoded = TransferEvent.decode(topics, data)
12. Notes and limitations
Only
function
andevent
ABI items are processed; others are ignoredOverloads 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 typesGenerated files are meant to be committed; do not edit manually (they include a notice)
Last updated