Zapper

Zapper Studio let developers build adapters for tokenized holdings and contract positions

Zapper Studio let developers build DeFi adapters that translated tokenized holdings and contract-recorded positions into portfolio data. Its token fetchers described application tokens and their underlying assets, while contract position fetchers modeled claims a protocol recorded for an address. These integrations supplied balance data to the API and its consumers. The public development repository became read-only in January 2024, making its code a historical implementation reference for adapter development.

Last updated ·

Bottom line: Zapper Studio modeled wallet-held application tokens separately from contract-recorded positions, helping developers choose balance logic that matched each protocol’s accounting.

Token fetchers and contract position fetchers handled different holdings

The fetcher types separated a tokenized holding from a position whose accounting lived inside a protocol contract, giving developers different places to implement the relevant balance logic.

An application token combined familiar token properties with information about underlying assets. Its position object included supply and a price-per-share relationship. A contract position described the contract and its constituent tokens, including their roles within the position. That structure accommodated balances a protocol recorded without requiring every claim to appear as a separate token in the address’s wallet.


Position definitions gave balance reads their context

Position definitions established which contracts and tokens an integration recognized before its balance methods attached address-specific amounts. The templates kept those responsibilities separate, so an adapter could describe a supported position without confusing its definition with someone’s holdings. A contract position also carried the token definitions needed to interpret the values its balance method returned.

The shared contract shape included an application identifier, group identifier, network, and contract address. Those fields located a position within an integration rather than identifying it by its display name.

Underlying tokens connected share amounts to valuation

An application-token price came from the underlying token prices and the quantities each share represented in the archived base template. The field named pricePerShare described that relationship; it didn’t necessarily contain a dollar price. The template multiplied each underlying token’s price by its corresponding share quantity, then added the values to calculate the application-token price.

Token decimals mattered separately. Contract reads returned integer amounts, and the balance helper converted them into token units using each token’s decimals. It retained the raw balance string alongside the normalized amount and USD value. Underlying-token calculations also accounted for the decimals of the share token and each underlying token.


Contract positions preserved the meaning of each token balance

A contract-position adapter described what each constituent token meant within the protocol before it attached the address’s corresponding balance. The model distinguished supplied assets, borrowed assets, and claimable amounts, alongside other position roles.

Supplied assets and borrowed balances

The archived contract-position balance path treated tokens marked as borrowed as debt when calculating their USD contribution. That kept a liability’s direction separate from a supplied asset’s positive value. The position total then combined the retained token values.

Claimable amounts and token ordering

A claimable designation described a balance’s role in the position. It didn’t execute a claim or establish the protocol’s withdrawal conditions. The adapter still needed the balance method appropriate to the contract’s accounting.

The template matched returned balance amounts to the position’s token array by index. Developers had to preserve that relationship when defining tokens and implementing balance reads. A changed token order could attach an amount to the wrong asset or role even when the returned values looked plausible.

Pool discovery and reserve reads served different jobs

The archived Uniswap V2 implementation included a factory-enumeration base and a subgraph discovery variant. Those approaches determined which pool addresses entered the integration. The subgraph variant also supported required and ignored pool lists, then removed duplicate addresses. A pool’s existence alone didn’t establish its inclusion in a particular fetcher’s output.

Visual outline: Zapper: Pool discovery and reserve reads served different jobs

Open full-size image

Valuation used different information. The pool code resolved its underlying token addresses and read reserves from the pool contract. It normalized those reserves and divided them by share supply to calculate the underlying quantities per share. Discovering a contract and calculating what its shares represented answered separate questions, even though the integration needed both relationships.


A hypothetical share balance showed why location changed the fetcher

A developer comparing the same shares in a wallet and a contract-recorded stake needed balance logic appropriate to each location. Assume 17.6 application-token shares and 1.34 underlying-token units per share. These quantities and both holding arrangements are hypothetical, and the inputs already use units after decimal normalization.

With the shares in the wallet, the token-fetcher balance path read the address’s token balance. Multiplying 17.6 by 1.34 gave 23.584 underlying-token units of modeled exposure. The adapter represented a share holding with its underlying breakdown.

For the alternative contract-recorded stake, a contract position fetcher would read the deposited shares attributed to the address. If the stake retained that share conversion, its underlying breakdown represented the same 23.584 units. The amount came from the staking record even when those shares weren’t in the wallet.

The conversion had to match the staking contract’s accounting. A contract recording underlying assets directly required balance logic for those units. The calculated exposure didn’t specify what an executed withdrawal would deliver.

Scaffolding and ABI bindings shortened adapter development

The CLI generated application scaffolding and fetcher templates, while ABI-derived bindings supplied typed access to smart-contract methods. Developers provided the protocol-specific accounting and the relationships between its tokens.

Application scaffolding

The pnpm studio create-app command created the application scaffold. Separate template generators supported token fetchers and contract position fetchers. Those starting structures reduced repeated setup, while the integration still needed the contract definitions and balance logic appropriate to its supported positions.

The archived README required Node.js 18.16.1 or later and pnpm 8, and the package declared Node.js 18.x. An installation using another major version fell outside the package’s declared range.

ABI-derived contract bindings

An application binary interface, or ABI, described the contract methods and their argument and return types. Studio’s contract-factory generator used application ABI files to create TypeScript bindings. Those bindings gave the fetcher a typed way to access the methods the integration required.

Type information covered the interface the ABI described. Developers still needed an ABI matching the relevant contract deployment and methods matching its accounting. A typed call could return a valid value whose meaning differed from the balance the adapter intended to represent.

Why could an adapter miss an existing position?

An adapter could miss an existing position when its discovery logic omitted the relevant contract or its dependency loader couldn’t resolve required underlying tokens. The archived templates matched dependencies using contract addresses and networks. For applicable token types, identifiers supplied further context. An incomplete dependency set could prevent the template from building the position object.

Deployment changes could also require maintenance of contract definitions or balance methods. Labels described a position after the integration had resolved its constituent data; changing a label couldn’t repair a missing dependency or a read against the wrong contract. Missing output therefore needed interpretation within the particular fetcher’s coverage and implementation.

Local caches and network providers needed separate handling

The local filesystem cache persisted application tokens, contract positions, and other application data. An edited adapter could appear unchanged while the development server reused stored definitions. Studio included pnpm studio clear-cache to remove that persisted data during development.

Provider configuration addressed slow or failing blockchain access. The separate pnpm studio set-network-provider command allowed custom network providers. A provider supplied access to blockchain data; the adapter supplied the interpretation of contract methods and token relationships. Changing that access service didn’t correct a balance method whose accounting assumptions were wrong.

How did a contribution reach the shared integration code?

During Studio’s active contribution period, developers proposed changes through pull requests, and the team reviewed them before merging accepted updates into the shared repository. Contributors developed changes in their own forks and branches. The review process could request additional information or revisions, giving maintainers a chance to assess the integration’s purpose and implementation.

Contributions also covered improvements to existing integrations. Focused changes made it easier to identify the affected behavior and discuss a correction without mixing unrelated work. Submission alone didn’t establish acceptance into the shared code.


The 2024 archive preserved implementation history

The public Studio repository became read-only on January 24, 2024. Its archive preserved the data structures, CLI, and protocol-specific fetchers without continuing the original contribution channel. The separate documentation repository became read-only on January 28, 2025. Studying those artifacts can explain historical adapter behavior. Reusing an adapter in another application means maintaining a separate copy and adapting its deployments, interfaces, and dependencies to the data that application needs.

Zapper FAQs

Could someone outside a protocol’s team contribute a Studio adapter?

Studio’s public contribution model allowed developers outside a protocol’s own team to propose integrations. Contributors needed JavaScript or TypeScript knowledge and an understanding of smart contracts. Participation didn’t automatically establish acceptance: the original workflow used pull requests and team review, and the public repository became read-only in January 2024.

Did writing a Studio balance adapter also add swap or zap support?

A balance adapter described positions and retrieved holdings; it didn’t by itself implement a swap or zap transaction. Studio launched with balance fetching as its initial scope. Transactional experiences appeared separately in its development plans, so a working balance integration didn’t establish corresponding transaction support.

What did a zero APY value in the base application-token template mean?

The archived base application-token template returned zero from its default APY method unless an integration overrode it. That default wasn’t a measured statement that the protocol earned no yield. The same base template added its standard APY statistic only for a positive value, so inherited defaults could leave that statistic absent.

Why could the contract-position template omit a tiny displayed balance?

The archived contract-position template filtered token entries with an absolute USD value of $0.01 or less from its formatted balance output. It then summed the remaining entries for the position total. This display-processing rule concerned that template path; it didn’t establish that a contract held no smaller balance.

How did Studio distinguish TVL inclusion from balance inclusion?

The archived position templates declared separate exclusion flags for total value locked, wallet balances, and exploration views. Adapter authors could express those choices independently. Inclusion in one output category therefore wasn’t the same configuration choice as inclusion in another, and the flags didn’t alter the underlying protocol’s contracts.

When did Zapper Studio open its public integration repository?

Zapper announced Studio’s public launch on May 4, 2022, with balance fetching as the initial capability. The launch opened app integration development to external contributors and included improvements to existing adapters. Its announcement described further development plans separately, so that launch date didn’t establish when every proposed feature became available.

Would a successful TypeScript build prove a Studio adapter returned correct balances?

A successful TypeScript build couldn’t prove the adapter’s balance calculations matched the protocol’s accounting. Types described expected code shapes, while correctness also required suitable contracts, token units, and balance methods. The archived package included separate type-checking and integration-test scripts, reflecting different kinds of development checks.